Skip to content

Commit 12428d4

Browse files
committed
Add method on host to get DocumentPositionMapper so it can be cached.
1 parent 0dad79e commit 12428d4

File tree

13 files changed

+219
-89
lines changed

13 files changed

+219
-89
lines changed

src/compiler/scanner.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,12 +338,16 @@ namespace ts {
338338
}
339339

340340
export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number): number {
341-
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text);
341+
return sourceFile.getPositionOfLineAndCharacter ?
342+
sourceFile.getPositionOfLineAndCharacter(line, character) :
343+
computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text);
342344
}
343345

344346
/* @internal */
345347
export function getPositionOfLineAndCharacterWithEdits(sourceFile: SourceFileLike, line: number, character: number): number {
346-
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, /*allowEdits*/ true);
348+
return sourceFile.getPositionOfLineAndCharacter ?
349+
sourceFile.getPositionOfLineAndCharacter(line, character) :
350+
computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, /*allowEdits*/ true);
347351
}
348352

349353
/* @internal */

src/compiler/sourcemap.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,24 @@ namespace ts {
266266
const sourceMapCommentRegExp = /^\/\/[@#] source[M]appingURL=(.+)\s*$/;
267267
const whitespaceOrMapCommentRegExp = /^\s*(\/\/[@#] .*)?$/;
268268

269+
export interface LineInfo {
270+
getLineCount(): number;
271+
getLineText(line: number): string;
272+
}
273+
274+
export function getLineInfo(text: string, lineStarts: ReadonlyArray<number>): LineInfo {
275+
return {
276+
getLineCount: () => lineStarts.length,
277+
getLineText: line => text.substring(lineStarts[line], lineStarts[line + 1])
278+
};
279+
}
280+
269281
/**
270282
* Tries to find the sourceMappingURL comment at the end of a file.
271-
* @param text The source text of the file.
272-
* @param lineStarts The line starts of the file.
273283
*/
274-
export function tryGetSourceMappingURL(text: string, lineStarts: ReadonlyArray<number> = computeLineStarts(text)) {
275-
for (let index = lineStarts.length - 1; index >= 0; index--) {
276-
const line = text.substring(lineStarts[index], lineStarts[index + 1]);
284+
export function tryGetSourceMappingURL(lineInfo: LineInfo) {
285+
for (let index = lineInfo.getLineCount() - 1; index >= 0; index--) {
286+
const line = lineInfo.getLineText(index);
277287
const comment = sourceMapCommentRegExp.exec(line);
278288
if (comment) {
279289
return comment[1];

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,8 @@ namespace ts {
26142614
export interface SourceFileLike {
26152615
readonly text: string;
26162616
lineMap?: ReadonlyArray<number>;
2617+
/* @internal */
2618+
getPositionOfLineAndCharacter?(line: number, character: number): number;
26172619
}
26182620

26192621

src/harness/sourceMapRecorder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ namespace Harness.SourceMapRecorder {
6969
SourceMapDecoder.initializeSourceMapDecoding(sourceMapData);
7070
sourceMapRecorder.WriteLine("===================================================================");
7171
sourceMapRecorder.WriteLine("JsFile: " + sourceMapData.sourceMap.file);
72-
sourceMapRecorder.WriteLine("mapUrl: " + ts.tryGetSourceMappingURL(jsFile.text, jsLineMap));
72+
sourceMapRecorder.WriteLine("mapUrl: " + ts.tryGetSourceMappingURL(ts.getLineInfo(jsFile.text, jsLineMap)));
7373
sourceMapRecorder.WriteLine("sourceRoot: " + sourceMapData.sourceMap.sourceRoot);
7474
sourceMapRecorder.WriteLine("sources: " + sourceMapData.sourceMap.sources);
7575
if (sourceMapData.sourceMap.sourcesContent) {

src/server/project.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,66 @@ namespace ts.server {
503503
return this.getLanguageService().getSourceMapper();
504504
}
505505

506+
/*@internal*/
507+
getDocumentPositionMapper(fileName: string): DocumentPositionMapper | undefined {
508+
const declarationInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
509+
if (!declarationInfo) return undefined;
510+
511+
declarationInfo.getSnapshot(); // Ensure synchronized
512+
const existingMapper = declarationInfo.textStorage.mapper;
513+
if (existingMapper !== undefined) {
514+
return existingMapper ? existingMapper : undefined;
515+
}
516+
517+
// Create the mapper
518+
declarationInfo.mapInfo = undefined;
519+
520+
const mapper = getDocumentPositionMapper({
521+
getCanonicalFileName: this.projectService.toCanonicalFileName,
522+
log: s => this.log(s),
523+
readMapFile: f => this.readMapFile(f, declarationInfo),
524+
getSourceFileLike: f => this.getSourceFileLike(f)
525+
}, declarationInfo.fileName, declarationInfo.textStorage.getLineInfo());
526+
declarationInfo.textStorage.mapper = mapper || false;
527+
return mapper;
528+
}
529+
530+
private readMapFile(fileName: string, declarationInfo: ScriptInfo) {
531+
const mapInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
532+
if (!mapInfo) return undefined;
533+
declarationInfo.mapInfo = mapInfo;
534+
const snap = mapInfo.getSnapshot();
535+
return snap.getText(0, snap.getLength());
536+
}
537+
538+
/*@internal*/
539+
getSourceFileLike(fileName: string) {
540+
const path = this.toPath(fileName);
541+
const sourceFile = this.getSourceFile(path);
542+
if (sourceFile && sourceFile.resolvedPath === path) return sourceFile;
543+
544+
// Need to look for other files.
545+
const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
546+
if (!info) return undefined;
547+
548+
// Key doesnt matter since its only for text and lines
549+
if (info.cacheSourceFile) return info.cacheSourceFile.sourceFile;
550+
if (info.textStorage.sourceFileLike) return info.textStorage.sourceFileLike;
551+
552+
info.textStorage.sourceFileLike = {
553+
get text() {
554+
Debug.fail("shouldnt need text");
555+
return "";
556+
},
557+
getLineAndCharacterOfPosition: pos => {
558+
const lineOffset = info.positionToLineOffset(pos);
559+
return { line: lineOffset.line - 1, character: lineOffset.offset - 1 };
560+
},
561+
getPositionOfLineAndCharacter: (line, character) => info.lineOffsetToPosition(line + 1, character + 1)
562+
};
563+
return info.textStorage.sourceFileLike;
564+
}
565+
506566
private shouldEmitFile(scriptInfo: ScriptInfo) {
507567
return scriptInfo && !scriptInfo.isDynamicOrHasMixedContent();
508568
}

src/server/scriptInfo.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ namespace ts.server {
4646
*/
4747
private pendingReloadFromDisk = false;
4848

49+
mapper: DocumentPositionMapper | false | undefined = false;
50+
sourceFileLike: SourceFileLike | undefined;
51+
4952
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion: ScriptInfoVersion | undefined, private readonly info: ScriptInfo) {
5053
this.version = initialVersion || { svc: 0, text: 0 };
5154
}
@@ -70,6 +73,8 @@ namespace ts.server {
7073
this.text = newText;
7174
this.lineMap = undefined;
7275
this.fileSize = undefined;
76+
this.mapper = undefined;
77+
this.sourceFileLike = undefined;
7378
this.version.text++;
7479
}
7580

@@ -79,6 +84,8 @@ namespace ts.server {
7984
this.text = undefined;
8085
this.lineMap = undefined;
8186
this.fileSize = undefined;
87+
this.mapper = undefined;
88+
this.sourceFileLike = undefined;
8289
}
8390

8491
/**
@@ -156,8 +163,8 @@ namespace ts.server {
156163
: ScriptSnapshot.fromString(this.getOrLoadText());
157164
}
158165

159-
public getLineInfo(line: number): AbsolutePositionAndLineText {
160-
return this.switchToScriptVersionCache().getLineInfo(line);
166+
public getAbsolutePositionAndLineText(line: number): AbsolutePositionAndLineText {
167+
return this.switchToScriptVersionCache().getAbsolutePositionAndLineText(line);
161168
}
162169
/**
163170
* @param line 0 based index
@@ -246,6 +253,17 @@ namespace ts.server {
246253
Debug.assert(!this.svc, "ScriptVersionCache should not be set");
247254
return this.lineMap || (this.lineMap = computeLineStarts(this.getOrLoadText()));
248255
}
256+
257+
getLineInfo(): LineInfo {
258+
if (this.svc) {
259+
return {
260+
getLineCount: () => this.svc!.getLineCount(),
261+
getLineText: line => this.svc!.getAbsolutePositionAndLineText(line + 1).lineText!
262+
};
263+
}
264+
const lineMap = this.getLineMap();
265+
return getLineInfo(this.text!, lineMap);
266+
}
249267
}
250268

251269
/*@internal*/
@@ -269,7 +287,7 @@ namespace ts.server {
269287

270288
/* @internal */
271289
fileWatcher: FileWatcher | undefined;
272-
private textStorage: TextStorage;
290+
/* @internal */ textStorage: TextStorage;
273291

274292
/*@internal*/
275293
readonly isDynamic: boolean;
@@ -284,6 +302,9 @@ namespace ts.server {
284302
/*@internal*/
285303
mTime?: number;
286304

305+
/*@internal*/
306+
mapInfo?: ScriptInfo;
307+
287308
constructor(
288309
private readonly host: ServerHost,
289310
readonly fileName: NormalizedPath,
@@ -521,8 +542,8 @@ namespace ts.server {
521542
}
522543

523544
/*@internal*/
524-
getLineInfo(line: number): AbsolutePositionAndLineText {
525-
return this.textStorage.getLineInfo(line);
545+
getAbsolutePositionAndLineText(line: number): AbsolutePositionAndLineText {
546+
return this.textStorage.getAbsolutePositionAndLineText(line);
526547
}
527548

528549
editContent(start: number, end: number, newText: string): void {

src/server/scriptVersionCache.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ namespace ts.server {
308308
return this._getSnapshot().version;
309309
}
310310

311-
getLineInfo(line: number): AbsolutePositionAndLineText {
312-
return this._getSnapshot().index.lineNumberToInfo(line);
311+
getAbsolutePositionAndLineText(oneBasedLine: number): AbsolutePositionAndLineText {
312+
return this._getSnapshot().index.lineNumberToInfo(oneBasedLine);
313313
}
314314

315315
lineOffsetToPosition(line: number, column: number): number {
@@ -348,6 +348,10 @@ namespace ts.server {
348348
}
349349
}
350350

351+
getLineCount() {
352+
return this._getSnapshot().index.getLineCount();
353+
}
354+
351355
static fromString(script: string) {
352356
const svc = new ScriptVersionCache();
353357
const snap = new LineIndexSnapshot(0, svc, new LineIndex());
@@ -400,8 +404,12 @@ namespace ts.server {
400404
return this.root.charOffsetToLineInfo(1, position);
401405
}
402406

407+
getLineCount() {
408+
return this.root.lineCount();
409+
}
410+
403411
lineNumberToInfo(oneBasedLine: number): AbsolutePositionAndLineText {
404-
const lineCount = this.root.lineCount();
412+
const lineCount = this.getLineCount();
405413
if (oneBasedLine <= lineCount) {
406414
const { position, leaf } = this.root.lineNumberToInfo(oneBasedLine, 0);
407415
return { absolutePosition: position, lineText: leaf && leaf.text };

src/server/session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,7 @@ namespace ts.server {
14741474
// only to the previous line. If all this is true, then
14751475
// add edits necessary to properly indent the current line.
14761476
if ((args.key === "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) {
1477-
const { lineText, absolutePosition } = scriptInfo.getLineInfo(args.line);
1477+
const { lineText, absolutePosition } = scriptInfo.getAbsolutePositionAndLineText(args.line);
14781478
if (lineText && lineText.search("\\S") < 0) {
14791479
const preferredIndent = languageService.getIndentationAtPosition(file, position, formatOptions);
14801480
let hasIndent = 0;

src/services/services.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ namespace ts {
603603
}
604604

605605
public getPositionOfLineAndCharacter(line: number, character: number): number {
606-
return getPositionOfLineAndCharacter(this, line, character);
606+
return computePositionOfLineAndCharacter(getLineStarts(this), line, character, this.text);
607607
}
608608

609609
public getLineEndOfPosition(pos: number): number {
@@ -1143,8 +1143,10 @@ namespace ts {
11431143
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
11441144
getCurrentDirectory: () => currentDirectory,
11451145
getProgram,
1146-
fileExists: host.fileExists ? f => host.fileExists!(f) : returnFalse,
1147-
readFile: host.readFile ? (f, encoding) => host.readFile!(f, encoding) : () => undefined,
1146+
fileExists: host.fileExists && (f => host.fileExists!(f)),
1147+
readFile: host.readFile && ((f, encoding) => host.readFile!(f, encoding)),
1148+
getDocumentPositionMapper: host.getDocumentPositionMapper && (f => host.getDocumentPositionMapper!(f)),
1149+
getSourceFileLike: host.getSourceFileLike && (f => host.getSourceFileLike!(f)),
11481150
log
11491151
});
11501152

0 commit comments

Comments
 (0)