diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 397c16366..e5151dcba 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -116,6 +116,7 @@ interface ConfigurationJson { export class CppProperties { private propertiesFile: vscode.Uri = null; + private workspaceRoot: string; private readonly configFolder: string; private configurationJson: ConfigurationJson = null; private currentConfigurationIndex: PersistentFolderState; @@ -141,6 +142,7 @@ export class CppProperties { console.assert(rootPath !== undefined); this.currentConfigurationIndex = new PersistentFolderState("CppProperties.currentConfigurationIndex", -1, rootPath); this.configFolder = path.join(rootPath, ".vscode"); + this.workspaceRoot = rootPath; this.resetToDefaultSettings(this.currentConfigurationIndex.Value === -1); let configFilePath: string = path.join(this.configFolder, "c_cpp_properties.json"); @@ -295,31 +297,64 @@ export class CppProperties { this.onSelectionChanged(); } - private resolveAndSplit(paths: string[] | undefined): string[] { + private expandPath(path1: string): Promise { + return new Promise((resolve, reject) => { + let index: number = path1.indexOf("/*/"); + if (index >= 0) { + let paths: string[] = []; + let basePath: string = path1.substr(0, index).replace("${workspaceRoot}", this.workspaceRoot); + let remainingPath: string = path1.substr(index + 3); + try { + let items: string[] = fs.readdirSync(basePath); + items.forEach(directory => { + let potentialPath: string = path.join(basePath, directory, remainingPath); + try { + let stats: fs.Stats = fs.statSync(potentialPath.endsWith("*") ? potentialPath.substr(0, potentialPath.length - 1) : potentialPath); + if (stats && stats.isDirectory()) { + paths.push(potentialPath.replace(this.workspaceRoot, "${workspaceRoot}")); + } + } catch { + // potentialPath is not a valid path. Ignore it. + } + }); + } catch { + // basePath is not a valid path. Ignore it. + } + resolve(paths); + } else { + resolve([path1]); + } + }); + } + + private resolveAndSplit(paths: string[]): Promise { + let promises: Promise[] = []; let result: string[] = []; - if (paths) { - paths.forEach(entry => { - let entries: string[] = util.resolveVariables(entry).split(";").filter(e => e); - result = result.concat(entries); + paths.forEach(entry => { + let entries: string[] = util.resolveVariables(entry).split(";").filter(e => e); + entries.forEach(path => { + promises.push(this.expandPath(path).then(paths => { + result = result.concat(paths); + })); }); - } - return result; + }); + return Promise.all(promises).then(() => result); } - private updateServerOnFolderSettingsChange(): void { + private async updateServerOnFolderSettingsChange(): Promise { for (let i: number = 0; i < this.configurationJson.configurations.length; i++) { let configuration: Configuration = this.configurationJson.configurations[i]; if (configuration.includePath) { - configuration.includePath = this.resolveAndSplit(configuration.includePath); + configuration.includePath = await this.resolveAndSplit(configuration.includePath); } if (configuration.browse && configuration.browse.path) { - configuration.browse.path = this.resolveAndSplit(configuration.browse.path); + configuration.browse.path = await this.resolveAndSplit(configuration.browse.path); } if (configuration.macFrameworkPath) { - configuration.macFrameworkPath = this.resolveAndSplit(configuration.macFrameworkPath); + configuration.macFrameworkPath = await this.resolveAndSplit(configuration.macFrameworkPath); } if (configuration.forcedInclude) { - configuration.forcedInclude = this.resolveAndSplit(configuration.forcedInclude); + configuration.forcedInclude = await this.resolveAndSplit(configuration.forcedInclude); } if (configuration.compileCommands) { configuration.compileCommands = util.resolveVariables(configuration.compileCommands);