Skip to content

Commit a1ceda2

Browse files
Add cmake.exclude setting to allow for multi-root scenarios to ignore certain folders (#4440)
* Add the cmake.ignoredFolders setting. Added the ignoredFolders setting in the code such that it compiles. TODO to implement the usage of this setting in the extension. * update changelog, docs, and description * modify folderToProjectsMap to hold a vscode.WorkspaceFolder rather than string as key * rename loadAllProjects to loadAllFolders and add comment explaining what I think we should refactor * fix incorrect rebase * saving progress * make ignore logic more specific, handle removal from test explorer when sourceDirectory is changed * remove duplicate docs/cmake-settings entry * slight refactors to make more performant * fix workspace ignoredFolder handler to fix multiple invocation issue * use a more vscode-y name with cmake.exclude rather than cmake.ignoredFolders * fix string * update to ensure that the activeFolder updates accordingly * add telemetry * remove unused import
1 parent 767662f commit a1ceda2

File tree

8 files changed

+171
-75
lines changed

8 files changed

+171
-75
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Features:
77
- Add an option to specify the launch target for debugging CTest tests. [#4273](https://github.com/microsoft/vscode-cmake-tools/pull/4273)
88
- Add a setting to enable/disable our built-in language services. [#4290](https://github.com/microsoft/vscode-cmake-tools/issues/4290)
99
- Add an option to group the default build target dropdown using CMake groups [#3953](https://github.com/microsoft/vscode-cmake-tools/pull/3953) [@itzandroidtab](https://github.com/itzandroidtab)
10+
- Add `cmake.exclude` setting that allows users to set folders that they want the CMake Tools extension to ignore. [#4112](https://github.com/microsoft/vscode-cmake-tools/issues/4112)
1011

1112
Improvements:
1213

docs/cmake-settings.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Options that support substitution, in the table below, allow variable references
5252
| `cmake.enableLanguageServices` | If `true`, enable CMake language services. | `true` | no |
5353
| `cmake.enableTraceLogging` | If `true`, enable trace logging. | `false` | no |
5454
| `cmake.environment` | An object containing `key:value` pairs of environment variables, which will be available when configuring, building, or testing with CTest. | `{}` (no environment variables) | yes |
55+
| `cmake.exclude` | CMake Tools will ignore the folders defined in this setting. | `[]` | no |
5556
| `cmake.exportCompileCommandsFile` | If `true`, generate the compile_commands.json file. | `true` | no |
5657
| `cmake.generator` | Set to a string to override CMake Tools preferred generator logic. If set, CMake will unconditionally use it as the `-G` CMake generator command line argument. | `null` | no |
5758
| `cmake.ignoreCMakeListsMissing` | If `true`, do not show error when opening a project without CMakeLists.txt. | `false` | no |

package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,15 @@
20442044
"description": "%cmake-tools.configuration.cmake.defaultActiveFolder.description%",
20452045
"scope": "window"
20462046
},
2047+
"cmake.exclude": {
2048+
"type": "array",
2049+
"items": {
2050+
"type": "string"
2051+
},
2052+
"default": [],
2053+
"description": "%cmake-tools.configuration.cmake.exclude.description%",
2054+
"scope": "window"
2055+
},
20472056
"cmake.cmakePath": {
20482057
"type": "string",
20492058
"default": "cmake",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@
200200
"cmake-tools.configuration.cmake.enableTraceLogging.description": "Enable trace logging to file and console (very noisy).",
201201
"cmake-tools.configuration.cmake.autoSelectActiveFolder.description": "Select active folder automatically.",
202202
"cmake-tools.configuration.cmake.defaultActiveFolder.description": "Set the default active folder (only works when cmake.autoSelectActiveFolder is disable).",
203+
"cmake-tools.configuration.cmake.exclude.description": "The extension will ignore the folders listed in this setting. The folders should be listed as absolute paths.",
203204
"cmake-tools.configuration.cmake.touchbar.advanced.description": "Configures advanced settings for how the extension displays buttons on a MacBook Touch Bar.",
204205
"cmake-tools.configuration.cmake.touchbar.visibility.description": "Configures how the extension displays the buttons on a MacBook Touch Bar.",
205206
"cmake-tools.configuration.cmake.touchbar.visibility.default.description": "Show Touch Bar buttons on supported systems.",

src/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ export interface OptionConfig {
155155
export interface ExtensionConfigurationSettings {
156156
autoSelectActiveFolder: boolean;
157157
defaultActiveFolder: string | null;
158+
exclude: string[];
158159
cmakePath: string;
159160
buildDirectory: string;
160161
installPrefix: string | null;
@@ -322,6 +323,10 @@ export class ConfigurationReader implements vscode.Disposable {
322323
get defaultActiveFolder(): string | null {
323324
return this.configData.defaultActiveFolder;
324325
}
326+
get exclude(): string[] {
327+
return this.configData.exclude;
328+
}
329+
325330
buildDirectory(multiProject: boolean, workspaceFolder?: vscode.ConfigurationScope): string {
326331
if (multiProject && this.isDefaultValue('buildDirectory', workspaceFolder)) {
327332
return '${sourceDirectory}/build';
@@ -596,6 +601,7 @@ export class ConfigurationReader implements vscode.Disposable {
596601
private readonly emitters: EmittersOf<ExtensionConfigurationSettings> = {
597602
autoSelectActiveFolder: new vscode.EventEmitter<boolean>(),
598603
defaultActiveFolder: new vscode.EventEmitter<string | null>(),
604+
exclude: new vscode.EventEmitter<string[]>(),
599605
cmakePath: new vscode.EventEmitter<string>(),
600606
buildDirectory: new vscode.EventEmitter<string>(),
601607
installPrefix: new vscode.EventEmitter<string | null>(),

src/extension.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { CMakeCache } from '@cmt/cache';
1515
import { CMakeProject, ConfigureType, ConfigureTrigger, DiagnosticsConfiguration, DiagnosticsSettings } from '@cmt/cmakeProject';
1616
import { ConfigurationReader, getSettingsChangePromise, TouchBarConfig } from '@cmt/config';
1717
import { CppConfigurationProvider, DiagnosticsCpptools } from '@cmt/cpptools';
18-
import { ProjectController, FolderProjectType} from '@cmt/projectController';
18+
import { ProjectController, AfterAcknowledgeFolderType} from '@cmt/projectController';
1919

2020
import {
2121
SpecialKits,
@@ -162,13 +162,15 @@ export class ExtensionManager implements vscode.Disposable {
162162

163163
this.onDidChangeActiveTextEditorSub = vscode.window.onDidChangeActiveTextEditor(e => this.onDidChangeActiveTextEditor(e), this);
164164

165-
this.projectController.onAfterAddFolder(async (folderProjectMap: FolderProjectType) => {
166-
const folder: vscode.WorkspaceFolder = folderProjectMap.folder;
167-
if (this.projectController.numOfWorkspaceFolders === 1) {
168-
// First folder added
169-
await this.updateActiveProject(folder);
170-
} else {
171-
await this.initActiveProject();
165+
this.projectController.onAfterAcknowledgeFolder(async (obj: AfterAcknowledgeFolderType) => {
166+
const folder: vscode.WorkspaceFolder = obj.folderProjectType.folder;
167+
if (obj.isInitial) {
168+
if (this.projectController.numOfWorkspaceFolders === 1) {
169+
// First folder added
170+
await this.updateActiveProject(folder);
171+
} else {
172+
await this.initActiveProject();
173+
}
172174
}
173175
await setContextAndStore(multiProjectModeKey, this.projectController.hasMultipleProjects);
174176
this.projectOutline.addFolder(folder);
@@ -177,7 +179,8 @@ export class ExtensionManager implements vscode.Disposable {
177179
this.codeModelUpdateSubs.delete(folder.uri.fsPath);
178180
}
179181
const subs: vscode.Disposable[] = [];
180-
for (const project of folderProjectMap.projects) {
182+
for (const project of obj.folderProjectType.projects) {
183+
project.addTestExplorerRoot(project.folderPath);
181184
subs.push(project.onCodeModelChanged(FireLate, () => this.updateCodeModel(project)));
182185
subs.push(project.onTargetNameChanged(FireLate, () => this.updateCodeModel(project)));
183186
subs.push(project.onLaunchTargetNameChanged(FireLate, () => this.updateCodeModel(project)));
@@ -187,22 +190,23 @@ export class ExtensionManager implements vscode.Disposable {
187190
}
188191
});
189192

190-
this.projectController.onBeforeRemoveFolder(async projects => {
193+
this.projectController.onBeforeIgnoreFolder(async projects => {
191194
for (const project of projects) {
192195
project.removeTestExplorerRoot(project.folderPath);
193196
}
194197
});
195198

196-
this.projectController.onAfterRemoveFolder(async folder => {
199+
this.projectController.onAfterIgnoreFolder(async folder => {
197200
console.assert((vscode.workspace.workspaceFolders === undefined && this.projectController.numOfWorkspaceFolders === 0) ||
198201
(vscode.workspace.workspaceFolders !== undefined && vscode.workspace.workspaceFolders.length === this.projectController.numOfWorkspaceFolders));
199202
this.codeModelUpdateSubs.get(folder.uri.fsPath)?.forEach(sub => sub.dispose());
200203
this.codeModelUpdateSubs.delete(folder.uri.fsPath);
201-
if (!vscode.workspace.workspaceFolders?.length) {
204+
const workspaceFolders = this.projectController.getCMakeFoldersWithProject();
205+
if (workspaceFolders.length === 0) {
202206
await this.updateActiveProject(undefined);
203207
} else {
204208
if (this.activeFolderPath() === folder.uri.fsPath) {
205-
await this.updateActiveProject(vscode.workspace.workspaceFolders[0]);
209+
await this.updateActiveProject(workspaceFolders[0]);
206210
} else {
207211
this.setupSubscriptions();
208212
}
@@ -275,10 +279,9 @@ export class ExtensionManager implements vscode.Disposable {
275279

276280
let isMultiProject = false;
277281
if (vscode.workspace.workspaceFolders) {
278-
await this.projectController.loadAllProjects();
282+
await this.projectController.loadAllFolders();
279283
isMultiProject = this.projectController.hasMultipleProjects;
280284
await setContextAndStore(multiProjectModeKey, isMultiProject);
281-
this.projectOutline.addAllCurrentFolders();
282285
if (this.workspaceConfig.autoSelectActiveFolder && isMultiProject) {
283286
this.statusBar.setAutoSelectActiveProject(true);
284287
}
@@ -296,6 +299,7 @@ export class ExtensionManager implements vscode.Disposable {
296299
telemetryProperties['autoSelectActiveFolder'] = `${this.workspaceConfig.autoSelectActiveFolder}`;
297300
}
298301
telemetryProperties['enableLanguageServices'] = `${this.workspaceConfig.enableLanguageServices}`;
302+
telemetryProperties['excludedFoldersCount'] = `${this.workspaceConfig.exclude.length}`;
299303
telemetry.sendOpenTelemetry(telemetryProperties);
300304

301305
// do these last
@@ -355,7 +359,7 @@ export class ExtensionManager implements vscode.Disposable {
355359
projectStatus = new ProjectStatus();
356360

357361
// NOTE: (from sidebar) The project controller manages all the projects in the workspace
358-
public readonly projectController = new ProjectController(this.extensionContext, this.projectStatus);
362+
public readonly projectController = new ProjectController(this.extensionContext, this.projectStatus, this.workspaceConfig);
359363
/**
360364
* The status bar controller
361365
*/
@@ -685,7 +689,6 @@ export class ExtensionManager implements vscode.Disposable {
685689
return;
686690
}
687691
const rootFolder: vscode.WorkspaceFolder = project.workspaceFolder;
688-
project.addTestExplorerRoot(project.folderPath);
689692
// Scan for kits even under presets mode, so we can create presets from compilers.
690693
// Silent re-scan when detecting a breaking change in the kits definition.
691694
// Do this only for the first folder, to avoid multiple rescans taking place in a multi-root workspace.
@@ -774,9 +777,10 @@ export class ExtensionManager implements vscode.Disposable {
774777

775778
private async initActiveProject(): Promise<CMakeProject | undefined> {
776779
let folder: vscode.WorkspaceFolder | undefined;
777-
if (vscode.workspace.workspaceFolders && vscode.window.activeTextEditor && this.workspaceConfig.autoSelectActiveFolder) {
780+
const workspaceFoldersWithProjects = this.projectController.getCMakeFoldersWithProject();
781+
if (workspaceFoldersWithProjects.length > 0 && vscode.window.activeTextEditor && this.workspaceConfig.autoSelectActiveFolder) {
778782
folder = vscode.workspace.getWorkspaceFolder(vscode.window.activeTextEditor.document.uri);
779-
await this.updateActiveProject(folder ?? vscode.workspace.workspaceFolders[0], folder ? vscode.window.activeTextEditor : undefined);
783+
await this.updateActiveProject(folder ?? workspaceFoldersWithProjects[0], folder ? vscode.window.activeTextEditor : undefined);
780784
return this.getActiveProject();
781785
}
782786
const activeFolder = this.extensionContext.workspaceState.get<string>('activeFolder');
@@ -789,11 +793,11 @@ export class ExtensionManager implements vscode.Disposable {
789793
if (defaultActiveFolder) {
790794
// do not use the active text editor for updating active project
791795
activeTextEditor = undefined;
792-
folder = vscode.workspace.workspaceFolders!.find(candidate => candidate.uri.path.endsWith(defaultActiveFolder));
796+
folder = workspaceFoldersWithProjects!.find(candidate => candidate.uri.path.endsWith(defaultActiveFolder));
793797
}
794798

795799
if (!folder) {
796-
folder = vscode.workspace.workspaceFolders![0];
800+
folder = workspaceFoldersWithProjects![0];
797801
}
798802
await this.updateActiveProject(folder, activeTextEditor);
799803
return this.getActiveProject();

0 commit comments

Comments
 (0)