From 5d09e6a2103096f1f9dc1b819b79b0ba0cad0e0a Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Mon, 3 Jun 2019 13:44:46 -0700 Subject: [PATCH 01/11] edit config name --- .../src/LanguageServer/configurations.ts | 170 +++++++++++++----- Extension/src/LanguageServer/settingsPanel.ts | 71 ++++++-- Extension/ui/settings.html | 71 ++++++-- Extension/ui/settings.ts | 160 ++++++++++++++--- 4 files changed, 371 insertions(+), 101 deletions(-) diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 3c37fd750f..a94dd4c93d 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -227,22 +227,6 @@ export class CppProperties { private onSelectionChanged(): void { this.selectionChanged.fire(this.CurrentConfigurationIndex); - if (this.settingsPanel) { - this.ensurePropertiesFile().then(() => { - if (this.propertiesFile) { - // Clear out any modifications we may have made internally by parsing the json file - if (this.parsePropertiesFile(false)) { - // Update the UI with new selected configuration - this.settingsPanel.updateConfigUI( - this.configurationJson.configurations[this.currentConfigurationIndex.Value], - this.getErrorsForConfigUI()); - } else { - // Parse failed, open json file - vscode.workspace.openTextDocument(this.propertiesFile); - } - } - }); - } this.handleSquiggles(); } @@ -397,20 +381,20 @@ export class CppProperties { } } - private isCompilerIntelliSenseModeCompatible(): boolean { + private isCompilerIntelliSenseModeCompatible(configuration: Configuration): boolean { // Check if intelliSenseMode and compilerPath are compatible // cl.exe and msvc mode should be used together // Ignore if compiler path is not set or intelliSenseMode is not set - if (this.CurrentConfiguration.compilerPath === undefined || - this.CurrentConfiguration.compilerPath === "" || - this.CurrentConfiguration.compilerPath === "${default}" || - this.CurrentConfiguration.intelliSenseMode === undefined || - this.CurrentConfiguration.intelliSenseMode === "" || - this.CurrentConfiguration.intelliSenseMode === "${default}") { + if (configuration.compilerPath === undefined || + configuration.compilerPath === "" || + configuration.compilerPath === "${default}" || + configuration.intelliSenseMode === undefined || + configuration.intelliSenseMode === "" || + configuration.intelliSenseMode === "${default}") { return true; } - let compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(this.CurrentConfiguration.compilerPath); - return compilerPathAndArgs.compilerPath.endsWith("cl.exe") === (this.CurrentConfiguration.intelliSenseMode === "msvc-x64"); + let compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(configuration.compilerPath); + return compilerPathAndArgs.compilerPath.endsWith("cl.exe") === (configuration.intelliSenseMode === "msvc-x64"); } public addToIncludePathCommand(path: string): void { @@ -635,6 +619,25 @@ export class CppProperties { }); } + private ensureSettingsPanelInitlialized(): void { + if (this.settingsPanel === undefined) { + let settings: CppSettings = new CppSettings(this.rootUri); + this.settingsPanel = new SettingsPanel(); // set initial this.currentConfigurationIndex.Value + this.settingsPanel.setKnownCompilers(this.knownCompilers, settings.preferredPathSeparator); + this.settingsPanel.SettingsPanelActivated(() => this.onSettingsPanelActivated()); + this.settingsPanel.ConfigValuesChanged(() => this.saveConfigurationUI()); + this.settingsPanel.ConfigSelectionChanged(() => this.onConfigSelectionChanged()); + this.settingsPanel.AddConfigRequested((e) => this.onAddConfigRequested(e)); + this.disposables.push(this.settingsPanel); + } + } + + private onConfigSelectionChanged(): void { + this.settingsPanel.updateConfigUI(this.ConfigurationNames, + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], + this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); + } + public handleConfigurationEditUICommand(onCreation: () => void, showDocument: (document: vscode.TextDocument) => void): void { this.ensurePropertiesFile().then(() => { if (this.propertiesFile) { @@ -642,18 +645,13 @@ export class CppProperties { onCreation(); } if (this.parsePropertiesFile(false)) { - // Parse successful, show UI - if (this.settingsPanel === undefined) { - let settings: CppSettings = new CppSettings(this.rootUri); - this.settingsPanel = new SettingsPanel(); - this.settingsPanel.setKnownCompilers(this.knownCompilers, settings.preferredPathSeparator); - this.settingsPanel.SettingsPanelActivated(() => this.onSettingsPanelActivated()); - this.settingsPanel.ConfigValuesChanged(() => this.saveConfigurationUI()); - this.disposables.push(this.settingsPanel); - } - this.settingsPanel.createOrShow( - this.configurationJson.configurations[this.currentConfigurationIndex.Value], - this.getErrorsForConfigUI()); + this.ensureSettingsPanelInitlialized(); + + // Use the active configuration as the default selected configuration to load on UI editor + this.settingsPanel.selectedConfigIndex = this.currentConfigurationIndex.Value; + this.settingsPanel.createOrShow(this.ConfigurationNames, + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], + this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); } else { // Parse failed, open json file vscode.workspace.openTextDocument(this.propertiesFile).then((document: vscode.TextDocument) => { @@ -673,9 +671,12 @@ export class CppProperties { if (this.parsePropertiesFile(false)) { // The settings UI became visible or active. // Ensure settingsPanel has copy of latest current configuration - this.settingsPanel.updateConfigUI( - this.configurationJson.configurations[this.currentConfigurationIndex.Value], - this.getErrorsForConfigUI()); + if (this.settingsPanel.selectedConfigIndex >= this.configurationJson.configurations.length) { + this.settingsPanel.selectedConfigIndex = this.currentConfigurationIndex.Value; + } + this.settingsPanel.updateConfigUI(this.ConfigurationNames, + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], + this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); } else { // Parse failed, open json file vscode.workspace.openTextDocument(this.propertiesFile); @@ -685,11 +686,80 @@ export class CppProperties { } } + private onAddConfigRequested(configName: string): void { + this.parsePropertiesFile(false); // Clear out any modifications we may have made internally. + + // Create default config + let newConfig: Configuration = { name: configName }; + this.applyDefaultConfigurationValues(newConfig); + this.configurationJson.configurations.push(newConfig); + + this.settingsPanel.selectedConfigIndex = this.configurationJson.configurations.length - 1; + delete this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex].knownCompilers; + + // Update UI + this.settingsPanel.updateConfigUI(this.ConfigurationNames, + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], + null); + + // Save new config to file + this.writeToJson(); + } + + private applyDefaultConfigurationValues(configuration: Configuration): void { + let settings: CppSettings = new CppSettings(this.rootUri); + let isUnset: (input: any) => boolean = (input: any) => { + // default values for "default" config settings is null. + return input === null; + }; + + // Anything that has a vscode setting for it will be resolved in updateServerOnFolderSettingsChange. + // So if a property is currently unset, but has a vscode setting, don't set it yet, otherwise the linkage + // to the setting will be lost if this configuration is saved into a c_cpp_properties.json file. + + // Only add settings from the default compiler if user hasn't explicitly set the corresponding VS Code setting. + + if (isUnset(settings.defaultIncludePath)) { + // We don't add system includes to the includePath anymore. The language server has this information. + let abTestSettings: ABTestSettings = getABTestSettings(); + let rootFolder: string = abTestSettings.UseRecursiveIncludes ? "${workspaceFolder}/**" : "${workspaceFolder}"; + configuration.includePath = [rootFolder].concat(this.vcpkgIncludes); + } + // browse.path is not set by default anymore. When it is not set, the includePath will be used instead. + if (isUnset(settings.defaultDefines)) { + configuration.defines = (process.platform === 'win32') ? ["_DEBUG", "UNICODE", "_UNICODE"] : []; + } + if (isUnset(settings.defaultMacFrameworkPath) && process.platform === 'darwin') { + configuration.macFrameworkPath = this.defaultFrameworks; + } + if (isUnset(settings.defaultWindowsSdkVersion) && this.defaultWindowsSdkVersion && process.platform === 'win32') { + configuration.windowsSdkVersion = this.defaultWindowsSdkVersion; + } + if (isUnset(settings.defaultCompilerPath) && this.defaultCompilerPath && + isUnset(settings.defaultCompileCommands) && !configuration.compileCommands) { + // compile_commands.json already specifies a compiler. compilerPath overrides the compile_commands.json compiler so + // don't set a default when compileCommands is in use. + configuration.compilerPath = this.defaultCompilerPath; + } + if (this.knownCompilers) { + configuration.knownCompilers = this.knownCompilers; + } + if (isUnset(settings.defaultCStandard) && this.defaultCStandard) { + configuration.cStandard = this.defaultCStandard; + } + if (isUnset(settings.defaultCppStandard) && this.defaultCppStandard) { + configuration.cppStandard = this.defaultCppStandard; + } + if (isUnset(settings.defaultIntelliSenseMode)) { + configuration.intelliSenseMode = this.defaultIntelliSenseMode; + } + } + private saveConfigurationUI(): void { this.parsePropertiesFile(false); // Clear out any modifications we may have made internally. let config: Configuration = this.settingsPanel.getLastValuesFromConfigUI(); - this.configurationJson.configurations[this.currentConfigurationIndex.Value] = config; - this.settingsPanel.updateErrors(this.getErrorsForConfigUI()); + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex] = config; + this.settingsPanel.updateErrors(this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); this.writeToJson(); } @@ -885,12 +955,14 @@ export class CppProperties { return result; } - private getErrorsForConfigUI(): ConfigurationErrors { + private getErrorsForConfigUI(configIndex: number): ConfigurationErrors { let errors: ConfigurationErrors = {}; const isWindows: boolean = os.platform() === 'win32'; + let config: Configuration = this.configurationJson.configurations[configIndex]; + // Validate compilerPath - let resolvedCompilerPath: string = this.resolvePath(this.CurrentConfiguration.compilerPath, isWindows); + let resolvedCompilerPath: string = this.resolvePath(config.compilerPath, isWindows); let compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(resolvedCompilerPath); if (resolvedCompilerPath && // Don't error cl.exe paths because it could be for an older preview build. @@ -949,8 +1021,8 @@ export class CppProperties { // Validate includePath let includePathErrors: string[] = []; - if (this.CurrentConfiguration.includePath) { - for (let includePath of this.CurrentConfiguration.includePath) { + if (config.includePath) { + for (let includePath of config.includePath) { let pathExists: boolean = true; let resolvedIncludePath: string = this.resolvePath(includePath, isWindows); if (!resolvedIncludePath) { @@ -987,8 +1059,8 @@ export class CppProperties { } // Validate intelliSenseMode - if (isWindows && !this.isCompilerIntelliSenseModeCompatible()) { - errors.intelliSenseMode = `IntelliSense mode ${this.CurrentConfiguration.intelliSenseMode} is incompatible with compiler path.`; + if (isWindows && !this.isCompilerIntelliSenseModeCompatible(config)) { + errors.intelliSenseMode = `IntelliSense mode ${config.intelliSenseMode} is incompatible with compiler path.`; } return errors; @@ -1055,7 +1127,7 @@ export class CppProperties { const intelliSenseModeValueStart: number = curText.indexOf('"', curText.indexOf(":", intelliSenseModeStart)); const intelliSenseModeValueEnd: number = intelliSenseModeStart === -1 ? -1 : curText.indexOf('"', intelliSenseModeValueStart + 1) + 1; - if (!this.isCompilerIntelliSenseModeCompatible()) { + if (!this.isCompilerIntelliSenseModeCompatible(this.CurrentConfiguration)) { let message: string = `intelliSenseMode ${this.CurrentConfiguration.intelliSenseMode} is incompatible with compilerPath.`; let diagnostic: vscode.Diagnostic = new vscode.Diagnostic( new vscode.Range(document.positionAt(curTextStartOffset + intelliSenseModeValueStart), diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index 5cd9be9de5..083507ed13 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -23,27 +23,39 @@ const elementId: { [key: string]: string } = { }; export class SettingsPanel { - private configValues: config.Configuration; - private compilerPaths: string[] = []; - private isIntelliSenseModeDefined: boolean = false; + private telemetry: { [key: string]: number } = {}; + private disposable: vscode.Disposable = undefined; + + // Events private settingsPanelActivated = new vscode.EventEmitter(); private configValuesChanged = new vscode.EventEmitter(); + private configSelectionChanged = new vscode.EventEmitter(); + private addConfigRequested = new vscode.EventEmitter(); + + // Configuration data + private configValues: config.Configuration; + private isIntelliSenseModeDefined: boolean = false; + private configIndexSelected: number = 0; + private configSelection: string[] = []; + private compilerPaths: string[] = []; + + // WebviewPanel objects private panel: vscode.WebviewPanel; - private disposable: vscode.Disposable = undefined; private disposablesPanel: vscode.Disposable = undefined; private static readonly viewType: string = 'settingsPanel'; private static readonly title: string = 'C/C++ Configurations'; - private telemetry: { [key: string]: number } = {}; constructor() { this.configValues = { name: undefined }; this.disposable = vscode.Disposable.from( this.settingsPanelActivated, - this.configValuesChanged + this.configValuesChanged, + this.configSelectionChanged, + this.addConfigRequested ); } - public createOrShow(activeConfiguration: config.Configuration, errors: config.ConfigurationErrors): void { + public createOrShow(configSelection: string[], activeConfiguration: config.Configuration, errors: config.ConfigurationErrors): void { const column: vscode.ViewColumn = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined; @@ -83,7 +95,7 @@ export class SettingsPanel { this.panel.webview.html = this.getHtml(); - this.updateWebview(activeConfiguration, errors); + this.updateWebview(configSelection, activeConfiguration, errors); } public get SettingsPanelActivated(): vscode.Event { @@ -94,13 +106,29 @@ export class SettingsPanel { return this.configValuesChanged.event; } + public get ConfigSelectionChanged(): vscode.Event { + return this.configSelectionChanged.event; + } + + public get AddConfigRequested(): vscode.Event { + return this.addConfigRequested.event; + } + + public get selectedConfigIndex(): number { + return this.configIndexSelected; + } + + public set selectedConfigIndex(index: number) { + this.configIndexSelected = index; + } + public getLastValuesFromConfigUI(): config.Configuration { return this.configValues; } - public updateConfigUI(configuration: config.Configuration, errors: config.ConfigurationErrors): void { + public updateConfigUI(configSelection: string[], configuration: config.Configuration, errors: config.ConfigurationErrors|null): void { if (this.panel) { - this.updateWebview(configuration, errors); + this.updateWebview(configSelection, configuration, errors); } } @@ -153,13 +181,16 @@ export class SettingsPanel { } } - private updateWebview(configuration: config.Configuration, errors: config.ConfigurationErrors): void { + private updateWebview(configSelection: string[], configuration: config.Configuration, errors: config.ConfigurationErrors|null): void { this.configValues = Object.assign({}, configuration); // Copy configuration values this.isIntelliSenseModeDefined = (this.configValues.intelliSenseMode !== undefined); if (this.panel) { this.panel.webview.postMessage({ command: 'setKnownCompilers', compilers: this.compilerPaths}); + this.panel.webview.postMessage({ command: 'updateConfigSelection', selections: configSelection, selectedIndex: this.configIndexSelected}); this.panel.webview.postMessage({ command: 'updateConfig', config: this.configValues}); - this.panel.webview.postMessage({ command: 'updateErrors', errors: errors}); + if (errors !== null) { + this.panel.webview.postMessage({ command: 'updateErrors', errors: errors}); + } } } @@ -182,9 +213,25 @@ export class SettingsPanel { switch (message.command) { case 'change': this.updateConfig(message); + break; + case 'configSelect': + this.configSelect(message.index); + break; + case 'addConfig': + this.addConfig(message.name); + break; } } + private addConfig(name: string): void { + this.addConfigRequested.fire(name); + } + + private configSelect(index: number): void { + this.configIndexSelected = index; + this.configSelectionChanged.fire(); + } + private updateConfig(message: any): void { let entries: string[]; diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 65bae3edac..51a66d4e75 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -102,6 +102,11 @@ outline-offset: -1px } + button:focus { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: 2px + } + hr { border: 0; height: 1px; @@ -122,6 +127,10 @@ text-decoration: underline } + ::placeholder { + color: var(--vscode-input-placeholderForeground); + } + input { height: 17px; padding: 6px; @@ -143,6 +152,18 @@ border: 1px solid var(--vscode-settings-textInputBorder); } + button { + color: var(--vscode-button-foreground); + background: var(--vscode-button-background); + border: 0px; + padding: 6px 14px; + } + + button:hover { + background: var(--vscode-button-hoverBackground); + border: 0px; + } + .select-default { width: 300px; height: 27px; @@ -157,7 +178,7 @@ position: relative; background-color: var(--vscode-settings-textInputBackground); width: 800px; - height: 30px; + height: 31px; } .select-editable select { @@ -165,7 +186,7 @@ font-size: 13px; font-family: sans-serif; border: 1px solid var(--vscode-settings-textInputBorder); - height: 30px; + height: 31px; margin: auto; color: var(--vscode-settings-textInputForeground); background: var(--vscode-settings-textInputBackground); @@ -177,7 +198,7 @@ left: 1px; right: 1px; bottom: 1px; - height: 16px; + height: 17px; font-size: 13px; border: none; color: var(--vscode-settings-textInputForeground); @@ -260,6 +281,12 @@ border: solid 1px rgb(255, 255, 255); } + .vscode-high-contrast button { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); + border: solid 1px var(--vscode-contrastBorder); + } + .vscode-high-contrast code > div { background-color: #000 } @@ -367,7 +394,7 @@
IntelliSense Configurations
Use this editor to edit basic IntelliSense settings defined in the underlying c_cpp_properties.json file. - Changes made in this editor only apply to the active configuration. To modify other configurations change the active configuration. + Changes made in this editor only apply to the selected configuration name. To edit multiple configurations at once, or additional settings not shown here, go to c_cpp_properties.json.
@@ -380,11 +407,31 @@
Configuration name
A friendly name that identifies a configuration. Mac, Linux, and Win32 are special identifiers for configurations that will be auto-selected on those platforms, but the name of the identifier can be anything. - To edit the name of the current active configuration, go to the c_cpp_properties.json file and edit the name property.
- +
+ +
Select a configuration set to edit.
+ + + + + +
+
+ + +
+
+
+ +
+ +
+
@@ -395,10 +442,10 @@
Specify a compiler path or select a detected compiler path from the drop-down list.
-
- - -
+
+ + +
diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index bc689e43ae..e9b31af1d3 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -15,7 +15,14 @@ const elementId: { [key: string]: string } = { compilerPathInvalid: "compilerPathInvalid", intelliSenseModeInvalid: "intelliSenseModeInvalid", includePathInvalid: "includePathInvalid", - knownCompilers: "knownCompilers" + knownCompilers: "knownCompilers", + configSelection: "configSelection", + addConfigDiv: "addConfigDiv", + addConfigBtn: "addConfigBtn", + addConfigInputDiv: "addConfigInputDiv", + addConfigOk: "addConfigOk", + addConfigCancel: "addConfigCancel", + addConfigName: "addConfigName" }; interface VsCodeApi { @@ -35,8 +42,9 @@ class SettingsApp { window.addEventListener('message', this.onMessageReceived.bind(this)); - document.getElementById(elementId.configName).addEventListener("change", this.onChanged.bind(this, elementId.configName)); - + document.getElementById(elementId.configName).addEventListener("change", this.onConfigNameChanged.bind(this)); + document.getElementById(elementId.configSelection).addEventListener("change", this.onConfigSelect.bind(this)); + document.getElementById(elementId.compilerPath).addEventListener("change", this.onChanged.bind(this, elementId.compilerPath)); document.getElementById(elementId.intelliSenseMode).addEventListener("change", this.onChanged.bind(this, elementId.intelliSenseMode)); @@ -47,14 +55,81 @@ class SettingsApp { document.getElementById(elementId.cppStandard).addEventListener("change", this.onChanged.bind(this, elementId.cppStandard)); document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); + + document.getElementById(elementId.addConfigBtn).addEventListener("click", this.onAddConfigBtn.bind(this)); + document.getElementById(elementId.addConfigOk).addEventListener("click", this.OnAddConfigConfirm.bind(this, true)); + document.getElementById(elementId.addConfigCancel).addEventListener("click", this.OnAddConfigConfirm.bind(this, false)); } private onKnownCompilerSelect(): void { + if (this.updating) { + return; + } + const x: HTMLInputElement = document.getElementById(elementId.knownCompilers); (document.getElementById(elementId.compilerPath)).value = x.value; this.onChanged(elementId.compilerPath); } + private onAddConfigBtn(): void { + // Hide "Add Configuration" button + document.getElementById(elementId.addConfigDiv).style.visibility = "hidden"; + // Show input field and buttons + document.getElementById(elementId.addConfigInputDiv).style.visibility = "visible"; + } + + private OnAddConfigConfirm(request: boolean): void { + // Hide input field and buttons + document.getElementById(elementId.addConfigInputDiv).style.visibility = "hidden"; + // Show "Add Configuration" button + document.getElementById(elementId.addConfigDiv).style.visibility = "visible"; + + // If request is yes, send message to create new config + if (request) { + const x: HTMLInputElement = document.getElementById(elementId.addConfigName); + if (x.value !== undefined && x.value !== "") { + this.vsCodeApi.postMessage({ + command: "addConfig", + name: x.value + }); + } + } + } + + private onConfigNameChanged(): void { + if (this.updating) { + return; + } + + const configName: HTMLInputElement = document.getElementById(elementId.configName); + let list: HTMLSelectElement = document.getElementById(elementId.configSelection); + + if (configName.value === "") { + (document.getElementById(elementId.configName)).value = list.options[list.selectedIndex].value; + return; + } + + // Update name on selection + list.options[list.selectedIndex].value = configName.value; + list.options[list.selectedIndex].text = configName.value; + + this.onChanged(elementId.configName); + } + + private onConfigSelect(): void { + if (this.updating) { + return; + } + + const x: HTMLSelectElement = document.getElementById(elementId.configSelection); + (document.getElementById(elementId.configName)).value = x.value; + + this.vsCodeApi.postMessage({ + command: "configSelect", + index: x.selectedIndex + }); + } + private onChanged(id: string): void { if (this.updating) { return; @@ -80,6 +155,9 @@ class SettingsApp { case 'setKnownCompilers': this.setKnownCompilers(message.compilers); break; + case 'updateConfigSelection': + this.updateConfigSelection(message); + break; } } @@ -120,36 +198,62 @@ class SettingsApp { document.getElementById(elementID).innerHTML = errorInfo ? errorInfo : ""; } - private setKnownCompilers(compilers: string[]): void { - let list: HTMLElement = document.getElementById(elementId.knownCompilers); + private updateConfigSelection(message: any): void { + this.updating = true; + try { + let list: HTMLElement = document.getElementById(elementId.configSelection); - // No need to add items unless webview is reloaded, in which case it will not have any elements. - // Otherwise, add items again. - if (list.firstChild) { - return; - } + // Clear list before updating + (list).options.length = 0; + + for (let name of message.selections) { + let option: HTMLOptionElement = document.createElement("option"); + option.text = name; + option.value = name; + list.append(option); + } - if (compilers.length === 0) { - const noCompilers: string = "(No compiler paths detected)"; - let option: HTMLOptionElement = document.createElement("option"); - option.text = noCompilers; - option.value = noCompilers; - list.append(option); - - // Set the selection to this one item so that no selection change event will be fired - (list).value = noCompilers; - return; + (list).selectedIndex = message.selectedIndex; + } finally { + this.updating = false; } + } - for (let path of compilers) { - let option: HTMLOptionElement = document.createElement("option"); - option.text = path; - option.value = path; - list.append(option); - } + private setKnownCompilers(compilers: string[]): void { + this.updating = true; + try { + let list: HTMLElement = document.getElementById(elementId.knownCompilers); - // Initialize list with no selected item - (list).value = ""; + // No need to add items unless webview is reloaded, in which case it will not have any elements. + // Otherwise, add items again. + if (list.firstChild) { + return; + } + + if (compilers.length === 0) { + const noCompilers: string = "(No compiler paths detected)"; + let option: HTMLOptionElement = document.createElement("option"); + option.text = noCompilers; + option.value = noCompilers; + list.append(option); + + // Set the selection to this one item so that no selection change event will be fired + (list).value = noCompilers; + return; + } + + for (let path of compilers) { + let option: HTMLOptionElement = document.createElement("option"); + option.text = path; + option.value = path; + list.append(option); + } + + // Initialize list with no selected item + (list).value = ""; + } finally { + this.updating = false; + } } } From 994f8b65e67ae01cc80b55194003003f1836dc9c Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Mon, 3 Jun 2019 14:38:01 -0700 Subject: [PATCH 02/11] button active style --- Extension/ui/settings.html | 41 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 51a66d4e75..ca37b7376b 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -107,6 +107,10 @@ outline-offset: 2px } + button:active { + outline: none; + } + hr { border: 0; height: 1px; @@ -409,26 +413,27 @@ A friendly name that identifies a configuration. Mac, Linux, and Win32 are special identifiers for configurations that will be auto-selected on those platforms, but the name of the identifier can be anything.
-
Select a configuration set to edit.
- - - + + + + +
-
- - -
-
-
- -
- -
+
+ + +
+
+
+ +
+ +
From c7430ba4e6e5611a4214e27286a6a6c88a0dc354 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Mon, 3 Jun 2019 15:11:02 -0700 Subject: [PATCH 03/11] refactor settings.ts --- Extension/ui/settings.html | 2 +- Extension/ui/settings.ts | 92 +++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index ca37b7376b..6cb46784e3 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -36,7 +36,7 @@ background: var(--vscode-inputValidation-errorBackground); border: solid 1px var(--vscode-inputValidation-errorBorder); white-space: pre-wrap; - visibility: hidden; + display: none; padding: 1px 4px 4px 4px; } diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index e9b31af1d3..a857f7671a 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -6,23 +6,25 @@ const elementId: { [key: string]: string } = { configName: "configName", - compilerPath: "compilerPath", - intelliSenseMode: "intelliSenseMode", - includePath: "includePath", - defines: "defines", - cStandard: "cStandard", - cppStandard: "cppStandard", - compilerPathInvalid: "compilerPathInvalid", - intelliSenseModeInvalid: "intelliSenseModeInvalid", - includePathInvalid: "includePathInvalid", - knownCompilers: "knownCompilers", configSelection: "configSelection", addConfigDiv: "addConfigDiv", addConfigBtn: "addConfigBtn", addConfigInputDiv: "addConfigInputDiv", addConfigOk: "addConfigOk", addConfigCancel: "addConfigCancel", - addConfigName: "addConfigName" + addConfigName: "addConfigName", + + compilerPath: "compilerPath", + compilerPathInvalid: "compilerPathInvalid", + knownCompilers: "knownCompilers", + + intelliSenseMode: "intelliSenseMode", + intelliSenseModeInvalid: "intelliSenseModeInvalid", + includePath: "includePath", + includePathInvalid: "includePathInvalid", + defines: "defines", + cStandard: "cStandard", + cppStandard: "cppStandard", }; interface VsCodeApi { @@ -45,7 +47,13 @@ class SettingsApp { document.getElementById(elementId.configName).addEventListener("change", this.onConfigNameChanged.bind(this)); document.getElementById(elementId.configSelection).addEventListener("change", this.onConfigSelect.bind(this)); + document.getElementById(elementId.addConfigBtn).addEventListener("click", this.onAddConfigBtn.bind(this)); + document.getElementById(elementId.addConfigOk).addEventListener("click", this.OnAddConfigConfirm.bind(this, true)); + document.getElementById(elementId.addConfigCancel).addEventListener("click", this.OnAddConfigConfirm.bind(this, false)); + document.getElementById(elementId.compilerPath).addEventListener("change", this.onChanged.bind(this, elementId.compilerPath)); + document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); + document.getElementById(elementId.intelliSenseMode).addEventListener("change", this.onChanged.bind(this, elementId.intelliSenseMode)); document.getElementById(elementId.includePath).addEventListener("change", this.onChanged.bind(this, elementId.includePath)); @@ -53,36 +61,16 @@ class SettingsApp { document.getElementById(elementId.cStandard).addEventListener("change", this.onChanged.bind(this, elementId.cStandard)); document.getElementById(elementId.cppStandard).addEventListener("change", this.onChanged.bind(this, elementId.cppStandard)); - - document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); - - document.getElementById(elementId.addConfigBtn).addEventListener("click", this.onAddConfigBtn.bind(this)); - document.getElementById(elementId.addConfigOk).addEventListener("click", this.OnAddConfigConfirm.bind(this, true)); - document.getElementById(elementId.addConfigCancel).addEventListener("click", this.OnAddConfigConfirm.bind(this, false)); - } - - private onKnownCompilerSelect(): void { - if (this.updating) { - return; - } - - const x: HTMLInputElement = document.getElementById(elementId.knownCompilers); - (document.getElementById(elementId.compilerPath)).value = x.value; - this.onChanged(elementId.compilerPath); } private onAddConfigBtn(): void { - // Hide "Add Configuration" button - document.getElementById(elementId.addConfigDiv).style.visibility = "hidden"; - // Show input field and buttons - document.getElementById(elementId.addConfigInputDiv).style.visibility = "visible"; + this.showElement(elementId.addConfigDiv, false); + this.showElement(elementId.addConfigInputDiv, true); } private OnAddConfigConfirm(request: boolean): void { - // Hide input field and buttons - document.getElementById(elementId.addConfigInputDiv).style.visibility = "hidden"; - // Show "Add Configuration" button - document.getElementById(elementId.addConfigDiv).style.visibility = "visible"; + this.showElement(elementId.addConfigInputDiv, false); + this.showElement(elementId.addConfigDiv, true); // If request is yes, send message to create new config if (request) { @@ -130,6 +118,15 @@ class SettingsApp { }); } + private onKnownCompilerSelect(): void { + if (this.updating) { + return; + } + const x: HTMLInputElement = document.getElementById(elementId.knownCompilers); + (document.getElementById(elementId.compilerPath)).value = x.value; + this.onChanged(elementId.compilerPath); + } + private onChanged(id: string): void { if (this.updating) { return; @@ -194,18 +191,19 @@ class SettingsApp { } private showErrorWithInfo(elementID: string, errorInfo: string): void { - document.getElementById(elementID).style.visibility = errorInfo ? "visible" : "hidden"; - document.getElementById(elementID).innerHTML = errorInfo ? errorInfo : ""; + this.showElement(elementID, errorInfo ? true : false); + document.getElementById(elementID).innerHTML = errorInfo ? errorInfo : ""; } private updateConfigSelection(message: any): void { this.updating = true; try { - let list: HTMLElement = document.getElementById(elementId.configSelection); + let list: HTMLSelectElement = document.getElementById(elementId.configSelection); // Clear list before updating - (list).options.length = 0; - + list.options.length = 0; + + // Update list for (let name of message.selections) { let option: HTMLOptionElement = document.createElement("option"); option.text = name; @@ -213,7 +211,7 @@ class SettingsApp { list.append(option); } - (list).selectedIndex = message.selectedIndex; + list.selectedIndex = message.selectedIndex; } finally { this.updating = false; } @@ -222,7 +220,7 @@ class SettingsApp { private setKnownCompilers(compilers: string[]): void { this.updating = true; try { - let list: HTMLElement = document.getElementById(elementId.knownCompilers); + let list: HTMLSelectElement = document.getElementById(elementId.knownCompilers); // No need to add items unless webview is reloaded, in which case it will not have any elements. // Otherwise, add items again. @@ -238,7 +236,7 @@ class SettingsApp { list.append(option); // Set the selection to this one item so that no selection change event will be fired - (list).value = noCompilers; + list.value = noCompilers; return; } @@ -248,13 +246,17 @@ class SettingsApp { option.value = path; list.append(option); } - + // Initialize list with no selected item - (list).value = ""; + list.value = ""; } finally { this.updating = false; } } + + private showElement(elementID: string, show: boolean): void { + document.getElementById(elementID).style.display = show ? "block" : "none"; + } } let app: SettingsApp = new SettingsApp(); From 45158f352062ed8febca033ffb80e6f469abec38 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Mon, 3 Jun 2019 15:30:23 -0700 Subject: [PATCH 04/11] clean up configurations.ts --- .../src/LanguageServer/configurations.ts | 172 +++++++----------- 1 file changed, 63 insertions(+), 109 deletions(-) diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index a94dd4c93d..bc4edd2064 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -257,53 +257,57 @@ export class CppProperties { private applyDefaultIncludePathsAndFrameworks(): void { if (this.configurationIncomplete && this.defaultIncludes && this.defaultFrameworks && this.vcpkgPathReady) { let configuration: Configuration = this.CurrentConfiguration; - let settings: CppSettings = new CppSettings(this.rootUri); - let isUnset: (input: any) => boolean = (input: any) => { + this.applyDefaultConfigurationValues(configuration); + this.configurationIncomplete = false; + } + } + + private applyDefaultConfigurationValues(configuration: Configuration): void { + let settings: CppSettings = new CppSettings(this.rootUri); + let isUnset: (input: any) => boolean = (input: any) => { // default values for "default" config settings is null. return input === null; - }; + }; - // Anything that has a vscode setting for it will be resolved in updateServerOnFolderSettingsChange. - // So if a property is currently unset, but has a vscode setting, don't set it yet, otherwise the linkage - // to the setting will be lost if this configuration is saved into a c_cpp_properties.json file. + // Anything that has a vscode setting for it will be resolved in updateServerOnFolderSettingsChange. + // So if a property is currently unset, but has a vscode setting, don't set it yet, otherwise the linkage + // to the setting will be lost if this configuration is saved into a c_cpp_properties.json file. - // Only add settings from the default compiler if user hasn't explicitly set the corresponding VS Code setting. + // Only add settings from the default compiler if user hasn't explicitly set the corresponding VS Code setting. - if (isUnset(settings.defaultIncludePath)) { - // We don't add system includes to the includePath anymore. The language server has this information. - let abTestSettings: ABTestSettings = getABTestSettings(); - let rootFolder: string = abTestSettings.UseRecursiveIncludes ? "${workspaceFolder}/**" : "${workspaceFolder}"; - configuration.includePath = [rootFolder].concat(this.vcpkgIncludes); - } - // browse.path is not set by default anymore. When it is not set, the includePath will be used instead. - if (isUnset(settings.defaultDefines)) { - configuration.defines = (process.platform === 'win32') ? ["_DEBUG", "UNICODE", "_UNICODE"] : []; - } - if (isUnset(settings.defaultMacFrameworkPath) && process.platform === 'darwin') { - configuration.macFrameworkPath = this.defaultFrameworks; - } - if (isUnset(settings.defaultWindowsSdkVersion) && this.defaultWindowsSdkVersion && process.platform === 'win32') { - configuration.windowsSdkVersion = this.defaultWindowsSdkVersion; - } - if (isUnset(settings.defaultCompilerPath) && this.defaultCompilerPath && - isUnset(settings.defaultCompileCommands) && !configuration.compileCommands) { - // compile_commands.json already specifies a compiler. compilerPath overrides the compile_commands.json compiler so - // don't set a default when compileCommands is in use. - configuration.compilerPath = this.defaultCompilerPath; - } - if (this.knownCompilers) { - configuration.knownCompilers = this.knownCompilers; - } - if (isUnset(settings.defaultCStandard) && this.defaultCStandard) { - configuration.cStandard = this.defaultCStandard; - } - if (isUnset(settings.defaultCppStandard) && this.defaultCppStandard) { - configuration.cppStandard = this.defaultCppStandard; - } - if (isUnset(settings.defaultIntelliSenseMode)) { - configuration.intelliSenseMode = this.defaultIntelliSenseMode; - } - this.configurationIncomplete = false; + if (isUnset(settings.defaultIncludePath)) { + // We don't add system includes to the includePath anymore. The language server has this information. + let abTestSettings: ABTestSettings = getABTestSettings(); + let rootFolder: string = abTestSettings.UseRecursiveIncludes ? "${workspaceFolder}/**" : "${workspaceFolder}"; + configuration.includePath = [rootFolder].concat(this.vcpkgIncludes); + } + // browse.path is not set by default anymore. When it is not set, the includePath will be used instead. + if (isUnset(settings.defaultDefines)) { + configuration.defines = (process.platform === 'win32') ? ["_DEBUG", "UNICODE", "_UNICODE"] : []; + } + if (isUnset(settings.defaultMacFrameworkPath) && process.platform === 'darwin') { + configuration.macFrameworkPath = this.defaultFrameworks; + } + if (isUnset(settings.defaultWindowsSdkVersion) && this.defaultWindowsSdkVersion && process.platform === 'win32') { + configuration.windowsSdkVersion = this.defaultWindowsSdkVersion; + } + if (isUnset(settings.defaultCompilerPath) && this.defaultCompilerPath && + isUnset(settings.defaultCompileCommands) && !configuration.compileCommands) { + // compile_commands.json already specifies a compiler. compilerPath overrides the compile_commands.json compiler so + // don't set a default when compileCommands is in use. + configuration.compilerPath = this.defaultCompilerPath; + } + if (this.knownCompilers) { + configuration.knownCompilers = this.knownCompilers; + } + if (isUnset(settings.defaultCStandard) && this.defaultCStandard) { + configuration.cStandard = this.defaultCStandard; + } + if (isUnset(settings.defaultCppStandard) && this.defaultCppStandard) { + configuration.cppStandard = this.defaultCppStandard; + } + if (isUnset(settings.defaultIntelliSenseMode)) { + configuration.intelliSenseMode = this.defaultIntelliSenseMode; } } @@ -632,12 +636,6 @@ export class CppProperties { } } - private onConfigSelectionChanged(): void { - this.settingsPanel.updateConfigUI(this.ConfigurationNames, - this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], - this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); - } - public handleConfigurationEditUICommand(onCreation: () => void, showDocument: (document: vscode.TextDocument) => void): void { this.ensurePropertiesFile().then(() => { if (this.propertiesFile) { @@ -686,18 +684,31 @@ export class CppProperties { } } + private saveConfigurationUI(): void { + this.parsePropertiesFile(false); // Clear out any modifications we may have made internally. + let config: Configuration = this.settingsPanel.getLastValuesFromConfigUI(); + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex] = config; + this.settingsPanel.updateErrors(this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); + this.writeToJson(); + } + + private onConfigSelectionChanged(): void { + this.settingsPanel.updateConfigUI(this.ConfigurationNames, + this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], + this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); + } + private onAddConfigRequested(configName: string): void { this.parsePropertiesFile(false); // Clear out any modifications we may have made internally. - // Create default config + // Create default config and add to list of configurations let newConfig: Configuration = { name: configName }; this.applyDefaultConfigurationValues(newConfig); + delete newConfig.knownCompilers; this.configurationJson.configurations.push(newConfig); - this.settingsPanel.selectedConfigIndex = this.configurationJson.configurations.length - 1; - delete this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex].knownCompilers; - // Update UI + this.settingsPanel.selectedConfigIndex = this.configurationJson.configurations.length - 1; this.settingsPanel.updateConfigUI(this.ConfigurationNames, this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex], null); @@ -706,63 +717,6 @@ export class CppProperties { this.writeToJson(); } - private applyDefaultConfigurationValues(configuration: Configuration): void { - let settings: CppSettings = new CppSettings(this.rootUri); - let isUnset: (input: any) => boolean = (input: any) => { - // default values for "default" config settings is null. - return input === null; - }; - - // Anything that has a vscode setting for it will be resolved in updateServerOnFolderSettingsChange. - // So if a property is currently unset, but has a vscode setting, don't set it yet, otherwise the linkage - // to the setting will be lost if this configuration is saved into a c_cpp_properties.json file. - - // Only add settings from the default compiler if user hasn't explicitly set the corresponding VS Code setting. - - if (isUnset(settings.defaultIncludePath)) { - // We don't add system includes to the includePath anymore. The language server has this information. - let abTestSettings: ABTestSettings = getABTestSettings(); - let rootFolder: string = abTestSettings.UseRecursiveIncludes ? "${workspaceFolder}/**" : "${workspaceFolder}"; - configuration.includePath = [rootFolder].concat(this.vcpkgIncludes); - } - // browse.path is not set by default anymore. When it is not set, the includePath will be used instead. - if (isUnset(settings.defaultDefines)) { - configuration.defines = (process.platform === 'win32') ? ["_DEBUG", "UNICODE", "_UNICODE"] : []; - } - if (isUnset(settings.defaultMacFrameworkPath) && process.platform === 'darwin') { - configuration.macFrameworkPath = this.defaultFrameworks; - } - if (isUnset(settings.defaultWindowsSdkVersion) && this.defaultWindowsSdkVersion && process.platform === 'win32') { - configuration.windowsSdkVersion = this.defaultWindowsSdkVersion; - } - if (isUnset(settings.defaultCompilerPath) && this.defaultCompilerPath && - isUnset(settings.defaultCompileCommands) && !configuration.compileCommands) { - // compile_commands.json already specifies a compiler. compilerPath overrides the compile_commands.json compiler so - // don't set a default when compileCommands is in use. - configuration.compilerPath = this.defaultCompilerPath; - } - if (this.knownCompilers) { - configuration.knownCompilers = this.knownCompilers; - } - if (isUnset(settings.defaultCStandard) && this.defaultCStandard) { - configuration.cStandard = this.defaultCStandard; - } - if (isUnset(settings.defaultCppStandard) && this.defaultCppStandard) { - configuration.cppStandard = this.defaultCppStandard; - } - if (isUnset(settings.defaultIntelliSenseMode)) { - configuration.intelliSenseMode = this.defaultIntelliSenseMode; - } - } - - private saveConfigurationUI(): void { - this.parsePropertiesFile(false); // Clear out any modifications we may have made internally. - let config: Configuration = this.settingsPanel.getLastValuesFromConfigUI(); - this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex] = config; - this.settingsPanel.updateErrors(this.getErrorsForConfigUI(this.settingsPanel.selectedConfigIndex)); - this.writeToJson(); - } - private handleConfigurationChange(): void { if (this.propertiesFile === undefined) { return; // Occurs when propertiesFile hasn't been checked yet. From 12dc7a77338a3a217ab68c816b592666bcebe7f0 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 11:34:51 -0700 Subject: [PATCH 05/11] advanced settings --- Extension/src/LanguageServer/settingsPanel.ts | 91 ++++++++-- Extension/ui/settings.html | 163 ++++++++++++++++-- Extension/ui/settings.ts | 73 +++++++- 3 files changed, 295 insertions(+), 32 deletions(-) diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index 083507ed13..1fe6b6142d 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -13,13 +13,40 @@ import * as telemetry from '../telemetry'; // TODO: share ElementId between SettingsPanel and SettingsApp. Investigate why SettingsApp cannot import/export const elementId: { [key: string]: string } = { + // Basic settings configName: "configName", + configSelection: "configSelection", + addConfigBtn: "addConfigBtn", + addConfigOk: "addConfigOk", + addConfigCancel: "addConfigCancel", + addConfigName: "addConfigName", + compilerPath: "compilerPath", - intelliSenseMode: "intelliSenseMode", + compilerPathInvalid: "compilerPathInvalid", + knownCompilers: "knownCompilers", + + intelliSenseMode: "intelliSenseMode", + intelliSenseModeInvalid: "intelliSenseModeInvalid", includePath: "includePath", + includePathInvalid: "includePathInvalid", defines: "defines", cStandard: "cStandard", - cppStandard: "cppStandard" + cppStandard: "cppStandard", + + // Advance settings + windowsSdkVersion: "windowsSdkVersion", + macFrameworkPath: "macFrameworkPath", + compileCommands: "compileCommands", + configurationProvider: "configurationProvider", + forcedInclude: "forcedInclude", + + // Browse properties + browsePath: "browsePath", + limitSymbolsToIncludedHeaders: "limitSymbolsToIncludedHeaders", + databaseFilename: "databaseFilename", + + // Other + showAdvancedBtn: "showAdvancedBtn" }; export class SettingsPanel { @@ -220,39 +247,44 @@ export class SettingsPanel { case 'addConfig': this.addConfig(message.name); break; + case 'knownCompilerSelect': + this.knownCompilerSelect(); + break; } } private addConfig(name: string): void { this.addConfigRequested.fire(name); + this.logTelementryForElement(elementId.addConfigName); } private configSelect(index: number): void { this.configIndexSelected = index; this.configSelectionChanged.fire(); + this.logTelementryForElement(elementId.configSelection); + } + + private knownCompilerSelect(): void { + this.logTelementryForElement(elementId.knownCompilers); } private updateConfig(message: any): void { - let entries: string[]; + let splitEntries: (input: any) => string[] = (input: any) => { + return input.split("\n").filter((e: string) => e); + }; switch (message.key) { case elementId.configName: this.configValues.name = message.value; - this.logTelementryForElement(elementId.configName); break; case elementId.compilerPath: this.configValues.compilerPath = message.value; - this.logTelementryForElement(elementId.compilerPath); break; case elementId.includePath: - entries = message.value.split("\n"); - this.configValues.includePath = entries.filter(e => e); - this.logTelementryForElement(elementId.includePath); + this.configValues.includePath = splitEntries(message.value); break; case elementId.defines: - entries = message.value.split("\n"); - this.configValues.defines = entries.filter(e => e); - this.logTelementryForElement(elementId.defines); + this.configValues.defines = splitEntries(message.value); break; case elementId.intelliSenseMode: if (message.value !== "${default}" || this.isIntelliSenseModeDefined) { @@ -260,19 +292,44 @@ export class SettingsPanel { } else { this.configValues.intelliSenseMode = undefined; } - this.logTelementryForElement(elementId.intelliSenseMode); break; case elementId.cStandard: this.configValues.cStandard = message.value; - this.logTelementryForElement(elementId.cStandard); break; case elementId.cppStandard: this.configValues.cppStandard = message.value; - this.logTelementryForElement(elementId.cppStandard); + break; + case elementId.windowsSdkVersion: + this.configValues.windowsSdkVersion = message.value; + break; + case elementId.macFrameworkPath: + this.configValues.macFrameworkPath = splitEntries(message.value); + break; + case elementId.compileCommands: + this.configValues.compileCommands = message.value; + break; + case elementId.configurationProvider: + this.configValues.configurationProvider = message.value; + break; + case elementId.forcedInclude: + this.configValues.forcedInclude = splitEntries(message.value); + break; + case elementId.browsePath: + this.initializeBrowseProperties(); + this.configValues.browse.path = splitEntries(message.value); + break; + case elementId.limitSymbolsToIncludedHeaders: + this.initializeBrowseProperties(); + this.configValues.browse.limitSymbolsToIncludedHeaders = (message.value === "on" ? true : false); + break; + case elementId.databaseFilename: + this.initializeBrowseProperties(); + this.configValues.browse.databaseFilename = message.value; break; } this.configValuesChanged.fire(); + this.logTelementryForElement(message.key); } private logTelementryForElement(elementId: string): void { @@ -282,6 +339,12 @@ export class SettingsPanel { this.telemetry[elementId]++; } + private initializeBrowseProperties(): void { + if (this.configValues.browse === undefined) { + this.configValues.browse = {}; + } + } + private getHtml(): string { let content: string | undefined; content = fs.readFileSync(util.getExtensionFilePath("ui/settings.html")).toString(); diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 6cb46784e3..7b4125153e 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -40,6 +40,41 @@ padding: 1px 4px 4px 4px; } + .headerBtn, + .headerBtn:hover, + .headerBtn:active, + .headerBtn:focus { + cursor: pointer; + color: var(--vscode-foreground); + background: var(--vscode-background); + border: 0px; + padding: 0px; + outline: none; + } + + .headerBtn:focus:not(:hover):not(:active) { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: 3px; + } + + .expand:after { + font-weight: bold; + float: right; + margin-right: 6px; + margin-top: -4px; + content: '\276E'; + transform: rotate(90deg); + } + + .collapse:after { + font-weight: bold; + float: right; + margin-right: 6px; + margin-top: -4px; + content: '\276E'; + transform: rotate(270deg); + } + .main { max-width: 800px; margin-left: 320px; @@ -94,6 +129,12 @@ text-decoration: none } + checkbox { + color: var(--vscode-settings-checkboxForeground); + background: var(--vscode-settings-checkboxForeground); + border: var(--vscode-settings-checkboxBorder); + } + a:focus, input:focus, select:focus, @@ -102,15 +143,6 @@ outline-offset: -1px } - button:focus { - outline: 1px solid -webkit-focus-ring-color; - outline-offset: 2px - } - - button:active { - outline: none; - } - hr { border: 0; height: 1px; @@ -168,6 +200,15 @@ border: 0px; } + button:focus { + outline: 1px solid -webkit-focus-ring-color; + outline-offset: 2px + } + + button:active { + outline: none; + } + .select-default { width: 300px; height: 27px; @@ -399,7 +440,7 @@
Use this editor to edit basic IntelliSense settings defined in the underlying c_cpp_properties.json file. Changes made in this editor only apply to the selected configuration name. - To edit multiple configurations at once, or additional settings not shown here, go to c_cpp_properties.json. + To edit multiple configurations at once go to c_cpp_properties.json.
@@ -519,10 +560,108 @@ - - + +
+ +
+ +
+ +
+
Configuration provider
+
+ The ID of a VS Code extension that can provide IntelliSense configuration information for source files. +
+
+ +
+
+ +
+
Windows SDK version
+
+ Version of the Windows SDK include path to use on Windows, e.g. 10.0.17134.0. +
+
+ +
+
+ +
+
Mac framework path
+
+ A list of paths for the Intellisense engine to use while searching for included headers from Mac frameworks. Only supported on Mac configuration. +
+
+
One path per line.
+ +
+
+ +
+
Forced include
+
+ A list of files that should be included before any other characters in the source file are processed. Files are included in the order listed. +
+
+
One file per line.
+ +
+
+ +
+
Compile commands
+
+ Full path to compile_commands.json file for the workspace. +
+
+ +
+
+ +
+
Browse: path
+
+ A list of paths for the tag parser to use while searching for included headers. + Searching on these paths is recursive by default. Specify * to indicate non-recursive search. + For example: /usr/include will search through all subdirectories while /usr/include/* will not. +
+
+
One browse path per line.
+ +
+
+ +
+
Browse: limit symbols to included headers
+
+ + Process only those files directly or indirectly included as headers. If not set, process all files under the specified include paths. + +
+
+ +
+
Browse: database filename
+
+ Path to the generated symbol database. If a relative path is specified, + it will be made relative to the workspace's default storage location. +
+
+ +
+
+ +
+ + + + + diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index a857f7671a..0ec31e86fb 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -5,6 +5,7 @@ 'use strict'; const elementId: { [key: string]: string } = { + // Basic settings configName: "configName", configSelection: "configSelection", addConfigDiv: "addConfigDiv", @@ -25,6 +26,22 @@ const elementId: { [key: string]: string } = { defines: "defines", cStandard: "cStandard", cppStandard: "cppStandard", + + // Advance settings + windowsSdkVersion: "windowsSdkVersion", + macFrameworkPath: "macFrameworkPath", + compileCommands: "compileCommands", + configurationProvider: "configurationProvider", + forcedInclude: "forcedInclude", + + // Browse properties + browsePath: "browsePath", + limitSymbolsToIncludedHeaders: "limitSymbolsToIncludedHeaders", + databaseFilename: "databaseFilename", + + // Other + showAdvanced: "showAdvanced", + advancedSection: "advancedSection" }; interface VsCodeApi { @@ -44,23 +61,44 @@ class SettingsApp { window.addEventListener('message', this.onMessageReceived.bind(this)); + // Basic settings document.getElementById(elementId.configName).addEventListener("change", this.onConfigNameChanged.bind(this)); document.getElementById(elementId.configSelection).addEventListener("change", this.onConfigSelect.bind(this)); - document.getElementById(elementId.addConfigBtn).addEventListener("click", this.onAddConfigBtn.bind(this)); document.getElementById(elementId.addConfigOk).addEventListener("click", this.OnAddConfigConfirm.bind(this, true)); document.getElementById(elementId.addConfigCancel).addEventListener("click", this.OnAddConfigConfirm.bind(this, false)); document.getElementById(elementId.compilerPath).addEventListener("change", this.onChanged.bind(this, elementId.compilerPath)); document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); - document.getElementById(elementId.intelliSenseMode).addEventListener("change", this.onChanged.bind(this, elementId.intelliSenseMode)); - document.getElementById(elementId.includePath).addEventListener("change", this.onChanged.bind(this, elementId.includePath)); document.getElementById(elementId.defines).addEventListener("change", this.onChanged.bind(this, elementId.defines)); - document.getElementById(elementId.cStandard).addEventListener("change", this.onChanged.bind(this, elementId.cStandard)); document.getElementById(elementId.cppStandard).addEventListener("change", this.onChanged.bind(this, elementId.cppStandard)); + + // Advanced settings + document.getElementById(elementId.windowsSdkVersion).addEventListener("change", this.onChanged.bind(this, elementId.windowsSdkVersion)); + document.getElementById(elementId.macFrameworkPath).addEventListener("change", this.onChanged.bind(this, elementId.macFrameworkPath)); + document.getElementById(elementId.compileCommands).addEventListener("change", this.onChanged.bind(this, elementId.compileCommands)); + document.getElementById(elementId.configurationProvider).addEventListener("change", this.onChanged.bind(this, elementId.configurationProvider)); + + // Browse properties + document.getElementById(elementId.browsePath).addEventListener("change", this.onChanged.bind(this, elementId.browsePath)); + document.getElementById(elementId.limitSymbolsToIncludedHeaders).addEventListener("change", this.onChanged.bind(this, elementId.limitSymbolsToIncludedHeaders)); + document.getElementById(elementId.databaseFilename).addEventListener("change", this.onChanged.bind(this, elementId.databaseFilename)); + + // Other + document.getElementById(elementId.showAdvanced).addEventListener("click", this.onShowAdvanced.bind(this)); + document.getElementById(elementId.advancedSection).style.display = "none"; + } + + private onShowAdvanced(): void { + let isShown: boolean = (document.getElementById(elementId.advancedSection).style.display === "block"); + document.getElementById(elementId.advancedSection).style.display = isShown ? "none" : "block"; + + let element: HTMLElement = document.getElementById(elementId.showAdvanced); + element.classList.toggle('collapse'); + element.classList.toggle('expand'); } private onAddConfigBtn(): void { @@ -161,8 +199,8 @@ class SettingsApp { private updateConfig(config: any): void { this.updating = true; try { + // Basic settings (document.getElementById(elementId.configName)).value = config.name; - (document.getElementById(elementId.compilerPath)).value = config.compilerPath ? config.compilerPath : ""; (document.getElementById(elementId.intelliSenseMode)).value = config.intelliSenseMode ? config.intelliSenseMode : "${default}"; @@ -174,6 +212,29 @@ class SettingsApp { (document.getElementById(elementId.cStandard)).value = config.cStandard; (document.getElementById(elementId.cppStandard)).value = config.cppStandard; + + // Advance settings + (document.getElementById(elementId.windowsSdkVersion)).value = config.windowsSdkVersion ? config.windowsSdkVersion : ""; + + (document.getElementById(elementId.macFrameworkPath)).value = + (config.macFrameworkPath && config.macFrameworkPath.length > 0) ? config.macFrameworkPath.join("\n") : ""; + + (document.getElementById(elementId.compileCommands)).value = config.compileCommands ? config.compileCommands : ""; + (document.getElementById(elementId.configurationProvider)).value = config.configurationProvider ? config.configurationProvider : ""; + + (document.getElementById(elementId.forcedInclude)).value = + (config.forcedInclude && config.forcedInclude.length > 0) ? config.forcedInclude.join("\n") : ""; + + if (config.browse) { + (document.getElementById(elementId.browsePath)).value = + (config.browse.path && config.browse.path.length > 0) ? config.browse.path.join("\n") : ""; + (document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked = config.browse.limitSymbolsToIncludedHeaders ? true : false; + (document.getElementById(elementId.databaseFilename)).value = config.browse.databaseFilename ? config.browse.databaseFilename : ""; + } else { + (document.getElementById(elementId.browsePath)).value = ""; + (document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked = false; + (document.getElementById(elementId.databaseFilename)).value = ""; + } } finally { this.updating = false; } @@ -234,7 +295,7 @@ class SettingsApp { option.text = noCompilers; option.value = noCompilers; list.append(option); - + // Set the selection to this one item so that no selection change event will be fired list.value = noCompilers; return; From 88954db4ddb0c54521c76599e779eabbe2b04b55 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 12:36:57 -0700 Subject: [PATCH 06/11] telemetry compilerPath & listen to forecedInclude --- Extension/src/LanguageServer/settingsPanel.ts | 4 ++++ Extension/ui/settings.ts | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index 1fe6b6142d..cbf214c52a 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -266,6 +266,10 @@ export class SettingsPanel { private knownCompilerSelect(): void { this.logTelementryForElement(elementId.knownCompilers); + // Remove one count from compilerPath because selecting a different compiler causes a change on the compiler path + if (this.telemetry[elementId.compilerPath]) { + this.telemetry[elementId.compilerPath]--; + } } private updateConfig(message: any): void { diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index 0ec31e86fb..fa69b75979 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -81,6 +81,7 @@ class SettingsApp { document.getElementById(elementId.macFrameworkPath).addEventListener("change", this.onChanged.bind(this, elementId.macFrameworkPath)); document.getElementById(elementId.compileCommands).addEventListener("change", this.onChanged.bind(this, elementId.compileCommands)); document.getElementById(elementId.configurationProvider).addEventListener("change", this.onChanged.bind(this, elementId.configurationProvider)); + document.getElementById(elementId.forcedInclude).addEventListener("change", this.onChanged.bind(this, elementId.forcedInclude)); // Browse properties document.getElementById(elementId.browsePath).addEventListener("change", this.onChanged.bind(this, elementId.browsePath)); @@ -163,6 +164,11 @@ class SettingsApp { const x: HTMLInputElement = document.getElementById(elementId.knownCompilers); (document.getElementById(elementId.compilerPath)).value = x.value; this.onChanged(elementId.compilerPath); + + // Post message that this control was used for telemetry + this.vsCodeApi.postMessage({ + command: "knownCompilerSelect" + }); } private onChanged(id: string): void { From 03e875e41ff6df9efe3f8152fe592ea6b082f9e5 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 12:44:13 -0700 Subject: [PATCH 07/11] fix lint --- Extension/src/LanguageServer/settingsPanel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index cbf214c52a..280e14dcb9 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -63,7 +63,6 @@ export class SettingsPanel { private configValues: config.Configuration; private isIntelliSenseModeDefined: boolean = false; private configIndexSelected: number = 0; - private configSelection: string[] = []; private compilerPaths: string[] = []; // WebviewPanel objects From 4ca31512239094f2ccaf727ee4077eee127753b1 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 13:26:57 -0700 Subject: [PATCH 08/11] fix spelling --- Extension/src/LanguageServer/settingsPanel.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index 280e14dcb9..9231d72ba7 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -33,7 +33,7 @@ const elementId: { [key: string]: string } = { cStandard: "cStandard", cppStandard: "cppStandard", - // Advance settings + // Advanced settings windowsSdkVersion: "windowsSdkVersion", macFrameworkPath: "macFrameworkPath", compileCommands: "compileCommands", @@ -183,7 +183,7 @@ export class SettingsPanel { } public dispose(): void { - // Log any telementry + // Log any telemetry if (Object.keys(this.telemetry).length > 0) { telemetry.logLanguageServerEvent("ConfigUI", null, this.telemetry); } @@ -254,17 +254,17 @@ export class SettingsPanel { private addConfig(name: string): void { this.addConfigRequested.fire(name); - this.logTelementryForElement(elementId.addConfigName); + this.logTelemetryForElement(elementId.addConfigName); } private configSelect(index: number): void { this.configIndexSelected = index; this.configSelectionChanged.fire(); - this.logTelementryForElement(elementId.configSelection); + this.logTelemetryForElement(elementId.configSelection); } private knownCompilerSelect(): void { - this.logTelementryForElement(elementId.knownCompilers); + this.logTelemetryForElement(elementId.knownCompilers); // Remove one count from compilerPath because selecting a different compiler causes a change on the compiler path if (this.telemetry[elementId.compilerPath]) { this.telemetry[elementId.compilerPath]--; @@ -332,10 +332,10 @@ export class SettingsPanel { } this.configValuesChanged.fire(); - this.logTelementryForElement(message.key); + this.logTelemetryForElement(message.key); } - private logTelementryForElement(elementId: string): void { + private logTelemetryForElement(elementId: string): void { if (this.telemetry[elementId] === undefined) { this.telemetry[elementId] = 0; } From 3e91e257d65405ba3a2514fb270d651c3d763dc0 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 15:28:07 -0700 Subject: [PATCH 09/11] spelling & fix contrast color for buttons --- Extension/ui/settings.html | 26 +++++++++----------------- Extension/ui/settings.ts | 2 +- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 7b4125153e..2c870f7cd2 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -42,8 +42,7 @@ .headerBtn, .headerBtn:hover, - .headerBtn:active, - .headerBtn:focus { + .headerBtn:active { cursor: pointer; color: var(--vscode-foreground); background: var(--vscode-background); @@ -52,7 +51,7 @@ outline: none; } - .headerBtn:focus:not(:hover):not(:active) { + .headerBtn:focus { outline: 1px solid -webkit-focus-ring-color; outline-offset: 3px; } @@ -190,14 +189,13 @@ button { color: var(--vscode-button-foreground); - background: var(--vscode-button-background); - border: 0px; + background-color: var(--vscode-button-background); + border: solid 1px var(--vscode-contrastBorder); padding: 6px 14px; } button:hover { - background: var(--vscode-button-hoverBackground); - border: 0px; + background-color: var(--vscode-button-hoverBackground); } button:focus { @@ -326,12 +324,6 @@ border: solid 1px rgb(255, 255, 255); } - .vscode-high-contrast button { - color: var(--vscode-button-foreground); - background-color: var(--vscode-button-background); - border: solid 1px var(--vscode-contrastBorder); - } - .vscode-high-contrast code > div { background-color: #000 } @@ -439,7 +431,7 @@
IntelliSense Configurations
Use this editor to edit basic IntelliSense settings defined in the underlying c_cpp_properties.json file. - Changes made in this editor only apply to the selected configuration name. + Changes made in this editor only apply to the selected configuration. To edit multiple configurations at once go to c_cpp_properties.json.
@@ -538,7 +530,7 @@
-
C Standard
+
C standard
The version of the C language standard to use for IntelliSense.
@@ -564,7 +556,7 @@

-
diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index fa69b75979..740e6a1e3b 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -27,7 +27,7 @@ const elementId: { [key: string]: string } = { cStandard: "cStandard", cppStandard: "cppStandard", - // Advance settings + // Advanced settings windowsSdkVersion: "windowsSdkVersion", macFrameworkPath: "macFrameworkPath", compileCommands: "compileCommands", From 8ac66a449bd35facbed22646e51705331dce5b3a Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Wed, 5 Jun 2019 16:23:50 -0700 Subject: [PATCH 10/11] remove outline of button on click --- Extension/ui/settings.html | 4 ++++ Extension/ui/settings.ts | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index 2c870f7cd2..bc7ed0f450 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -124,6 +124,10 @@ line-height: 19px } + body:not(.tabbing) button:focus { + outline: none; + } + a { text-decoration: none } diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index 740e6a1e3b..2d7ec66b3b 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -59,6 +59,7 @@ class SettingsApp { constructor() { this.vsCodeApi = acquireVsCodeApi(); + window.addEventListener('keydown', this.handleTab.bind(this)); window.addEventListener('message', this.onMessageReceived.bind(this)); // Basic settings @@ -93,6 +94,20 @@ class SettingsApp { document.getElementById(elementId.advancedSection).style.display = "none"; } + private handleTab(e: any): void { + if (e.keyCode === 9) { + document.body.classList.add('tabbing'); + window.removeEventListener('keydown', this.handleTab); + window.addEventListener('mousedown', this.handleMouseDown.bind(this)); + } + } + + private handleMouseDown(): void { + document.body.classList.remove('tabbing'); + window.removeEventListener('mousedown', this.handleMouseDown); + window.addEventListener('keydown', this.handleTab.bind(this)); + } + private onShowAdvanced(): void { let isShown: boolean = (document.getElementById(elementId.advancedSection).style.display === "block"); document.getElementById(elementId.advancedSection).style.display = isShown ? "none" : "block"; From 6cb387f8257af071461688affbaf696c7e526831 Mon Sep 17 00:00:00 2001 From: Michelle Matias Date: Thu, 6 Jun 2019 13:56:46 -0700 Subject: [PATCH 11/11] save view state & code cleanup --- .../src/LanguageServer/configurations.ts | 2 +- Extension/src/LanguageServer/settingsPanel.ts | 2 +- Extension/ui/settings.html | 30 +++--- Extension/ui/settings.ts | 98 +++++++++++-------- 4 files changed, 73 insertions(+), 59 deletions(-) diff --git a/Extension/src/LanguageServer/configurations.ts b/Extension/src/LanguageServer/configurations.ts index 19657ec761..8ffb52a7f5 100644 --- a/Extension/src/LanguageServer/configurations.ts +++ b/Extension/src/LanguageServer/configurations.ts @@ -626,7 +626,7 @@ export class CppProperties { private ensureSettingsPanelInitlialized(): void { if (this.settingsPanel === undefined) { let settings: CppSettings = new CppSettings(this.rootUri); - this.settingsPanel = new SettingsPanel(); // set initial this.currentConfigurationIndex.Value + this.settingsPanel = new SettingsPanel(); this.settingsPanel.setKnownCompilers(this.knownCompilers, settings.preferredPathSeparator); this.settingsPanel.SettingsPanelActivated(() => this.onSettingsPanelActivated()); this.settingsPanel.ConfigValuesChanged(() => this.saveConfigurationUI()); diff --git a/Extension/src/LanguageServer/settingsPanel.ts b/Extension/src/LanguageServer/settingsPanel.ts index 9231d72ba7..761b27876a 100644 --- a/Extension/src/LanguageServer/settingsPanel.ts +++ b/Extension/src/LanguageServer/settingsPanel.ts @@ -323,7 +323,7 @@ export class SettingsPanel { break; case elementId.limitSymbolsToIncludedHeaders: this.initializeBrowseProperties(); - this.configValues.browse.limitSymbolsToIncludedHeaders = (message.value === "on" ? true : false); + this.configValues.browse.limitSymbolsToIncludedHeaders = message.value; break; case elementId.databaseFilename: this.initializeBrowseProperties(); diff --git a/Extension/ui/settings.html b/Extension/ui/settings.html index bc7ed0f450..ef0d39f95d 100644 --- a/Extension/ui/settings.html +++ b/Extension/ui/settings.html @@ -486,7 +486,7 @@
Specify a compiler path or select a detected compiler path from the drop-down list.
- +
@@ -500,7 +500,7 @@ Select a specific IntelliSense mode to override the ${default} mode.
- @@ -517,7 +517,7 @@
One include path per line.
- +
@@ -529,7 +529,7 @@
One definition per line.
- +
@@ -537,7 +537,7 @@
C standard
The version of the C language standard to use for IntelliSense.
- @@ -549,7 +549,7 @@
C++ standard
The version of the C++ language standard to use for IntelliSense.
- @@ -560,7 +560,7 @@

-
@@ -573,7 +573,7 @@ The ID of a VS Code extension that can provide IntelliSense configuration information for source files.
- +
@@ -583,7 +583,7 @@ Version of the Windows SDK include path to use on Windows, e.g. 10.0.17134.0.
- +
@@ -594,7 +594,7 @@
One path per line.
- +
@@ -605,7 +605,7 @@
One file per line.
- +
@@ -615,7 +615,7 @@ Full path to compile_commands.json file for the workspace.
- +
@@ -628,7 +628,7 @@
One browse path per line.
- +
@@ -648,14 +648,12 @@ it will be made relative to the workspace's default storage location.
- +
- - diff --git a/Extension/ui/settings.ts b/Extension/ui/settings.ts index 2d7ec66b3b..c1b8f2db51 100644 --- a/Extension/ui/settings.ts +++ b/Extension/ui/settings.ts @@ -59,62 +59,65 @@ class SettingsApp { constructor() { this.vsCodeApi = acquireVsCodeApi(); - window.addEventListener('keydown', this.handleTab.bind(this)); - window.addEventListener('message', this.onMessageReceived.bind(this)); + window.addEventListener("keydown", this.handleTab.bind(this)); + window.addEventListener("message", this.onMessageReceived.bind(this)); - // Basic settings + // Add event listeners to UI elements + this.addEventsToConfigNameChanges(); + this.addEventsToInputValues(); + document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); + + // Set view state of advanced settings and add event + const oldState: any = this.vsCodeApi.getState(); + const advancedShown: boolean = (oldState && oldState.advancedShown); + document.getElementById(elementId.advancedSection).style.display = advancedShown ? "block" : "none"; + document.getElementById(elementId.showAdvanced).classList.toggle(advancedShown ? "collapse" : "expand", true); + document.getElementById(elementId.showAdvanced).addEventListener("click", this.onShowAdvanced.bind(this)); + } + + private addEventsToInputValues(): void { + const elements: NodeListOf = document.getElementsByName("inputValue"); + elements.forEach(el => { + el.addEventListener("change", this.onChanged.bind(this, el.id)); + }); + + // Special case for checkbox element + document.getElementById(elementId.limitSymbolsToIncludedHeaders).addEventListener("change", this.onChangedCheckbox.bind(this, elementId.limitSymbolsToIncludedHeaders)); + } + + private addEventsToConfigNameChanges(): void { document.getElementById(elementId.configName).addEventListener("change", this.onConfigNameChanged.bind(this)); document.getElementById(elementId.configSelection).addEventListener("change", this.onConfigSelect.bind(this)); document.getElementById(elementId.addConfigBtn).addEventListener("click", this.onAddConfigBtn.bind(this)); document.getElementById(elementId.addConfigOk).addEventListener("click", this.OnAddConfigConfirm.bind(this, true)); document.getElementById(elementId.addConfigCancel).addEventListener("click", this.OnAddConfigConfirm.bind(this, false)); - - document.getElementById(elementId.compilerPath).addEventListener("change", this.onChanged.bind(this, elementId.compilerPath)); - document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this)); - document.getElementById(elementId.intelliSenseMode).addEventListener("change", this.onChanged.bind(this, elementId.intelliSenseMode)); - document.getElementById(elementId.includePath).addEventListener("change", this.onChanged.bind(this, elementId.includePath)); - document.getElementById(elementId.defines).addEventListener("change", this.onChanged.bind(this, elementId.defines)); - document.getElementById(elementId.cStandard).addEventListener("change", this.onChanged.bind(this, elementId.cStandard)); - document.getElementById(elementId.cppStandard).addEventListener("change", this.onChanged.bind(this, elementId.cppStandard)); - - // Advanced settings - document.getElementById(elementId.windowsSdkVersion).addEventListener("change", this.onChanged.bind(this, elementId.windowsSdkVersion)); - document.getElementById(elementId.macFrameworkPath).addEventListener("change", this.onChanged.bind(this, elementId.macFrameworkPath)); - document.getElementById(elementId.compileCommands).addEventListener("change", this.onChanged.bind(this, elementId.compileCommands)); - document.getElementById(elementId.configurationProvider).addEventListener("change", this.onChanged.bind(this, elementId.configurationProvider)); - document.getElementById(elementId.forcedInclude).addEventListener("change", this.onChanged.bind(this, elementId.forcedInclude)); - - // Browse properties - document.getElementById(elementId.browsePath).addEventListener("change", this.onChanged.bind(this, elementId.browsePath)); - document.getElementById(elementId.limitSymbolsToIncludedHeaders).addEventListener("change", this.onChanged.bind(this, elementId.limitSymbolsToIncludedHeaders)); - document.getElementById(elementId.databaseFilename).addEventListener("change", this.onChanged.bind(this, elementId.databaseFilename)); - - // Other - document.getElementById(elementId.showAdvanced).addEventListener("click", this.onShowAdvanced.bind(this)); - document.getElementById(elementId.advancedSection).style.display = "none"; } private handleTab(e: any): void { if (e.keyCode === 9) { - document.body.classList.add('tabbing'); - window.removeEventListener('keydown', this.handleTab); - window.addEventListener('mousedown', this.handleMouseDown.bind(this)); + document.body.classList.add("tabbing"); + window.removeEventListener("keydown", this.handleTab); + window.addEventListener("mousedown", this.handleMouseDown.bind(this)); } } private handleMouseDown(): void { - document.body.classList.remove('tabbing'); - window.removeEventListener('mousedown', this.handleMouseDown); - window.addEventListener('keydown', this.handleTab.bind(this)); + document.body.classList.remove("tabbing"); + window.removeEventListener("mousedown", this.handleMouseDown); + window.addEventListener("keydown", this.handleTab.bind(this)); } private onShowAdvanced(): void { - let isShown: boolean = (document.getElementById(elementId.advancedSection).style.display === "block"); + const isShown: boolean = (document.getElementById(elementId.advancedSection).style.display === "block"); document.getElementById(elementId.advancedSection).style.display = isShown ? "none" : "block"; - let element: HTMLElement = document.getElementById(elementId.showAdvanced); - element.classList.toggle('collapse'); - element.classList.toggle('expand'); + // Save view state + this.vsCodeApi.setState({ advancedShown: !isShown }); + + // Update chevron on button + const element: HTMLElement = document.getElementById(elementId.showAdvanced); + element.classList.toggle("collapse"); + element.classList.toggle("expand"); } private onAddConfigBtn(): void { @@ -185,17 +188,29 @@ class SettingsApp { command: "knownCompilerSelect" }); } + private onChangedCheckbox(id: string): void { + if (this.updating) { + return; + } + + const el: HTMLInputElement = document.getElementById(id); + this.vsCodeApi.postMessage({ + command: "change", + key: id, + value: el.checked + }); + } private onChanged(id: string): void { if (this.updating) { return; } - const x: HTMLInputElement = document.getElementById(id); + const el: HTMLInputElement = document.getElementById(id); this.vsCodeApi.postMessage({ command: "change", key: id, - value: x.value + value: el.value }); } @@ -234,7 +249,7 @@ class SettingsApp { (document.getElementById(elementId.cStandard)).value = config.cStandard; (document.getElementById(elementId.cppStandard)).value = config.cppStandard; - // Advance settings + // Advanced settings (document.getElementById(elementId.windowsSdkVersion)).value = config.windowsSdkVersion ? config.windowsSdkVersion : ""; (document.getElementById(elementId.macFrameworkPath)).value = @@ -249,7 +264,8 @@ class SettingsApp { if (config.browse) { (document.getElementById(elementId.browsePath)).value = (config.browse.path && config.browse.path.length > 0) ? config.browse.path.join("\n") : ""; - (document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked = config.browse.limitSymbolsToIncludedHeaders ? true : false; + (document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked = + (config.browse.limitSymbolsToIncludedHeaders && config.browse.limitSymbolsToIncludedHeaders); (document.getElementById(elementId.databaseFilename)).value = config.browse.databaseFilename ? config.browse.databaseFilename : ""; } else { (document.getElementById(elementId.browsePath)).value = "";