Skip to content

Commit 3225e55

Browse files
committed
merge with origin/master
1 parent 2ffc363 commit 3225e55

3 files changed

Lines changed: 209 additions & 58 deletions

File tree

src/server/editorServices.ts

Lines changed: 190 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,66 @@ namespace ts.server {
123123
}
124124
}
125125

126-
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost {
126+
127+
function throwLanguageServiceIsDisabledError() {;
128+
throw new Error("LanguageService is disabled");
129+
}
130+
131+
const nullLanguageService: ts.LanguageService = {
132+
cleanupSemanticCache: (): any => throwLanguageServiceIsDisabledError(),
133+
getSyntacticDiagnostics: (): any => throwLanguageServiceIsDisabledError(),
134+
getSemanticDiagnostics: (): any => throwLanguageServiceIsDisabledError(),
135+
getCompilerOptionsDiagnostics: (): any => throwLanguageServiceIsDisabledError(),
136+
getSyntacticClassifications: (): any => throwLanguageServiceIsDisabledError(),
137+
getEncodedSyntacticClassifications: (): any => throwLanguageServiceIsDisabledError(),
138+
getSemanticClassifications: (): any => throwLanguageServiceIsDisabledError(),
139+
getEncodedSemanticClassifications: (): any => throwLanguageServiceIsDisabledError(),
140+
getCompletionsAtPosition: (): any => throwLanguageServiceIsDisabledError(),
141+
findReferences: (): any => throwLanguageServiceIsDisabledError(),
142+
getCompletionEntryDetails: (): any => throwLanguageServiceIsDisabledError(),
143+
getQuickInfoAtPosition: (): any => throwLanguageServiceIsDisabledError(),
144+
findRenameLocations: (): any => throwLanguageServiceIsDisabledError(),
145+
getNameOrDottedNameSpan: (): any => throwLanguageServiceIsDisabledError(),
146+
getBreakpointStatementAtPosition: (): any => throwLanguageServiceIsDisabledError(),
147+
getBraceMatchingAtPosition: (): any => throwLanguageServiceIsDisabledError(),
148+
getSignatureHelpItems: (): any => throwLanguageServiceIsDisabledError(),
149+
getDefinitionAtPosition: (): any => throwLanguageServiceIsDisabledError(),
150+
getRenameInfo: (): any => throwLanguageServiceIsDisabledError(),
151+
getTypeDefinitionAtPosition: (): any => throwLanguageServiceIsDisabledError(),
152+
getReferencesAtPosition: (): any => throwLanguageServiceIsDisabledError(),
153+
getDocumentHighlights: (): any => throwLanguageServiceIsDisabledError(),
154+
getOccurrencesAtPosition: (): any => throwLanguageServiceIsDisabledError(),
155+
getNavigateToItems: (): any => throwLanguageServiceIsDisabledError(),
156+
getNavigationBarItems: (): any => throwLanguageServiceIsDisabledError(),
157+
getOutliningSpans: (): any => throwLanguageServiceIsDisabledError(),
158+
getTodoComments: (): any => throwLanguageServiceIsDisabledError(),
159+
getIndentationAtPosition: (): any => throwLanguageServiceIsDisabledError(),
160+
getFormattingEditsForRange: (): any => throwLanguageServiceIsDisabledError(),
161+
getFormattingEditsForDocument: (): any => throwLanguageServiceIsDisabledError(),
162+
getFormattingEditsAfterKeystroke: (): any => throwLanguageServiceIsDisabledError(),
163+
getDocCommentTemplateAtPosition: (): any => throwLanguageServiceIsDisabledError(),
164+
isValidBraceCompletionAtPostion: (): any => throwLanguageServiceIsDisabledError(),
165+
getEmitOutput: (): any => throwLanguageServiceIsDisabledError(),
166+
getProgram: (): any => throwLanguageServiceIsDisabledError(),
167+
getNonBoundSourceFile: (): any => throwLanguageServiceIsDisabledError(),
168+
dispose: (): any => throwLanguageServiceIsDisabledError(),
169+
};
170+
171+
interface ServerLanguageServiceHost {
172+
getCompilationSettings(): CompilerOptions;
173+
setCompilationSettings(options: CompilerOptions): void;
174+
removeRoot(info: ScriptInfo): void;
175+
removeReferencedFile(info: ScriptInfo): void;
176+
}
177+
178+
const nullLanguageServiceHost: ServerLanguageServiceHost = {
179+
getCompilationSettings: () => undefined,
180+
setCompilationSettings: () => undefined,
181+
removeRoot: () => undefined,
182+
removeReferencedFile: () => undefined
183+
};
184+
185+
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost, ServerLanguageServiceHost {
127186
private compilationSettings: ts.CompilerOptions;
128187
private resolvedModuleNames: ts.FileMap<Map<ResolvedModuleWithFailedLookupLocations>>;
129188
private resolvedTypeReferenceDirectives: ts.FileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
@@ -302,31 +361,62 @@ namespace ts.server {
302361
export abstract class Project {
303362
private rootFiles: ScriptInfo[] = [];
304363
private rootFilesMap: FileMap<ScriptInfo> = createFileMap<ScriptInfo>();
305-
private readonly lsHost: LSHost;
364+
private lsHost: ServerLanguageServiceHost;
306365

307-
readonly languageService: LanguageService;
366+
languageService: LanguageService;
308367
protected program: ts.Program;
309368

310369
constructor(
311370
readonly projectKind: ProjectKind,
312371
readonly projectService: ProjectService,
313-
documentRegistry: ts.DocumentRegistry,
372+
private documentRegistry: ts.DocumentRegistry,
314373
hasExplicitListOfFiles: boolean,
315-
compilerOptions: CompilerOptions) {
374+
public languageServiceEnabled: boolean,
375+
private compilerOptions: CompilerOptions) {
316376

317-
if (!compilerOptions) {
318-
compilerOptions = ts.getDefaultCompilerOptions();
319-
compilerOptions.allowNonTsExtensions = true;
320-
compilerOptions.allowJs = true;
377+
if (!this.compilerOptions) {
378+
this.compilerOptions = ts.getDefaultCompilerOptions();
379+
this.compilerOptions.allowNonTsExtensions = true;
380+
this.compilerOptions.allowJs = true;
321381
}
322382
else if (hasExplicitListOfFiles) {
323383
// If files are listed explicitly, allow all extensions
324-
compilerOptions.allowNonTsExtensions = true;
384+
this.compilerOptions.allowNonTsExtensions = true;
385+
}
386+
387+
if (languageServiceEnabled) {
388+
this.enableLanguageServiceWorker();
389+
}
390+
else {
391+
this.disableLanguageServiceWorker();
392+
}
393+
}
394+
395+
enableLanguageService() {
396+
if (!this.languageServiceEnabled) {
397+
this.enableLanguageServiceWorker();
398+
}
399+
}
400+
401+
private enableLanguageServiceWorker() {
402+
const lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken);
403+
lsHost.setCompilationSettings(this.compilerOptions);
404+
this.languageService = ts.createLanguageService(lsHost, this.documentRegistry);
405+
406+
this.lsHost = lsHost;
407+
this.languageServiceEnabled = true;
408+
}
409+
410+
disableLanguageService() {
411+
if (this.languageServiceEnabled) {
412+
this.disableLanguageServiceWorker();
325413
}
414+
}
326415

327-
this.lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken);
328-
this.lsHost.setCompilationSettings(compilerOptions);
329-
this.languageService = ts.createLanguageService(this.lsHost, documentRegistry);
416+
private disableLanguageServiceWorker() {
417+
this.languageService = nullLanguageService;
418+
this.lsHost = nullLanguageServiceHost;
419+
this.languageServiceEnabled = false;
330420
}
331421

332422
getProjectFileName(): string {
@@ -343,29 +433,29 @@ namespace ts.server {
343433
}
344434

345435
getRootFiles() {
436+
if (!this.languageServiceEnabled && this.projectKind === ProjectKind.Inferred) {
437+
return undefined;
438+
}
346439
return this.rootFiles.map(info => info.fileName);
347440
}
348441

349442
getFileNames() {
350-
if (this.languageServiceDiabled) {
351-
if (!this.projectOptions) {
352-
return undefined;
353-
}
354-
355-
const fileNames: string[] = [];
356-
if (this.projectOptions && this.projectOptions.compilerOptions) {
357-
fileNames.push(getDefaultLibFilePath(this.projectOptions.compilerOptions));
443+
if (!this.languageServiceEnabled) {
444+
let rootFiles = this.getRootFiles();
445+
if (this.compilerOptions) {
446+
const defaultLibrary = getDefaultLibFilePath(this.compilerOptions);
447+
if (defaultLibrary) {
448+
(rootFiles || (rootFiles = [])).push(defaultLibrary);
449+
}
358450
}
359-
ts.addRange(fileNames, this.projectOptions.files);
360-
return fileNames;
451+
return rootFiles;
361452
}
362-
363453
const sourceFiles = this.program.getSourceFiles();
364454
return sourceFiles.map(sourceFile => sourceFile.fileName);
365455
}
366456

367457
containsScriptInfo(info: ScriptInfo): boolean {
368-
return this.program.getSourceFileByPath(info.path) !== undefined;
458+
return this.program && this.program.getSourceFileByPath(info.path) !== undefined;
369459
}
370460

371461
containsFile(filename: string, requireOpen?: boolean) {
@@ -455,8 +545,13 @@ namespace ts.server {
455545
// Used to keep track of what directories are watched for this project
456546
directoriesWatchedForTsconfig: string[] = [];
457547

458-
constructor(projectService: ProjectService, documentRegistry: ts.DocumentRegistry) {
459-
super(ProjectKind.Inferred, projectService, documentRegistry, /*files*/ undefined, /*compilerOptions*/ undefined);
548+
constructor(projectService: ProjectService, documentRegistry: ts.DocumentRegistry, languageServiceEnabled: boolean) {
549+
super(ProjectKind.Inferred,
550+
projectService,
551+
documentRegistry,
552+
/*files*/ undefined,
553+
languageServiceEnabled,
554+
/*compilerOptions*/ undefined);
460555
}
461556

462557
close() {
@@ -483,6 +578,9 @@ namespace ts.server {
483578
currentVersion: number = 1;
484579

485580
updateGraph() {
581+
if (!this.languageServiceEnabled) {
582+
return;
583+
}
486584
const oldProgram = this.program;
487585

488586
super.updateGraph();
@@ -538,8 +636,13 @@ namespace ts.server {
538636
/** Used for configured projects which may have multiple open roots */
539637
openRefCount = 0;
540638

541-
constructor(readonly configFileName: string, projectService: ProjectService, documentRegistry: ts.DocumentRegistry, hasExplicitListOfFiles: boolean, compilerOptions: CompilerOptions) {
542-
super(ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, compilerOptions);
639+
constructor(readonly configFileName: string,
640+
projectService: ProjectService,
641+
documentRegistry: ts.DocumentRegistry,
642+
hasExplicitListOfFiles: boolean,
643+
compilerOptions: CompilerOptions,
644+
languageServiceEnabled: boolean) {
645+
super(ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions);
543646
}
544647

545648
getProjectFileName() {
@@ -551,20 +654,29 @@ namespace ts.server {
551654
}
552655

553656
watchConfigDirectory(callback: (project: ConfiguredProject, path: string) => void) {
657+
if (this.directoryWatcher) {
658+
return;
659+
}
660+
554661
const directoryToWatch = ts.getDirectoryPath(this.configFileName);
555662
this.projectService.log(`Add recursive watcher for: ${directoryToWatch}`);
556663
this.directoryWatcher = this.projectService.host.watchDirectory(directoryToWatch, path => callback(this, path), /*recursive*/ true);
557664
}
558665

666+
stopWatchingDirectory() {
667+
if (this.directoryWatcher) {
668+
this.directoryWatcher.close();
669+
this.directoryWatcher = undefined;
670+
}
671+
}
672+
559673
close() {
560674
super.close();
561675

562676
if (this.projectFileWatcher) {
563677
this.projectFileWatcher.close();
564678
}
565-
if (this.directoryWatcher) {
566-
this.directoryWatcher.close();
567-
}
679+
this.stopWatchingDirectory();
568680
}
569681

570682
addOpenRef() {
@@ -578,8 +690,12 @@ namespace ts.server {
578690
}
579691

580692
class ExternalProject extends VersionedProject {
581-
constructor(readonly projectFileName: string, projectService: ProjectService, documentRegistry: ts.DocumentRegistry, compilerOptions: CompilerOptions) {
582-
super(ProjectKind.External, projectService, documentRegistry, /*hasExplicitListOfFiles*/ true, compilerOptions);
693+
constructor(readonly projectFileName: string,
694+
projectService: ProjectService,
695+
documentRegistry: ts.DocumentRegistry,
696+
compilerOptions: CompilerOptions,
697+
languageServiceEnabled: boolean) {
698+
super(ProjectKind.External, projectService, documentRegistry, /*hasExplicitListOfFiles*/ true, languageServiceEnabled, compilerOptions);
583699
}
584700

585701
getProjectFileName() {
@@ -1149,7 +1265,10 @@ namespace ts.server {
11491265
}
11501266
}
11511267

1152-
private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
1268+
private exceedTotalNonTsFileSizeLimit(options: CompilerOptions, fileNames: string[]) {
1269+
if (options && options.disableSizeLimit) {
1270+
return false;
1271+
}
11531272
let totalNonTsFileSize = 0;
11541273
if (!this.host.getFileSize) {
11551274
return false;
@@ -1168,23 +1287,38 @@ namespace ts.server {
11681287
}
11691288

11701289
private createAndAddExternalProject(projectFileName: string, files: string[], compilerOptions: CompilerOptions, clientFileName?: string) {
1171-
const project = new ExternalProject(projectFileName, this, this.documentRegistry, compilerOptions);
1290+
const sizeLimitExceeded = this.exceedTotalNonTsFileSizeLimit(compilerOptions, files);
1291+
const project = new ExternalProject(projectFileName, this, this.documentRegistry, compilerOptions, !sizeLimitExceeded);
11721292
const errors = this.addFilesToProject(project, files, clientFileName);
11731293
this.externalProjects.push(project);
11741294
return { project, errors };
11751295
}
11761296

11771297
private createAndAddConfiguredProject(configFileName: string, projectOptions: ProjectOptions, clientFileName?: string) {
1178-
const project = new ConfiguredProject(configFileName, this, this.documentRegistry, projectOptions.configHasFilesProperty, projectOptions.compilerOptions);
1298+
const sizeLimitExceeded = this.exceedTotalNonTsFileSizeLimit(projectOptions.compilerOptions, projectOptions.files);
1299+
const project = new ConfiguredProject(
1300+
configFileName,
1301+
this,
1302+
this.documentRegistry,
1303+
projectOptions.configHasFilesProperty,
1304+
projectOptions.compilerOptions,
1305+
!sizeLimitExceeded);
1306+
11791307
const errors = this.addFilesToProject(project, projectOptions.files, clientFileName);
11801308
project.watchConfigFile(project => this.onConfigChangedForConfiguredProject(project));
1181-
if (!projectOptions.configHasFilesProperty) {
1182-
project.watchConfigDirectory((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
1309+
if (!sizeLimitExceeded) {
1310+
this.watchConfigDirectoryForProject(project, projectOptions);
11831311
}
11841312
this.configuredProjects.push(project);
11851313
return { project, errors };
11861314
}
11871315

1316+
private watchConfigDirectoryForProject(project: ConfiguredProject, options: ProjectOptions) {
1317+
if (!options.configHasFilesProperty) {
1318+
project.watchConfigDirectory((project, path) => this.onSourceFileInDirectoryChangedForConfiguredProject(project, path));
1319+
}
1320+
}
1321+
11881322
private addFilesToProject(project: ConfiguredProject | ExternalProject, files: string[], clientFileName: string): Diagnostic[] {
11891323
let errors: Diagnostic[];
11901324
for (const rootFilename of files) {
@@ -1266,13 +1400,28 @@ namespace ts.server {
12661400
return errors;
12671401
}
12681402
else {
1269-
this.updateVersionedProjectWorker(project, projectOptions.files, projectOptions.compilerOptions);
1403+
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.compilerOptions, projectOptions.files)) {
1404+
project.setCompilerOptions(projectOptions.compilerOptions);
1405+
if (!project.languageServiceEnabled) {
1406+
// language service is already disabled
1407+
return;
1408+
}
1409+
project.disableLanguageService();
1410+
project.stopWatchingDirectory();
1411+
}
1412+
else {
1413+
if (!project.languageServiceEnabled) {
1414+
project.enableLanguageService();
1415+
}
1416+
this.watchConfigDirectoryForProject(project, projectOptions);
1417+
this.updateVersionedProjectWorker(project, projectOptions.files, projectOptions.compilerOptions);
1418+
}
12701419
}
12711420
}
12721421
}
12731422

12741423
createAndAddInferredProject(root: ScriptInfo) {
1275-
const project = new InferredProject(this, this.documentRegistry);
1424+
const project = new InferredProject(this, this.documentRegistry, /*languageServiceEnabled*/ true);
12761425
project.addRoot(root);
12771426

12781427
let currentPath = ts.getDirectoryPath(root.fileName);

0 commit comments

Comments
 (0)