Compare commits

..
66 Commits
Author SHA1 Message Date
Sean McManus fa4d7b22c1 Update package.json version. (#3948) 2019-07-19 12:33:53 -07:00
Colen Garoutte-Carson 3cb7f7e61f Merge pull request #3946 from microsoft/coleng/CherryPickAgain
Cherry pick into release for 0.24.1
2019-07-18 18:54:51 -07:00
Colen Garoutte-Carson 779f2ce2b5 Fix issue with didClose received after didOpen (#3844) 2019-07-18 18:42:51 -07:00
Colen Garoutte-Carson 0c4c83e5bd Improve scope names used by Enhanced Colorization (#3896) 2019-07-18 18:42:46 -07:00
Colen Garoutte-Carson a369ede8d9 Update changelog for 0.24.1 release (#3945) 2019-07-18 18:42:40 -07:00
Colen Garoutte-Carson 36ce8f885f Revert "cherry pick fixes for 0.24.1 (#3943)"
This reverts commit 347794b0c7.
2019-07-18 18:37:18 -07:00
Colen Garoutte-Carson 347794b0c7 cherry pick fixes for 0.24.1 (#3943) 2019-07-18 17:28:00 -07:00
Sean McManus 3ed087134c Merge pull request #3869 from microsoft/seanmcm/0_24_0_release
Seanmcm/0 24 0 release
2019-07-02 19:04:05 -07:00
Sean McManus 902355e021 Merge branch 'release' into seanmcm/0_24_0_release 2019-07-02 18:36:53 -07:00
Sean McManus 32e98912df Change version 2019-07-02 18:33:53 -07:00
Colen Garoutte-Carson 6bc49d595e Update release notes and changelog for June 2019 release (#3868)
* Update release notes and changelog for June 2019 release
2019-07-02 18:29:19 -07:00
Pierson Lee 6b3c0f1b10 Update default for externalConsole to false (#3828) 2019-07-02 17:12:23 -07:00
Sean McManus 35501431f8 Add the binaryVersion to Mac crash telemetry. (#3865) 2019-07-02 11:43:56 -07:00
Colen Garoutte-Carson 27a3c9958d Add output of current configuration to diagnostics command (#3866) 2019-07-01 19:38:25 -07:00
Sean McManus 5b3d4ebf44 Update dev dependencies and ThirdPartyNotices.txt (#3863)
* Update dev dependencies.
* Update ThirdPartyNotices.txt
2019-07-01 15:50:40 -07:00
Andrew Wang cfc064efcd Support resolving ${env:...} in sourceFileMap (#3857)
* Support resolving ${env:...} in sourceFileMap

This PR addresses ${env:...} variables in sourceFileMap keys and values.
2019-07-01 11:25:51 -07:00
Colen Garoutte-Carson 4f7a64a1a2 Add support parent scope syntax in theme loader for enhancedColorization (#3855) 2019-07-01 11:05:32 -07:00
Sean McManus c84cb36004 Update changelog for 0.24.0-insiders3. (#3850) 2019-06-27 19:10:25 -07:00
Andrew Wang 0502351002 Update envFile variable substitution (#3848)
* Update envFile variable substitution

In launch.json, the `envFile` configuration can substitute
${workspaceFolder}, ${workspaceRoot} and ${env::???}.

* Fix lint issues
2019-06-27 17:52:58 -07:00
Andrew Wang 5de420ee70 Decrease F5 workflow time w/ VSCode (#3843)
* Decrease F5 workflow time w/ VSCode

webpack is being called twice. Once with --mode production and then
rewritten with --mode development. Fixing tasks and launch.
2019-06-27 15:57:49 -07:00
Bob Brown 6a73275924 This message wasn't being sent by the language server (#3840) 2019-06-27 12:29:40 -07:00
Michelle Matias d12591062e validate advanced settings input (#3838) 2019-06-27 11:45:35 -07:00
Colen Garoutte-Carson 3926110b33 Update colorization.md to remove (syntactic) identifier (#3832) 2019-06-25 18:16:38 -07:00
Bob Brown f5975e6534 update fwlink for abtesting (#3830) 2019-06-25 13:19:07 -07:00
Pierson Lee b55e2c7ac5 Add useful links at the top of the README.md in the extension (#3808)
* Add useful links at the top of the README.md in the extension

* add liveshare badge
2019-06-25 10:52:38 -07:00
Colen Garoutte-Carson 73fda38d71 Enable enhanced colorization by default (#3824)
* Enable enhanced colorization by default
2019-06-25 10:21:11 -07:00
TheGreatRambler 9211292b60 Update FAQ.md (#3812) 2019-06-25 10:19:03 -07:00
Colen Garoutte-Carson f63a8da581 Remove syntactic colorization in favor of text mate colorization (#3821) 2019-06-24 17:42:10 -07:00
Colen Garoutte-Carson fd314b1b04 Handle comma-delimited scopes in JSON themes (#3814) 2019-06-21 16:54:48 -07:00
Sean McManus ea52c76595 Change to use machine scopes for clang_format_path.. (#3810)
* Change to use machine scopes for clang_format_path.
2019-06-21 11:49:23 -07:00
Colen Garoutte-Carson 7659e2826b Remove incorrect editor background setting (#3806) 2019-06-20 11:34:42 -07:00
Michelle Matias 8e898151f6 resolve cache path (#3807) 2019-06-20 11:20:24 -07:00
Colen Garoutte-Carson b2b0ad37af Avoid applying edits to cached colorization tokens until needed (#3793) 2019-06-17 18:12:28 -07:00
Bob Brown cee6ebe1d9 Disabling enhanced colorization for now. (#3785) 2019-06-17 17:31:40 -07:00
Colen Garoutte-Carson 566e657fad Make handleSquiggles no longer dependent on special escaping in parsePropertiesFile (#3778) 2019-06-17 10:38:59 -07:00
Colen Garoutte-Carson db1f631396 Fix colorization issue where only 1 of multiple get colorized (#3777) 2019-06-14 13:29:06 -07:00
Colen Garoutte-Carson 426c08293d Attempt to address colorization issue with flickering on Mac (#3775) 2019-06-14 13:00:06 -07:00
Colen Garoutte-Carson 631a4452d0 Enable enhancedColorization by default. Fix refresh race in colorization.ts (#3770) 2019-06-13 16:46:46 -07:00
Michelle Matias 9b29698b0e fix cl.exe check and other UI fixes (#3769) 2019-06-13 15:39:18 -07:00
Colen Garoutte-Carson b5c94e9e1f Address issue with AB default not applied. Fix issue with non file URIs (#3767) 2019-06-13 14:18:48 -07:00
Sean McManus 384cd35d6b Fix configuration squiggles not appearing for multiple occurrences of the same error. (#3766) 2019-06-13 13:55:55 -07:00
Sean McManus 2d4df9149f Update changelog for Insiders. (#3763)
* Update changelog for Insiders.
2019-06-12 19:44:57 -07:00
Michelle Matias d3c2ccbb93 return empty string if path is not set (#3761) 2019-06-12 17:15:56 -07:00
Colen Garoutte-Carson c637221b92 Update colorization support to only return tokens for currently visible ranges (#3738) 2019-06-12 16:28:40 -07:00
Michelle Matias 814f01b263 Change cache path default (#3747)
* change cache path default

* update check for falsy

* change default path name and location

* Update cache path description in json
2019-06-12 15:20:41 -07:00
Andrew Wang b763aa57d3 Fix windows remote attach experience (#3757)
* Check host machine for specific quotes for command

Attach to process is not working on Windows OS due to the single quote
then double inner quote. However, this is required for linux because if
you do not, it will evaluate the variables within the double quotes.
2019-06-12 15:06:02 -07:00
Michelle Matias 54b1e69975 Update IntelliSense mode and compiler compatibility validation (#3752)
* get compiler name

* get name for case when there are no args
2019-06-12 14:03:14 -07:00
Andrew Wang dacfe08033 Enable 'envFile' for cppdbg (#3723)
* Enable 'envFile' for cppdbg

This PR allows the cppdbg configuration to set environment variables
via a envFile.

Example envFile:
ENVIRONMENT_VAR_1=Hello
ENVIRONMENT_VAR_2=15
2019-06-10 17:54:00 -07:00
Michelle Matias f5aa7dc33e change text of include path. code clean up. (#3743) 2019-06-07 16:27:34 -07:00
Michelle Matias 90c6e9876a Configuration UI - V2 (#3732)
* edit config name

* button active style

* refactor settings.ts

* clean up configurations.ts

* advanced settings

* telemetry compilerPath & listen to forecedInclude

* fix lint

* fix spelling

* spelling & fix contrast color for buttons

* remove outline of button on click

* save view state & code cleanup
2019-06-07 09:46:43 -07:00
Bob Brown 9fa950db6a Add a command to rescan the workspace (#3658) 2019-06-05 15:12:29 -07:00
Bob Brown 8ea627e085 Telemetry not being logged for intellisense mode mismatch (#3726) 2019-06-04 11:39:47 -07:00
Andrew Wang 536d38e3bf Remove minify from webpack compile (#3724)
This will cause the code to still be webpacked but will not minify it.
2019-06-03 13:52:11 -07:00
Sean McManus c10c626869 Change multi-root storagePath to use the index instead of name. (#3715)
* Change multi-root storagePath to use the index as a subfolder when the name is a duplicate.
2019-05-31 14:47:45 -07:00
Sean McManus 24d37bc233 Update TPN from plist dependency. (#3719) 2019-05-31 13:35:06 -07:00
Sean McManus 158719cf46 Fixes to gcc problem matcher. (#3714)
* Fixes to gcc problem matcher.
2019-05-30 14:41:21 -07:00
Colen Garoutte-Carson b6327ed6c3 Add colorization support to cpptools (#3651) 2019-05-30 13:42:18 -07:00
Michelle Matias c60a2c6752 Add list of detected compiler paths to IntelliSense config UI (#3708)
* editable select control for compilerPath field

* set compiler path values

* update comments and width

* normalize path, update description
2019-05-30 11:27:49 -07:00
Michelle Matias 1f7c27d7f9 fix elementId.configName (#3692) 2019-05-24 17:25:50 -07:00
Karsten Thoms 1d82458a3a Fix typo in intelliSenseMode description (#3682) 2019-05-23 15:54:53 -07:00
Michelle Matias 25d122c3f7 Add telemetry to configuration UI (#3661)
* add telemetry to config ui

* cache telemetry and log when settingsPanel object is disposed

* fix linting
2019-05-22 14:41:39 -07:00
Andreea Isac 627acc535e Refresh IntelliSense time (#3680)
* Flame on timing

* Fixed linter errors

* Log IntelliSense refresh time information for debug logging level.

* Rephrasing log message

* Print the message in the output window instead of the console.
2019-05-22 14:03:04 -07:00
Sean McManus 515d858b4d Fix ${workspaceFolderBasename} resolving to "untitled", and add ${workspaceStorage} (#3643)
* Fix ${workspaceFolderBasename} resolving to "untitled".
* Enable ${workspaceStorage} in intelliSenseCachePath.
2019-05-21 15:26:05 -07:00
Bob Brown 7ec15af47c Clarify data collection policy #3299 (#3660) 2019-05-17 11:22:14 -07:00
Bob Brown cac58e9f88 Fix unit tests (#3659) 2019-05-16 11:46:29 -07:00
Sean McManus 0c28725628 Update versions. (#3641)
* Update versions.
2019-05-14 18:03:16 -07:00
37 changed files with 4304 additions and 3253 deletions
+5
View File
@@ -1,5 +1,6 @@
# Frequently asked questions
* [Why are my files corrupted on format?](#why-are-my-files-corrupted-on-format)
* [How do I get IntelliSense to work correctly?](#how-do-i-get-intellisense-to-work-correctly)
* [Why do I see red squiggles under Standard Library types?](#why-do-i-see-red-squiggles-under-standard-library-types)
* [How do I get the new IntelliSense to work with MinGW on Windows?](#how-do-i-get-the-new-intellisense-to-work-with-mingw-on-windows)
@@ -7,6 +8,10 @@
* [What is the difference between `"includePath"` and `"browse.path"` in **c_cpp_properties.json**?](#what-is-the-difference-between-includepath-and-browsepath-in-c_cpp_propertiesjson)
* [How do I re-create the IntelliSense database?](#how-do-i-re-create-the-intellisense-database)
## Why are my files corrupted on format?
This is likely due to the fact that you either have a multi-root workspace where one folder is a child of the other, or you are using symlinks to open your file. Reduce the folders in the workspace to one and remove the symlink. This should fix your problem.
## How do I get IntelliSense to work correctly?
There are two IntelliSense engines present in the extension: the "fuzzy" engine (or Tag Parser), and the new "Default" engine. If you are using version 0.11.0 or higher of the cpptools extension, then you can preview our new IntelliSense engine which has more accurate auto-complete suggestions and tooltips. To use the new engine, you need to ensure that `"C_Cpp.intelliSenseEngine"` is set to `"Default"` in your settings. Since the engine is still in preview it is not on by default for everyone yet.
@@ -0,0 +1,511 @@
# VS Code C/C++ Extension - Enhanced Colorization
The VS Code C/C++ extension now supports semantic colorization, when IntelliSense is enabled. Enhanced colorization can be enabled using the enhancedColorization setting:
```
"C_Cpp.enhancedColorization": "Enabled"
```
# Theming
Colors can be associated using the existing support for theming and color customization in VS Code. Documentation on Theming in VS Code can be found [here](https://code.visualstudio.com/docs/getstarted/themes)
Colors are associated with [TextMate scopes](https://macromates.com/manual/en/language_grammars#naming_conventions).
# IntelliSense Tokens and Scopes
| Token | Scope |
| ------------- |:-------------:|
| Class Template | entity.name.type.class.templated |
| Enumerator | variable.other.enummember |
| Event (C++/CLI) | variable.other.event |
| Function | entity.name.function |
| Function Template | entity.name.function.templated |
| Generic Type (C++/CLI) | entity.name.type.class.generic |
| Global Variable | variable.other.global |
| Label | entity.name.label |
| Local Variable | variable.other.local |
| Macro | entity.name.function.preprocessor |
| Member Field | variable.other.property |
| Member Function | entity.name.function.member |
| Namespace | entity.name.namespace |
| New / Delete | keyword.operator.new |
| Operator Overload Function | entity.name.function.operator |
| Operator Overload Member | entity.name.function.operator.member |
| Parameter | variable.parameter |
| Property (C++/CLI) | variable.other.property.cli |
| Reference Type (C++/CLI) | entity.name.type.class.reference |
| Static Member Field | variable.other.property.static |
| Static Member Function | entity.name.function.member.static |
| Type | entity.name.type.class |
| User-Defined Literal - Number | entity.name.operator.custom-literal.number |
| User-Defined Literal - Raw | entity.name.operator.custom-literal |
| User-Defined Literal - String | entity.name.operator.custom-literal.string |
| Value Type (C++/CLI) | entity.name.type.class.value |
Many of the tokens recognized by IntelliSense do not directly map to existing scopes in the VS Code's default C/C++ TextMate grammar, so are likely not colored by existing VS Code themes.
# Customizing Colors in Settings
Colors can also be overridden globally, in settings:
```
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "entity.name.type.class",
"settings": {
"foreground": "#FF0000",
"fontStyle": "italic bold underline"
}
}
]
}
```
Or, overridden on a per-theme basis:
```
"editor.tokenColorCustomizations": {
"[Visual Studio Dark]": {
"textMateRules": [
{
"scope": "entity.name.type.class",
"settings": {
"foreground": "#FF0000",
"fontStyle": "italic bold underline"
}
}
]
}
```
Use the following to augment the Visual Studio Dark theme to match what Visual Studio would display for C++ files.
```
"editor.tokenColorCustomizations": {
"[Visual Studio Dark]": {
"textMateRules": [
{
"scope": "comment",
"settings": {
"foreground": "#57A64A"
}
},
{
"scope": "keyword.control",
"settings": {
"foreground": "#569CD6"
}
},
{
"scope": "keyword.control.directive",
"settings": {
"foreground": "#9B9B9B"
}
},
{
"scope": "keyword.operator",
"settings": {
"foreground": "#B4B4B4"
}
},
{
"scope": "variable",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "constant.numeric",
"settings": {
"foreground": "#B5CEA8"
}
},
{
"scope": "string.quoted",
"settings": {
"foreground": "#D69D85"
}
},
{
"scope": "comment.xml.doc",
"settings": {
"foreground": "#57A64A"
}
},
{
"scope": "comment.xml.doc.tag",
"settings": {
"foreground": "#57A64A"
}
},
{
"scope": "entity.name.function.preprocessor",
"settings": {
"foreground": "#BD63C5"
}
},
{
"scope": "variable.other.enummember",
"settings": {
"foreground": "#B8D7A3"
}
},
{
"scope": "variable.other.global",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "variable.other.local",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "variable.parameter",
"settings": {
"foreground": "#7F7F7F"
}
},
{
"scope": "entity.name.type.class",
"settings": {
"foreground": "#4EC9B0"
}
},
{
"scope": "entity.name.type.class.reference",
"settings": {
"foreground": "#4EC9B0"
}
},
{
"scope": "entity.name.type.class.value",
"settings": {
"foreground": "#4EC9B0"
}
},
{
"scope": "entity.name.function",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "entity.name.function.member",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "variable.other.property",
"settings": {
"foreground": "#DADADA"
}
},
{
"scope": "entity.name.function.member.static",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "variable.other.property.static",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "variable.other.event",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "entity.name.type.class.templated",
"settings": {
"foreground": "#4EC9B0"
}
},
{
"scope": "entity.name.type.class.generic",
"settings": {
"foreground": "#4EC9B0"
}
},
{
"scope": "entity.name.function.templated",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "entity.name.type.namespace",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "entity.name.label",
"settings": {
"foreground": "#C8C8C8"
}
},
{
"scope": "entity.name.operator.custom-literal",
"settings": {
"foreground": "#DADADA"
}
},
{
"scope": "entity.name.operator.custom-literal.string",
"settings": {
"foreground": "#D69D85"
}
},
{
"scope": "entity.name.operator.custom-literal.number",
"settings": {
"foreground": "#B5CEA8"
}
},
{
"scope": "entity.name.function.operator",
"settings": {
"foreground": "#B4B4B4"
}
},
{
"scope": "keyword.operator.member",
"settings": {
"foreground": "#B4B4B4"
}
},
{
"scope": "keyword.operator.new",
"settings": {
"foreground": "#569CD6"
}
},
]
}
}
```
Use the following to augment the Visual Studio Light theme to match what Visual Studio would display for C++ files.
````
"editor.tokenColorCustomizations": {
"[Visual Studio Light]": {
"textMateRules": [
{
"scope": "comment",
"settings": {
"foreground": "#008000"
}
},
{
"scope": "keyword.control",
"settings": {
"foreground": "#0000FF"
}
},
{
"scope": "keyword.control.directive",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "keyword.operator",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "constant.numeric",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "string.quoted",
"settings": {
"foreground": "#A31515"
}
},
{
"scope": "comment.xml.doc",
"settings": {
"foreground": "#006400"
}
},
{
"scope": "comment.xml.doc.tag",
"settings": {
"foreground": "#A9A9A9"
}
},
{
"scope": "entity.name.function.preprocessor",
"settings": {
"foreground": "#6F0026"
}
},
{
"scope": "variable.other.enummember",
"settings": {
"foreground": "#2F4F4F"
}
},
{
"scope": "variable.other.global",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable.other.local",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable.parameter",
"settings": {
"foreground": "#808080"
}
},
{
"scope": "entity.name.type.class",
"settings": {
"foreground": "#2B91AF"
}
},
{
"scope": "entity.name.type.class.reference",
"settings": {
"foreground": "#2B91AF"
}
},
{
"scope": "entity.name.type.class.value",
"settings": {
"foreground": "#2B91AF"
}
},
{
"scope": "entity.name.function",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.function.member",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable.other.property",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.function.member.static",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable.other.property.static",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "variable.other.event",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.type.class.templated",
"settings": {
"foreground": "#2B91AF"
}
},
{
"scope": "entity.name.type.class.generic",
"settings": {
"foreground": "#2B91AF"
}
},
{
"scope": "entity.name.function.templated",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.type.namespace",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.label",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.operator.custom-literal",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.operator.custom-literal.string",
"settings": {
"foreground": "#A31515"
}
},
{
"scope": "entity.name.operator.custom-literal.number",
"settings": {
"foreground": "#000000"
}
},
{
"scope": "entity.name.function.operator",
"settings": {
"foreground": "#008080"
}
},
{
"scope": "keyword.operator.member",
"settings": {
"foreground": "#008080"
}
},
{
"scope": "keyword.operator.new",
"settings": {
"foreground": "#0000FF"
}
},
]
}
}
````
-3
View File
@@ -64,9 +64,6 @@
"run",
"compileDev"
],
"dependsOn": [
"TypeScript Compile"
],
"problemMatcher": "$tsc-watch"
},
{
+48
View File
@@ -1,5 +1,53 @@
# C/C++ for Visual Studio Code Change Log
## Version 0.24.1: July 22, 2019
### Bug Fixes
* Fix an issue with the Outline not being populated when a file is opened. [#3877](https://github.com/microsoft/vscode-cpptools/issues/3877)
* Update scopes used by semantic colorization. [PR# 3896](https://github.com/microsoft/vscode-cpptools/pull/3896)
## Version 0.24.0: July 3, 2019
### New Features
* Semantic colorization [Documentation](https://github.com/microsoft/vscode-cpptools/blob/master/Documentation/LanguageServer/colorization.md) [#230](https://github.com/microsoft/vscode-cpptools/issues/230)
* Add `Rescan Workspace` command. [microsoft/vscode-cpptools-api#11](https://github.com/microsoft/vscode-cpptools-api/issues/11)
### Enhancements
* Configuration UI editor improvements:
* Add list of detected compiler paths. [PR #3708](https://github.com/microsoft/vscode-cpptools/pull/3708)
* Enable selecting/editing of other configurations and add "Advanced Settings" section. [PR #3732](https://github.com/microsoft/vscode-cpptools/pull/3732)
* Enable `envFile` for `cppdbg`. [PR #3723](https://github.com/microsoft/vscode-cpptools/pull/3723)
* Change the default path value of `C_Cpp.intelliSenseCachePath`. [#3347](https://github.com/microsoft/vscode-cpptools/issues/3347) [#3664](https://github.com/microsoft/vscode-cpptools/issues/3664)
* Change `C_Cpp.clang_format_path` to `machine` scope. [#3774](https://github.com/microsoft/vscode-cpptools/issues/3774)
* Add validation to the advanced configuration UI settings. [PR #3838](https://github.com/microsoft/vscode-cpptools/pull/3838)
* Add `Current Configuration` to `C/C++: Log Diagnostics`. [PR #3866](https://github.com/microsoft/vscode-cpptools/pull/3866)
### Bug Fixes
* Fix for gdb `follow-fork-mode` `child` not working. [#2738](https://github.com/microsoft/vscode-cpptools/issues/2738)
* Fix IntelliSense process crash on hover with certain arrays. [#3081](https://github.com/Microsoft/vscode-cpptools/issues/3081)
* Fix IntelliSense-based `Go to Definition` for goto labels. [#3111](https://github.com/microsoft/vscode-cpptools/issues/3111)
* Fix IntelliSense behaving incorrectly when files are opened with different casing on Windows. [#3229](https://github.com/microsoft/vscode-cpptools/issues/3229)
* Fix user defined literals crashing IntelliSense in clang/gcc mode. [#3481](https://github.com/microsoft/vscode-cpptools/issues/3481)
* Improve `sourceFileMap` to be more dynamic. [#3504](https://github.com/microsoft/vscode-cpptools/issues/3504)
* Fix IntelliSense-based hover document comments being shown for invalid declarations not used by the current translation unit. [#3596](https://github.com/microsoft/vscode-cpptools/issues/3596)
* Fix `Go to Definition` when is `void` missing in the parameter list of a function definition a .c file. [#3609](https://github.com/microsoft/vscode-cpptools/issues/3609)
* Fix configuration validation of compiler path and IntelliSense mode compatibility for `clang-cl.exe` compiler. [#3637](https://github.com/microsoft/vscode-cpptools/issues/3637)
* Fix resolving `${workspaceFolderBasename}` and add `${workspaceStorage}`. [#3642](https://github.com/microsoft/vscode-cpptools/issues/3642)
* Fix IntelliSense-based `Go to Definition` performance issue due to extra database iteration. [#3655](https://github.com/microsoft/vscode-cpptools/issues/3655)
* Fix `SourceRequest` causing debugging to stop with `NotImplementedException`. [#3662](https://github.com/microsoft/vscode-cpptools/issues/3662)
* Fix typo in `intelliSenseMode` description.
* Karsten Thoms (@kthoms) [PR #3682](https://github.com/microsoft/vscode-cpptools/pull/3682)
* Fix invalid warning with typedef enums in .c files. [#3685](https://github.com/microsoft/vscode-cpptools/issues/3685)
* Fix incorrect `keyword` completion occurring for pragma `#keyword`. [#3690](https://github.com/microsoft/vscode-cpptools/issues/3690)
* Fix problem matcher to show fatal errors from GCC [#3712](https://github.com/microsoft/vscode-cpptools/issues/3712)
* Fix multi-root folders with the same name sharing the same browse database. [PR #3715](https://github.com/microsoft/vscode-cpptools/pull/3715)
* Fix `remoteProcessPicker` on Windows. [#3758](https://github.com/microsoft/vscode-cpptools/issues/3758)
* Fix crash when tag parsing Objective-C code. [#3776](https://github.com/microsoft/vscode-cpptools/issues/3776)
* Fix duplicate slashes getting added to `c_cpp_properties.json`. [PR #3778](https://github.com/microsoft/vscode-cpptools/pull/3778)
* Fix `envFile` variable substitution. [#3836](https://github.com/microsoft/vscode-cpptools/issues/3836)
* Fix missing headers popup. [PR #3840](https://github.com/microsoft/vscode-cpptools/pull/3840)
* Fix multiple anonymous unions not showing correctly in Locals while debugging. [MIEngine#820](https://github.com/microsoft/MIEngine/issues/820)
* Fix pause not working when using `DebugServer`/`MIDebuggerServerAddress` on Linux and macOS. [MIEngine#844](https://github.com/microsoft/MIEngine/issues/844)
* Improvements to CPU and memory usage when editing.
## Version 0.23.1: May 13, 2019
### Bug Fixes
* Fix `launch.json` creation when `intelliSenseEngine` is `"Disabled"`. [#3583](https://github.com/microsoft/vscode-cpptools/issues/3583)
+5
View File
@@ -1,4 +1,9 @@
# C/C++ for Visual Studio Code
### [Repository](https://github.com/microsoft/vscode-cpptools)  |  [Issues](https://github.com/microsoft/vscode-cpptools/issues)  |  [Documentation](https://github.com/microsoft/vscode-cpptools/tree/master/Documentation)  |  [Code Samples](https://github.com/microsoft/vscode-cpptools/tree/master/Code%20Samples)  |  [Offline Installers](https://github.com/microsoft/vscode-cpptools/releases)
[![Badge](https://aka.ms/vsls-badge)](https://aka.ms/vsls)
This preview release of the extension adds language support for C/C++ to Visual Studio Code including:
* Language service
* Code Formatting (clang-format)
+7 -13
View File
@@ -205,20 +205,14 @@
<tr>
<td>
<div>
<h2 class="caption">May 2019 Update</h2>
<div>Thank you for installing the C/C++ extension! We're excited to announce the following features in the May update:<br/>
<h3 style="font-weight: 600">IntelliSense configuration settings editor UI</h3>
The extension now has a UI editor to edit basic IntelliSense configuration settings defined in the underlying <code>c_cpp_properties.json</code> file.<br/>
<br/>
You can get to the IntelliSense configuration settings editor UI through the command palette (Ctrl+Shift+P) and running the <code>C/C++: Edit configurations (UI)</code> command.
The <code>c_cpp_properties.json</code> file can be opened by running the <code>C/C++: Edit configurations (JSON)</code> command.
<br/>
<br/>
<em style="font-weight: 600">Please Note:</em> When configuring IntelliSense for the first time, VS Code will open the UI editor or JSON file based on your <code>workbench.settings.editor</code> setting.
If <code>workbench.settings.editor</code> is set to “ui”, then the UI editor will open by default, and if it is set to “json”, then the JSON file will open by default. You can view that setting under VS Code preferences → settings → “Workbench Settings Editor”.<br/>
<h2 class="caption">June 2019 Update</h2>
<div>Thank you for installing the C/C++ extension! We're excited to announce the following feature in the June update:<br/>
<h3 style="font-weight: 600">Enhanced Colorization</h3>
The extension now supports semantic colorization.
Enhanced colorization adds colors for tokens identified semantically by IntelliSense.
Colors can be configured by themes or customized in settings.
More information can be found <a href="https://github.com/microsoft/vscode-cpptools/blob/master/Documentation/LanguageServer/colorization.md">here</a>.
<h3 style="font-weight: 600">Log diagnostics command</h3>
We added the command <code>C/C++: Log Diagnostics</code> to help diagnose IntelliSense issues. Running the command shows IntelliSense information of the current translation unit that is associated with the active file.<br/>
<br/>
<br/>
Additional features and bug fixes are detailed in the <a href="https://github.com/Microsoft/vscode-cpptools/releases">full release notes</a>.</div>
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -71,7 +71,7 @@
}
},
"intelliSenseMode": {
"description": "If set, it overrides the default mode used by the IntelliSense engine. Windows defaults to msvc-x64, Linux defaults to gcc-x64, and Mac default to clang-x64.",
"description": "If set, it overrides the default mode used by the IntelliSense engine. Windows defaults to msvc-x64, Linux defaults to gcc-x64, and Mac defaults to clang-x64.",
"type": "string",
"enum": [
"msvc-x64",
+2 -1
View File
@@ -2,5 +2,6 @@
"intelliSenseEngine_default_percentage": 100,
"defaultIntelliSenseEngine": 100,
"recursiveIncludes": 100,
"gotoDefIntelliSense": 100
"gotoDefIntelliSense": 100,
"enhancedColorization": 100
}
+4 -5
View File
@@ -29,15 +29,14 @@ jobs:
displayName: 'Run Linter'
workingDirectory: '$(Build.SourcesDirectory)\Extension'
- script: 'npm run unitTests'
displayName: 'Run unit tests'
workingDirectory: '$(Build.SourcesDirectory)\Extension'
continueOnError: true
- script: npm run pretest
displayName: "Compile Test Sources"
workingDirectory: '$(Build.SourcesDirectory)\Extension'
- script: 'npm run unitTests'
displayName: 'Run unit tests'
workingDirectory: '$(Build.SourcesDirectory)\Extension'
- script: 'node node_modules/vscode/bin/test'
displayName: 'Run languageServer integration tests'
workingDirectory: '$(Build.SourcesDirectory)\Extension'
+4 -5
View File
@@ -28,11 +28,6 @@ jobs:
displayName: 'Run Linter'
workingDirectory: '$(Build.SourcesDirectory)/Extension'
- script: 'npm run unitTests'
displayName: 'Run unit tests'
workingDirectory: '$(Build.SourcesDirectory)/Extension'
continueOnError: true
- script: |
set -e
/usr/bin/Xvfb :10 -ac >> /tmp/Xvfb.out 2>&1 &
@@ -43,6 +38,10 @@ jobs:
displayName: "Compile Test Sources"
workingDirectory: '$(Build.SourcesDirectory)/Extension'
- script: 'npm run unitTests'
displayName: 'Run unit tests'
workingDirectory: '$(Build.SourcesDirectory)/Extension'
- script: 'node node_modules/vscode/bin/test'
displayName: 'Run languageServer integration tests'
workingDirectory: '$(Build.SourcesDirectory)/Extension'
+11
View File
@@ -0,0 +1,11 @@
{
"name": "C",
"scopeName": "source.c",
"version": "0",
"information_for_contributors": [
],
"patterns": [
],
"repository": {
}
}
+11
View File
@@ -0,0 +1,11 @@
{
"name": "C++",
"scopeName": "source.cpp",
"version": "0",
"information_for_contributors": [
],
"patterns": [
],
"repository": {
}
}
+275 -392
View File
File diff suppressed because it is too large Load Diff
+47 -24
View File
@@ -2,7 +2,7 @@
"name": "cpptools",
"displayName": "C/C++",
"description": "C/C++ IntelliSense, debugging, and code browsing.",
"version": "0.23.1",
"version": "0.24.1",
"publisher": "ms-vscode",
"preview": true,
"icon": "LanguageCCPP_color_128x.png",
@@ -46,13 +46,14 @@
"problemMatchers": [
{
"name": "gcc",
"source": "gcc",
"owner": "cpptools",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
@@ -72,7 +73,7 @@
],
"default": null,
"description": "The full path of the clang-format executable.",
"scope": "resource"
"scope": "machine"
},
"C_Cpp.clang_format_style": {
"type": "string",
@@ -145,7 +146,7 @@
"C_Cpp.dimInactiveRegions": {
"type": "boolean",
"default": true,
"description": "Controls whether inactive preprocessor blocks are colored differently than active code. This setting is ignored by the Tag Parser engine.",
"description": "Controls whether inactive preprocessor blocks are colored differently than active code. This setting has no effect if IntelliSense is disabled or if using the Default High Contrast theme.",
"scope": "resource"
},
"C_Cpp.inactiveRegionOpacity": {
@@ -292,8 +293,8 @@
},
"C_Cpp.intelliSenseCachePath": {
"type": "string",
"default": "${workspaceFolder}/.vscode",
"description": "Defines the folder path for cached precompiled headers used by IntelliSense. The default path \"${workspaceFolder}/.vscode\" will be used if a specified path is invalid.",
"default": null,
"description": "Defines the folder path for cached precompiled headers used by IntelliSense. The default cache path is \"%LocalAppData%/Microsoft/vscode-cpptools\" on Windows and \"~/.vscode-cpptools\" on Linux and Mac. The default path will be used if no path is specified or if a specified path is invalid.",
"scope": "resource"
},
"C_Cpp.intelliSenseCacheSize": {
@@ -495,6 +496,16 @@
"default": true,
"description": "If true, snippets are provided by the language server.",
"scope": "resource"
},
"C_Cpp.enhancedColorization": {
"type": "string",
"enum": [
"Enabled",
"Disabled"
],
"default": "Enabled",
"description": "If enabled, code is colorized based on IntelliSense. This setting has no effect if IntelliSense is disabled or if using the Default High Contrast theme.",
"scope": "resource"
}
}
},
@@ -598,6 +609,11 @@
"command": "C_Cpp.LogDiagnostics",
"title": "%c_cpp.command.logDiagnostics.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.RescanWorkspace",
"title": "%c_cpp.command.rescanWorkspace.title%",
"category": "C/C++"
}
],
"keybindings": [
@@ -781,6 +797,11 @@
},
"default": []
},
"envFile": {
"type": "string",
"description": "Absolute path to a file containing environment variable definitions. This file has key value pairs separated by an equals sign per line. E.g. KEY=VALUE",
"default": "${workspaceFolder}/.env"
},
"additionalSOLibSearchPath": {
"type": "string",
"description": "Semicolon separated list of directories to use to search for .so files. Example: \"c:\\dir1;c:\\dir2\".",
@@ -1203,7 +1224,7 @@
},
"envFile": {
"type": "string",
"description": "Absolute path to a file containing environment variable definitions. These file has key value pairs sepearted by an equals sign per line. E.g. KEY=VALUE",
"description": "Absolute path to a file containing environment variable definitions. This file has key value pairs separated by an equals sign per line. E.g. KEY=VALUE",
"default": "${workspaceFolder}/.env"
},
"symbolSearchPath": {
@@ -1438,43 +1459,45 @@
},
"scripts": {
"compile": "npm run vscode:prepublish",
"compileDev": "webpack --mode development",
"compileDev": "npm run prepublishjs && webpack --mode development",
"generateOptionsSchema": "gulp generateOptionsSchema",
"postinstall": "node ./node_modules/vscode/bin/install",
"prepublishjs": "node ./tools/prepublish.js",
"pretest": "tsc -p test.tsconfig.json",
"pr-check": "gulp pr-check",
"tslint": "gulp tslint",
"unitTests": "gulp unitTests",
"vscode:prepublish": "node ./tools/prepublish.js && webpack --mode production",
"vscode:prepublish": "npm run prepublishjs && webpack --mode production",
"watch": "webpack --watch --mode development"
},
"devDependencies": {
"@types/mocha": "^5.2.6",
"@types/node": "^12.0.0",
"@types/minimatch": "^3.0.3",
"@types/mocha": "^5.2.7",
"@types/node": "^12.0.10",
"async-child-process": "^1.1.1",
"await-notify": "^1.0.1",
"gulp": "^4.0.2",
"gulp-env": "^0.4.0",
"gulp-mocha": "^6.0.0",
"gulp-tslint": "^8.1.4",
"tslint": "^5.16.0",
"tslint-microsoft-contrib": "^6.1.1",
"ts-loader": "^6.0.4",
"tslint": "^5.18.0",
"tslint-microsoft-contrib": "^6.2.0",
"tslint-no-unused-expression-chai": "^0.1.4",
"ts-loader": "^6.0.0",
"typescript": "^3.4.5",
"typescript": "^3.5.2",
"vrsource-tslint-rules": "^6.0.0",
"vscode": "^1.1.34",
"webpack": "^4.30.0",
"webpack-cli": "^3.3.2"
"vscode": "^1.1.35",
"webpack": "^4.35.2",
"webpack-cli": "^3.3.5"
},
"dependencies": {
"@types/minimatch": "^3.0.3",
"escape-string-regexp": "^2.0.0",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
"jsonc-parser": "^2.1.0",
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"plist": "^2.0.1",
"tmp": "^0.1.0",
"vscode-cpptools": "^2.1.2",
"vscode-debugadapter": "^1.34.0",
@@ -1486,7 +1509,7 @@
"runtimeDependencies": [
{
"description": "C/C++ language components (Linux / x86_64)",
"url": "https://go.microsoft.com/fwlink/?linkid=2092043",
"url": "https://go.microsoft.com/fwlink/?linkid=2092533",
"platforms": [
"linux"
],
@@ -1500,7 +1523,7 @@
},
{
"description": "C/C++ language components (Linux / x86)",
"url": "https://go.microsoft.com/fwlink/?linkid=2092112",
"url": "https://go.microsoft.com/fwlink/?linkid=2092603",
"platforms": [
"linux"
],
@@ -1516,7 +1539,7 @@
},
{
"description": "C/C++ language components (OS X)",
"url": "https://go.microsoft.com/fwlink/?linkid=2092042",
"url": "https://go.microsoft.com/fwlink/?linkid=2092602",
"platforms": [
"darwin"
],
@@ -1527,7 +1550,7 @@
},
{
"description": "C/C++ language components (Windows)",
"url": "https://go.microsoft.com/fwlink/?linkid=2092111",
"url": "https://go.microsoft.com/fwlink/?linkid=2092532",
"platforms": [
"win32"
],
@@ -1648,4 +1671,4 @@
"binaries": []
}
]
}
}
+5 -4
View File
@@ -5,7 +5,7 @@
"c_cpp.command.configurationEditUI.title": "Modifica configurazioni (UI)",
"c_cpp.command.goToDeclaration.title": "Vai a dichiarazione",
"c_cpp.command.peekDeclaration.title": "Visualizza dichiarazione",
"c_cpp.command.switchHeaderSource.title": "Visualizza Header/Sorgente",
"c_cpp.command.switchHeaderSource.title": "Visualizza header/sorgente",
"c_cpp.command.navigate.title": "Naviga...",
"c_cpp.command.enableErrorSquiggles.title": "Attiva sottolineamento errori",
"c_cpp.command.disableErrorSquiggles.title": "Disattiva sottolineamento errori",
@@ -16,7 +16,8 @@
"c_cpp.command.pauseParsing.title": "Metti in pausa l'analisi del codice",
"c_cpp.command.resumeParsing.title": "Riprendi l'analisi del codice",
"c_cpp.command.showParsingCommands.title": "Mostra comandi per l'analisi del codice",
"c_cpp.command.takeSurvey.title": "Partecipa al Sondaggio",
"c_cpp.command.buildAndDebugActiveFile.title": "Compila ed Esegui il debug del file attivo",
"c_cpp.command.logDiagnostics.title": "Registra Diagnostica"
"c_cpp.command.takeSurvey.title": "Partecipa al sondaggio",
"c_cpp.command.buildAndDebugActiveFile.title": "Compila ed esegui il debug del file attivo",
"c_cpp.command.logDiagnostics.title": "Registra diagnostica",
"c_cpp.command.rescanWorkspace.title": "Ripetere l'analisi dell'area di lavoro"
}
+16 -15
View File
@@ -1,22 +1,23 @@
{
"c_cpp.command.configurationSelect.title": "Select a configuration...",
"c_cpp.command.configurationProviderSelect.title": "Change configuration provider...",
"c_cpp.command.configurationEditJSON.title": "Edit configurations (JSON)",
"c_cpp.command.configurationEditUI.title": "Edit configurations (UI)",
"c_cpp.command.configurationSelect.title": "Select a Configuration...",
"c_cpp.command.configurationProviderSelect.title": "Change Configuration Provider...",
"c_cpp.command.configurationEditJSON.title": "Edit Configurations (JSON)",
"c_cpp.command.configurationEditUI.title": "Edit Configurations (UI)",
"c_cpp.command.goToDeclaration.title": "Go to Declaration",
"c_cpp.command.peekDeclaration.title": "Peek Declaration",
"c_cpp.command.switchHeaderSource.title": "Switch Header/Source",
"c_cpp.command.navigate.title": "Navigate...",
"c_cpp.command.enableErrorSquiggles.title": "Enable error squiggles",
"c_cpp.command.disableErrorSquiggles.title": "Disable error squiggles",
"c_cpp.command.toggleIncludeFallback.title": "Toggle IntelliSense engine fallback on include errors",
"c_cpp.command.toggleDimInactiveRegions.title": "Toggle inactive region colorization",
"c_cpp.command.showReleaseNotes.title": "Show release notes",
"c_cpp.command.resetDatabase.title": "Reset IntelliSense database",
"c_cpp.command.pauseParsing.title": "Pause parsing",
"c_cpp.command.resumeParsing.title": "Resume parsing",
"c_cpp.command.showParsingCommands.title": "Show parsing commands",
"c_cpp.command.takeSurvey.title": "Take survey",
"c_cpp.command.enableErrorSquiggles.title": "Enable Error Squiggles",
"c_cpp.command.disableErrorSquiggles.title": "Disable Error Squiggles",
"c_cpp.command.toggleIncludeFallback.title": "Toggle IntelliSense Engine Fallback on Include Errors",
"c_cpp.command.toggleDimInactiveRegions.title": "Toggle Inactive Region Colorization",
"c_cpp.command.showReleaseNotes.title": "Show Release Notes",
"c_cpp.command.resetDatabase.title": "Reset IntelliSense Database",
"c_cpp.command.pauseParsing.title": "Pause Parsing",
"c_cpp.command.resumeParsing.title": "Resume Parsing",
"c_cpp.command.showParsingCommands.title": "Show Parsing Commands",
"c_cpp.command.takeSurvey.title": "Take Survey",
"c_cpp.command.buildAndDebugActiveFile.title": "Build and Debug Active File",
"c_cpp.command.logDiagnostics.title": "Log Diagnostics"
"c_cpp.command.logDiagnostics.title": "Log Diagnostics",
"c_cpp.command.rescanWorkspace.title": "Rescan Workspace"
}
+2 -1
View File
@@ -18,5 +18,6 @@
"c_cpp.command.showParsingCommands.title": "查看解析命令",
"c_cpp.command.takeSurvey.title": "调查问卷",
"c_cpp.command.buildAndDebugActiveFile.title": "生成和调试当前文件",
"c_cpp.command.logDiagnostics.title": "记录诊断"
"c_cpp.command.logDiagnostics.title": "记录诊断",
"c_cpp.command.rescanWorkspace.title": "重新扫描工作区"
}
+21 -7
View File
@@ -103,15 +103,29 @@ export class RemoteAttachPicker {
});
}
private getRemoteOSAndProcesses(pipeCmd: string): Promise<AttachItem[]> {
// Commands to get OS and processes
const command: string = `sh -c "uname && if [ $(uname) = \\\"Linux\\\" ] ; then ${PsProcessParser.psLinuxCommand} ; elif [ $(uname) = \\\"Darwin\\\" ] ; ` +
`then ${PsProcessParser.psDarwinCommand}; fi"`;
// Creates a string to run on the host machine which will execute a shell script on the remote machine to retrieve OS and processes
private getRemoteProcessCommand(): string {
let innerQuote: string = `'`;
let outerQuote: string = `"`;
// Must use single quotes around ${command}. Linux systems evaluate $() within double-quotes.
return execChildProcess(`${pipeCmd} '${command}'`, null, this._channel).then(output => {
// Must use single quotes around the whole command and double quotes for the argument to `sh -c` because Linux evaluates $() inside of double quotes.
// Having double quotes for the outerQuote will have $(uname) replaced before it is sent to the remote machine.
if (os.platform() !== "win32") {
innerQuote = `"`;
outerQuote = `'`;
}
return `${outerQuote}sh -c ${innerQuote}uname && if [ $(uname) = \\\"Linux\\\" ] ; then ${PsProcessParser.psLinuxCommand} ; elif [ $(uname) = \\\"Darwin\\\" ] ; ` +
`then ${PsProcessParser.psDarwinCommand}; fi${innerQuote}${outerQuote}`;
}
private getRemoteOSAndProcesses(pipeCmd: string): Promise<AttachItem[]> {
// Do not add any quoting in execCommand.
const execCommand: string = `${pipeCmd} ${this.getRemoteProcessCommand()}`;
return execChildProcess(execCommand, null, this._channel).then(output => {
// OS will be on first line
// Processess will follow if listed
// Processes will follow if listed
let lines: string[] = output.split(/\r?\n/);
if (lines.length === 0) {
+77 -19
View File
@@ -12,6 +12,7 @@ import * as util from '../common';
import * as fs from 'fs';
import * as Telemetry from '../telemetry';
import { buildAndDebugActiveFileStr } from './extension';
import * as logger from '../logger';
import { IConfiguration, IConfigurationSnippet, DebuggerType, MIConfigurations, WindowsConfigurations, WSLConfigurations, PipeTransportConfigurations } from './configurations';
import { parse } from 'jsonc-parser';
@@ -183,7 +184,7 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider {
if (config.type === 'cppvsdbg') {
// Fail if cppvsdbg type is running on non-Windows
if (os.platform() !== 'win32') {
vscode.window.showErrorMessage("Debugger of type: 'cppvsdbg' is only available on Windows. Use type: 'cppdbg' on the current OS platform.");
logger.getOutputChannelLogger().showWarningMessage("Debugger of type: 'cppvsdbg' is only available on Windows. Use type: 'cppdbg' on the current OS platform.");
return undefined;
}
@@ -197,26 +198,13 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider {
config.environment = [disableDebugHeapEnvSetting];
}
}
// Add environment variables from .env file
if (config.envFile) {
try {
const parsedFile: ParsedEnvironmentFile = ParsedEnvironmentFile.CreateFromFile(config.envFile.replace(/\${workspaceFolder}/g, folder.uri.path), config["environment"]);
// show error message if single lines cannot get parsed
if (parsedFile.Warning) {
CppConfigurationProvider.showFileWarningAsync(parsedFile.Warning, config.envFile);
}
config.environment = parsedFile.Env;
delete config.envFile;
} catch (e) {
throw new Error("Can't parse envFile " + config.envFile);
}
}
}
// Add environment variables from .env file
this.resolveEnvFile(config, folder);
this.resolveSourceFileMapVariables(config);
// Modify WSL config for OpenDebugAD7
if (os.platform() === 'win32' &&
config.pipeTransport &&
@@ -244,6 +232,76 @@ class CppConfigurationProvider implements vscode.DebugConfigurationProvider {
return config && config.type ? config : null;
}
private resolveEnvFile(config: vscode.DebugConfiguration, folder: vscode.WorkspaceFolder): void {
if (config.envFile) {
// replace ${env:???} variables
let envFilePath: string = util.resolveVariables(config.envFile, null);
try {
if (folder && folder.uri && folder.uri.fsPath) {
// Try to replace ${workspaceFolder} or ${workspaceRoot}
envFilePath = envFilePath.replace(/(\${workspaceFolder}|\${workspaceRoot})/g, folder.uri.fsPath);
}
const parsedFile: ParsedEnvironmentFile = ParsedEnvironmentFile.CreateFromFile(envFilePath, config["environment"]);
// show error message if single lines cannot get parsed
if (parsedFile.Warning) {
CppConfigurationProvider.showFileWarningAsync(parsedFile.Warning, config.envFile);
}
config.environment = parsedFile.Env;
delete config.envFile;
} catch (e) {
throw new Error(`Failed to use envFile. Reason: ${e.message}`);
}
}
}
private resolveSourceFileMapVariables(config: vscode.DebugConfiguration): void {
let messages: string[] = [];
if (config.sourceFileMap) {
for (const sourceFileMapSource of Object.keys(config.sourceFileMap)) {
let message: string = "";
const sourceFileMapTarget: string = config.sourceFileMap[sourceFileMapSource];
// TODO: pass config.environment as 'additionalEnvironment' to resolveVariables when it is { key: value } instead of { "key": key, "value": value }
const newSourceFileMapSource: string = util.resolveVariables(sourceFileMapSource, null);
const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, null);
let source: string = sourceFileMapSource;
let target: string = sourceFileMapTarget;
if (sourceFileMapSource !== newSourceFileMapSource) {
message = `\tReplacing sourcePath '${sourceFileMapSource}' with '${newSourceFileMapSource}'.`;
delete config.sourceFileMap[sourceFileMapSource];
source = newSourceFileMapSource;
}
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += `Replacing targetPath '${sourceFileMapTarget}' with '${newSourceFileMapTarget}'.`;
target = newSourceFileMapTarget;
}
if (message) {
config.sourceFileMap[source] = target;
messages.push(message);
}
}
if (messages.length > 0) {
logger.getOutputChannel().appendLine("Resolving variables in sourceFileMap...");
messages.forEach((message) => {
logger.getOutputChannel().appendLine(message);
});
logger.showOutputChannel();
}
}
}
private static async showFileWarningAsync(message: string, fileName: string) : Promise<void> {
const openItem: vscode.MessageItem = { title: 'Open envFile' };
let result: vscode.MessageItem = await vscode.window.showWarningMessage(message, openItem);
+1 -1
View File
@@ -40,7 +40,7 @@ function createLaunchString(name: string, type: string, executable: string): str
"stopAtEntry": false,
"cwd": "$\{workspaceFolder\}",
"environment": [],
"externalConsole": true
"externalConsole": false
`;
}
+337 -186
View File
@@ -31,8 +31,10 @@ import { getCustomConfigProviders, CustomConfigurationProviderCollection, Custom
import { ABTestSettings, getABTestSettings } from '../abTesting';
import * as fs from 'fs';
import * as os from 'os';
import { TokenKind, ColorizationSettings, ColorizationState } from './colorization';
let ui: UI;
let timeStamp: number = 0;
const configProviderTimeout: number = 2000;
interface NavigationPayload {
@@ -80,9 +82,11 @@ interface OutputNotificationBody {
output: string;
}
interface InactiveRegionParams {
interface SemanticColorizationRegionsParams {
uri: string;
regions: InputRegion[];
regions: InputColorizationRegion[];
inactiveRegions: InputRegion[];
editVersion: number;
}
interface InputRegion {
@@ -90,9 +94,9 @@ interface InputRegion {
endLine: number;
}
interface DecorationRangesPair {
decoration: vscode.TextEditorDecorationType;
ranges: vscode.Range[];
interface InputColorizationRegion {
range: Range;
kind: number;
}
// Need to convert vscode.Uri to a string before sending it to the language server.
@@ -144,6 +148,19 @@ interface GetDiagnosticsResult {
diagnostics: string;
}
interface DidChangeVisibleRangesParams {
uri: string;
ranges: Range[];
}
interface SemanticColorizationRegionsReceiptParams {
uri: string;
}
interface ColorThemeChangedParams {
name: string;
}
// Requests
const NavigationListRequest: RequestType<TextDocumentIdentifier, string, void, void> = new RequestType<TextDocumentIdentifier, string, void, void>('cpptools/requestNavigationList');
const GoToDeclarationRequest: RequestType<void, void, void, void> = new RequestType<void, void, void, void>('cpptools/goToDeclaration');
@@ -168,6 +185,10 @@ const IntervalTimerNotification: NotificationType<void, void> = new Notification
const CustomConfigurationNotification: NotificationType<CustomConfigurationParams, void> = new NotificationType<CustomConfigurationParams, void>('cpptools/didChangeCustomConfiguration');
const CustomBrowseConfigurationNotification: NotificationType<CustomBrowseConfigurationParams, void> = new NotificationType<CustomBrowseConfigurationParams, void>('cpptools/didChangeCustomBrowseConfiguration');
const ClearCustomConfigurationsNotification: NotificationType<void, void> = new NotificationType<void, void>('cpptools/clearCustomConfigurations');
const RescanFolderNotification: NotificationType<void, void> = new NotificationType<void, void>('cpptools/rescanFolder');
const DidChangeVisibleRangesNotification: NotificationType<DidChangeVisibleRangesParams, void> = new NotificationType<DidChangeVisibleRangesParams, void>('cpptools/didChangeVisibleRanges');
const SemanticColorizationRegionsReceiptNotification: NotificationType<SemanticColorizationRegionsReceiptParams, void> = new NotificationType<SemanticColorizationRegionsReceiptParams, void>('cpptools/semanticColorizationRegionsReceipt');
const ColorThemeChangedNotification: NotificationType<ColorThemeChangedParams, void> = new NotificationType<ColorThemeChangedParams, void>('cpptools/colorThemeChanged');
// Notifications from the server
const ReloadWindowNotification: NotificationType<void, void> = new NotificationType<void, void>('cpptools/reloadWindow');
@@ -177,39 +198,11 @@ const ReportTagParseStatusNotification: NotificationType<ReportStatusNotificatio
const ReportStatusNotification: NotificationType<ReportStatusNotificationBody, void> = new NotificationType<ReportStatusNotificationBody, void>('cpptools/reportStatus');
const DebugProtocolNotification: NotificationType<OutputNotificationBody, void> = new NotificationType<OutputNotificationBody, void>('cpptools/debugProtocol');
const DebugLogNotification: NotificationType<OutputNotificationBody, void> = new NotificationType<OutputNotificationBody, void>('cpptools/debugLog');
const InactiveRegionNotification: NotificationType<InactiveRegionParams, void> = new NotificationType<InactiveRegionParams, void>('cpptools/inactiveRegions');
const SemanticColorizationRegionsNotification: NotificationType<SemanticColorizationRegionsParams, void> = new NotificationType<SemanticColorizationRegionsParams, void>('cpptools/semanticColorizationRegions');
const CompileCommandsPathsNotification: NotificationType<CompileCommandsPaths, void> = new NotificationType<CompileCommandsPaths, void>('cpptools/compileCommandsPaths');
const UpdateClangFormatPathNotification: NotificationType<string, void> = new NotificationType<string, void>('cpptools/updateClangFormatPath');
const UpdateIntelliSenseCachePathNotification: NotificationType<string, void> = new NotificationType<string, void>('cpptools/updateIntelliSenseCachePath');
class BlockingTask<T> {
private dependency: BlockingTask<any>;
private done: boolean = false;
private promise: Promise<T>;
constructor(task: () => T, dependency?: BlockingTask<any>) {
this.promise = new Promise<T>(async (resolve, reject) => {
try {
let result: T = await task();
resolve(result);
this.done = true;
} catch (err) {
reject(err);
this.done = true;
}
});
this.dependency = dependency;
}
public get Done(): boolean {
return this.done && (!this.dependency || this.dependency.Done);
}
public then(onSucceeded: (value: T) => any, onRejected: (err) => any): Promise<any> {
return this.promise.then(onSucceeded, onRejected);
}
}
let failureMessageShown: boolean = false;
interface ClientModel {
@@ -230,13 +223,17 @@ export interface Client {
RootUri: vscode.Uri;
Name: string;
TrackedDocuments: Set<vscode.TextDocument>;
onDidChangeSettings(): { [key: string] : string };
onDidChangeSettings(event: vscode.ConfigurationChangeEvent): { [key: string] : string };
onDidOpenTextDocument(document: vscode.TextDocument): void;
onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void;
onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void;
onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void;
onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable<void>;
updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable<void>;
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void>;
provideCustomConfiguration(document: vscode.TextDocument): Promise<void>;
logDiagnostics(): Promise<void>;
rescanFolder(): Promise<void>;
getCurrentConfigName(): Thenable<string>;
getCompilerPath(): Thenable<string>;
getKnownCompilers(): Thenable<configs.KnownCompiler[]>;
@@ -280,13 +277,16 @@ class DefaultClient implements Client {
private configuration: configs.CppProperties;
private rootPathFileWatcher: vscode.FileSystemWatcher;
private rootFolder: vscode.WorkspaceFolder | undefined;
private storagePath: string;
private trackedDocuments = new Set<vscode.TextDocument>();
private outputChannel: vscode.OutputChannel;
private debugChannel: vscode.OutputChannel;
private diagnosticsChannel: vscode.OutputChannel;
private crashTimes: number[] = [];
private isSupported: boolean = true;
private inactiveRegionsDecorations = new Map<string, DecorationRangesPair>();
private colorizationSettings: ColorizationSettings;
private colorizationState = new Map<string, ColorizationState>();
private visibleRanges = new Map<string, Range[]>();
private settingsTracker: SettingsTracker;
private configurationProvider: string;
@@ -322,7 +322,7 @@ class DefaultClient implements Client {
}
private get AdditionalEnvironment(): { [key: string]: string | string[] } {
return { workspaceFolderBasename: this.Name };
return { workspaceFolderBasename: this.Name, workspaceStorage: this.storagePath };
}
private getName(workspaceFolder?: vscode.WorkspaceFolder): string {
@@ -336,15 +336,33 @@ class DefaultClient implements Client {
* @see notifyWhenReady(notify)
*/
private pendingTask: BlockingTask<void>;
private pendingTask: util.BlockingTask<any>;
private getUniqueWorkspaceStorageName(workspaceFolder?: vscode.WorkspaceFolder) : string {
let workspaceFolderName: string = this.getName(workspaceFolder);
if (!workspaceFolder || workspaceFolder.index < 1) {
return workspaceFolderName; // No duplicate names to search for.
}
for (let i: number = 0; i < workspaceFolder.index; ++i) {
if (vscode.workspace.workspaceFolders[i].name === workspaceFolderName) {
return path.join(workspaceFolderName, String(workspaceFolder.index)); // Use the index as a subfolder.
}
}
return workspaceFolderName; // No duplicate names found.
}
constructor(allClients: ClientCollection, workspaceFolder?: vscode.WorkspaceFolder) {
this.rootFolder = workspaceFolder;
this.storagePath = util.extensionContext ? util.extensionContext.storagePath :
path.join((this.rootFolder ? this.rootFolder.uri.fsPath : ""), "/.vscode");
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 1) {
this.storagePath = path.join(this.storagePath, this.getUniqueWorkspaceStorageName(this.rootFolder));
}
try {
let languageClient: LanguageClient = this.createLanguageClient(allClients, workspaceFolder);
let languageClient: LanguageClient = this.createLanguageClient(allClients);
languageClient.registerProposedFeatures();
languageClient.start(); // This returns Disposable, but doesn't need to be tracked because we call .stop() explicitly in our dispose()
util.setProgress(util.getProgressExecutableStarted());
this.rootFolder = workspaceFolder;
ui = getUI();
ui.bind(this);
@@ -396,30 +414,24 @@ class DefaultClient implements Client {
vscode.window.showErrorMessage("Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: " + additionalInfo);
}
}
this.colorizationSettings = new ColorizationSettings(this.RootUri);
}
private createLanguageClient(allClients: ClientCollection, workspaceFolder?: vscode.WorkspaceFolder): LanguageClient {
private createLanguageClient(allClients: ClientCollection): LanguageClient {
let serverModule: string = getLanguageServerFileName();
let exeExists: boolean = fs.existsSync(serverModule);
if (!exeExists) {
telemetry.logLanguageServerEvent("missingLanguageServerBinary");
throw String('Missing binary at ' + serverModule);
}
let serverName: string = this.getName(workspaceFolder);
let serverName: string = this.getName(this.rootFolder);
let serverOptions: ServerOptions = {
run: { command: serverModule },
debug: { command: serverModule, args: [ serverName ] }
};
let settings: CppSettings = new CppSettings(workspaceFolder ? workspaceFolder.uri : null);
let other: OtherSettings = new OtherSettings(workspaceFolder ? workspaceFolder.uri : null);
let storagePath: string = util.extensionContext ? util.extensionContext.storagePath :
path.join((workspaceFolder ? workspaceFolder.uri.fsPath : ""), "/.vscode");
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 1) {
storagePath = path.join(storagePath, serverName);
}
let settings: CppSettings = new CppSettings(this.rootFolder ? this.rootFolder.uri : null);
let other: OtherSettings = new OtherSettings(this.rootFolder ? this.rootFolder.uri : null);
let abTestSettings: ABTestSettings = getABTestSettings();
let intelliSenseCacheDisabled: boolean = false;
@@ -440,7 +452,7 @@ class DefaultClient implements Client {
// Synchronize the setting section to the server
configurationSection: ['C_Cpp', 'files', 'search']
},
workspaceFolder: workspaceFolder,
workspaceFolder: this.rootFolder,
initializationOptions: {
clang_format_path: util.resolveVariables(settings.clangFormatPath, this.AdditionalEnvironment),
clang_format_style: settings.clangFormatStyle,
@@ -450,16 +462,17 @@ class DefaultClient implements Client {
extension_path: util.extensionPath,
exclude_files: other.filesExclude,
exclude_search: other.searchExclude,
storage_path: storagePath,
storage_path: this.storagePath,
tab_size: other.editorTabSize,
intelliSenseEngine: settings.intelliSenseEngine,
intelliSenseEngineFallback: settings.intelliSenseEngineFallback,
intelliSenseCacheDisabled: intelliSenseCacheDisabled,
intelliSenseCachePath : util.resolveVariables(settings.intelliSenseCachePath, this.AdditionalEnvironment),
intelliSenseCachePath : util.resolveCachePath(settings.intelliSenseCachePath, this.AdditionalEnvironment),
intelliSenseCacheSize : settings.intelliSenseCacheSize,
autocomplete: settings.autoComplete,
errorSquiggles: settings.errorSquiggles,
dimInactiveRegions: settings.dimInactiveRegions,
enhancedColorization: settings.enhancedColorization,
suggestSnippets: settings.suggestSnippets,
loggingLevel: settings.loggingLevel,
workspaceParsingPriority: settings.workspaceParsingPriority,
@@ -506,9 +519,44 @@ class DefaultClient implements Client {
return new LanguageClient(`cpptools: ${serverName}`, serverOptions, clientOptions);
}
public onDidChangeSettings(): { [key: string] : string } {
let changedSettings: { [key: string] : string } = this.settingsTracker.getChangedSettings();
public onDidChangeSettings(event: vscode.ConfigurationChangeEvent): { [key: string] : string } {
let colorizationNeedsReload: boolean = event.affectsConfiguration("workbench.colorTheme")
|| event.affectsConfiguration("editor.tokenColorCustomizations");
let colorizationNeedsRefresh: boolean = colorizationNeedsReload
|| event.affectsConfiguration("C_Cpp.enhancedColorization", this.RootUri)
|| event.affectsConfiguration("C_Cpp.dimInactiveRegions", this.RootUri)
|| event.affectsConfiguration("C_Cpp.inactiveRegionOpacity", this.RootUri)
|| event.affectsConfiguration("C_Cpp.inactiveRegionForegroundColor", this.RootUri)
|| event.affectsConfiguration("C_Cpp.inactiveRegionBackgroundColor", this.RootUri);
let colorThemeChanged: boolean = event.affectsConfiguration("workbench.colorTheme", this.RootUri);
if (colorThemeChanged) {
let otherSettings: OtherSettings = new OtherSettings(this.RootUri);
this.languageClient.sendNotification(ColorThemeChangedNotification, { name: otherSettings.colorTheme } );
}
if (colorizationNeedsReload) {
this.colorizationSettings.reload();
}
if (colorizationNeedsRefresh) {
let processedUris: vscode.Uri[] = [];
for (let e of vscode.window.visibleTextEditors) {
let uri: vscode.Uri = e.document.uri;
// Make sure we don't process the same file multiple times.
// colorizationState.onSettingsChanged ensures all visible text editors for that file get
// refreshed, after it creates a set of decorators to be shared by all visible instances of the file.
if (!processedUris.find(e => e === uri)) {
processedUris.push(uri);
let colorizationState: ColorizationState = this.colorizationState.get(uri.toString());
if (colorizationState) {
colorizationState.onSettingsChanged(uri);
}
}
}
}
let changedSettings: { [key: string] : string } = this.settingsTracker.getChangedSettings();
if (Object.keys(changedSettings).length > 0) {
if (changedSettings["commentContinuationPatterns"]) {
updateLanguageConfigurations();
@@ -519,28 +567,96 @@ class DefaultClient implements Client {
}
if (changedSettings["intelliSenseCachePath"]) {
let settings: CppSettings = new CppSettings(this.RootUri);
this.languageClient.sendNotification(UpdateIntelliSenseCachePathNotification, util.resolveVariables(settings.intelliSenseCachePath, this.AdditionalEnvironment));
this.languageClient.sendNotification(UpdateIntelliSenseCachePathNotification, util.resolveCachePath(settings.intelliSenseCachePath, this.AdditionalEnvironment));
}
this.configuration.onDidChangeSettings();
telemetry.logLanguageServerEvent("CppSettingsChange", changedSettings, null);
}
return changedSettings;
}
public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
let settings: CppSettings = new CppSettings(this.RootUri);
if (settings.dimInactiveRegions) {
//Apply text decorations to inactive regions
for (let e of editors) {
let valuePair: DecorationRangesPair = this.inactiveRegionsDecorations.get(e.document.uri.toString());
if (valuePair) {
e.setDecorations(valuePair.decoration, valuePair.ranges); // VSCode clears the decorations when the text editor becomes invisible
private editVersion: number = 0;
public onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void {
// Increment editVersion for every call to onDidChangeTextDocument, regardless of whether the file is handled
this.editVersion++;
if (textDocumentChangeEvent.document.uri.scheme === "file") {
if (textDocumentChangeEvent.document.languageId === "cpp" || textDocumentChangeEvent.document.languageId === "c") {
try {
let colorizationState: ColorizationState = this.getColorizationState(textDocumentChangeEvent.document.uri.toString());
// Adjust colorization ranges after this edit. (i.e. if a line was added, push decorations after it down one line)
colorizationState.addEdits(textDocumentChangeEvent.contentChanges, this.editVersion);
} catch (e) {
// Ensure an exception does not prevent pass-through to native handler, or editVersion could become inconsistent
console.log(e.toString());
}
}
}
}
public onDidOpenTextDocument(document: vscode.TextDocument): void {
if (document.uri.scheme === "file") {
this.sendVisibleRanges(document.uri);
}
}
public onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
let processedUris: vscode.Uri[] = [];
editors.forEach(editor => {
if (editor.document.uri.scheme === "file") {
let colorizationState: ColorizationState = this.colorizationState.get(editor.document.uri.toString());
if (colorizationState) {
colorizationState.refresh(editor);
}
if (!processedUris.find(uri => uri === editor.document.uri)) {
processedUris.push(editor.document.uri);
this.sendVisibleRanges(editor.document.uri);
}
}
});
}
public sendVisibleRanges(uri: vscode.Uri): void {
let ranges: Range[] = [];
// Get ranges from all editors matching this URI
let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri === uri);
for (let e of editors) {
e.visibleRanges.forEach(range => ranges.push(Range.create(range.start.line, range.start.character, range.end.line, range.end.character)));
}
// Only send ranges if they have actually changed.
let isSame: boolean = false;
let savedRanges: Range[] = this.visibleRanges.get(uri.toString());
if (savedRanges) {
if (ranges.length === savedRanges.length) {
isSame = true;
for (let i: number = 0; i < ranges.length; i++) {
if (ranges[i] !== savedRanges[i]) {
isSame = false;
break;
}
}
}
} else {
isSame = ranges.length === 0;
}
if (!isSame) {
this.visibleRanges.set(uri.toString(), ranges);
let params: DidChangeVisibleRangesParams = {
uri: uri.toString(),
ranges: ranges
};
this.notifyWhenReady(() => this.languageClient.sendNotification(DidChangeVisibleRangesNotification, params));
}
}
public onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void {
if (textEditorVisibleRangesChangeEvent.textEditor.document.uri.scheme === "file") {
this.sendVisibleRanges(textEditorVisibleRangesChangeEvent.textEditor.document.uri);
}
}
public onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable<void> {
let onRegistered: () => void = () => {
// version 2 providers control the browse.path. Avoid thrashing the tag parser database by pausing parsing until
@@ -654,82 +770,92 @@ class DefaultClient implements Client {
this.diagnosticsChannel = vscode.window.createOutputChannel("C/C++ Diagnostics");
this.disposables.push(this.diagnosticsChannel);
}
let header: string = `-------- Diagnostics - ${new Date().toLocaleString()}\n`;
let version: string = `Version: ${util.packageJson.version}\n`;
this.diagnosticsChannel.appendLine(`${header}${version}${response.diagnostics}`);
let configJson: string = "";
if (this.configuration.CurrentConfiguration) {
configJson = `Current Configuration:\n${JSON.stringify(this.configuration.CurrentConfiguration, null, 4)}\n`;
}
this.diagnosticsChannel.appendLine(`${header}${version}${configJson}${response.diagnostics}`);
this.diagnosticsChannel.show(false);
}
public async rescanFolder(): Promise<void> {
await this.notifyWhenReady(() => this.languageClient.sendNotification(RescanFolderNotification));
}
public async provideCustomConfiguration(document: vscode.TextDocument): Promise<void> {
let tokenSource: CancellationTokenSource = new CancellationTokenSource();
let providers: CustomConfigurationProviderCollection = getCustomConfigProviders();
if (providers.size === 0) {
return Promise.resolve();
}
console.log("provideCustomConfiguration");
let providerId: string|undefined = await this.getCustomConfigurationProviderId();
if (!providerId) {
return Promise.resolve();
}
let providerName: string = providerId;
let params: QueryTranslationUnitSourceParams = {
uri: document.uri.toString()
};
let response: QueryTranslationUnitSourceResult = await this.requestWhenReady(() => this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params));
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.ConfigNotNeeded) {
return Promise.resolve();
}
let tuUri: vscode.Uri = vscode.Uri.parse(response.uri);
let configName: string = await this.getCurrentConfigName();
const notReadyMessage: string = `${providerName} is not ready`;
let provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[]> = async () => {
// The config requests that we use a provider, try to get IntelliSense configuration info from that provider.
try {
let provider: CustomConfigurationProvider1|null = providers.get(providerId);
if (provider) {
if (!provider.isReady) {
return Promise.reject(notReadyMessage);
}
providerName = provider.name;
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
return provider.provideConfigurations([tuUri], tokenSource.token);
}
}
} catch (err) {
return this.queueBlockingTask(async () => {
let tokenSource: CancellationTokenSource = new CancellationTokenSource();
let providers: CustomConfigurationProviderCollection = getCustomConfigProviders();
if (providers.size === 0) {
return Promise.resolve();
}
console.log("provideCustomConfiguration");
let providerId: string|undefined = this.configuration.CurrentConfigurationProvider;
if (!providerId) {
return Promise.resolve();
}
console.warn("failed to provide configuration");
return Promise.reject("");
};
return this.queueTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource).then(
(configs: SourceFileConfigurationItem[]) => {
if (configs && configs.length > 0) {
this.sendCustomConfigurations(configs, true);
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.AncestorConfigNeeded) {
// replacing uri with original uri
let newConfig: SourceFileConfigurationItem = { uri: document.uri, configuration: configs[0].configuration };
this.sendCustomConfigurations([newConfig], true);
}
}
},
(err) => {
if (err === notReadyMessage) {
return;
}
let settings: CppSettings = new CppSettings(this.RootUri);
if (settings.configurationWarnings === "Enabled" && !this.isExternalHeader(document.uri) && !vscode.debug.activeDebugSession) {
const dismiss: string = "Dismiss";
const disable: string = "Disable Warnings";
let message: string = `'${providerName}' is unable to provide IntelliSense configuration information for '${document.uri.fsPath}'. ` +
`Settings from the '${configName}' configuration will be used instead.`;
if (err) {
message += ` (${err})`;
}
let providerName: string = providerId;
let params: QueryTranslationUnitSourceParams = {
uri: document.uri.toString()
};
let response: QueryTranslationUnitSourceResult = await this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params);
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.ConfigNotNeeded) {
return Promise.resolve();
}
vscode.window.showInformationMessage(message, dismiss, disable).then(response => {
let tuUri: vscode.Uri = vscode.Uri.parse(response.uri);
let configName: string = this.configuration.CurrentConfiguration.name;
const notReadyMessage: string = `${providerName} is not ready`;
let provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[]> = async () => {
// The config requests that we use a provider, try to get IntelliSense configuration info from that provider.
try {
let provider: CustomConfigurationProvider1|null = providers.get(providerId);
if (provider) {
if (!provider.isReady) {
return Promise.reject(notReadyMessage);
}
providerName = provider.name;
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
return provider.provideConfigurations([tuUri], tokenSource.token);
}
}
} catch (err) {
}
console.warn("failed to provide configuration");
return Promise.reject("");
};
return this.callTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource).then(
(configs: SourceFileConfigurationItem[]) => {
if (configs && configs.length > 0) {
this.sendCustomConfigurations(configs, false);
if (response.configDisposition === QueryTranslationUnitSourceConfigDisposition.AncestorConfigNeeded) {
// replacing uri with original uri
let newConfig: SourceFileConfigurationItem = { uri: document.uri, configuration: configs[0].configuration };
this.sendCustomConfigurations([newConfig], false);
}
}
},
(err) => {
if (err === notReadyMessage) {
return;
}
let settings: CppSettings = new CppSettings(this.RootUri);
if (settings.configurationWarnings === "Enabled" && !this.isExternalHeader(document.uri) && !vscode.debug.activeDebugSession) {
const dismiss: string = "Dismiss";
const disable: string = "Disable Warnings";
let message: string = `'${providerName}' is unable to provide IntelliSense configuration information for '${document.uri.fsPath}'. ` +
`Settings from the '${configName}' configuration will be used instead.`;
if (err) {
message += ` (${err})`;
}
vscode.window.showInformationMessage(message, dismiss, disable).then(response => {
switch (response) {
case disable: {
settings.toggleSetting("configurationWarnings", "Enabled", "Disabled");
@@ -737,18 +863,15 @@ class DefaultClient implements Client {
}
}
});
}
});
}
});
});
}
private isExternalHeader(uri: vscode.Uri): boolean {
return util.isHeader(uri) && !uri.toString().startsWith(this.RootUri.toString());
}
private getCustomConfigurationProviderId(): Thenable<string|undefined> {
return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfigurationProvider));
}
public getCurrentConfigName(): Thenable<string> {
return this.queueTask(() => Promise.resolve(this.configuration.CurrentConfiguration.name));
}
@@ -798,7 +921,7 @@ class DefaultClient implements Client {
if (this.pendingTask && !this.pendingTask.Done) {
// We don't want the queue to stall because of a rejected promise.
return this.pendingTask.then(nextTask, nextTask);
return this.pendingTask.getPromise().then(nextTask, nextTask);
} else {
this.pendingTask = undefined;
return nextTask();
@@ -815,7 +938,8 @@ class DefaultClient implements Client {
*/
private queueBlockingTask(task: () => Thenable<void>): Thenable<void> {
if (this.isSupported) {
this.pendingTask = new BlockingTask<void>(task, this.pendingTask);
this.pendingTask = new util.BlockingTask<void>(task, this.pendingTask);
return this.pendingTask.getPromise();
} else {
return Promise.reject("Unsupported client");
}
@@ -848,6 +972,31 @@ class DefaultClient implements Client {
});
}
private callTaskWithTimeout(task: () => Thenable<any>, ms: number, cancelToken?: CancellationTokenSource): Thenable<any> {
let timer: NodeJS.Timer;
// Create a promise that rejects in <ms> milliseconds
let timeout: () => Promise<any> = () => new Promise((resolve, reject) => {
timer = setTimeout(() => {
clearTimeout(timer);
if (cancelToken) {
cancelToken.cancel();
}
reject("Timed out in " + ms + "ms.");
}, ms);
});
// Returns a race between our timeout and the passed in promise
return Promise.race([task(), timeout()]).then(
(result: any) => {
clearTimeout(timer);
return result;
},
(error: any) => {
clearTimeout(timer);
throw error;
});
}
public requestWhenReady(request: () => Thenable<any>): Thenable<any> {
return this.queueTask(request);
}
@@ -875,7 +1024,7 @@ class DefaultClient implements Client {
this.languageClient.onNotification(ReportNavigationNotification, (e) => this.navigate(e));
this.languageClient.onNotification(ReportStatusNotification, (e) => this.updateStatus(e));
this.languageClient.onNotification(ReportTagParseStatusNotification, (e) => this.updateTagParseStatus(e));
this.languageClient.onNotification(InactiveRegionNotification, (e) => this.updateInactiveRegions(e));
this.languageClient.onNotification(SemanticColorizationRegionsNotification, (e) => this.updateSemanticColorizationRegions(e));
this.languageClient.onNotification(CompileCommandsPathsNotification, (e) => this.promptCompileCommands(e));
this.setupOutputHandlers();
}
@@ -1017,9 +1166,16 @@ class DefaultClient implements Client {
this.model.isTagParsing.Value = true;
testHook.updateStatus(Status.TagParsingBegun);
} else if (message.endsWith("Updating IntelliSense...")) {
timeStamp = Date.now();
this.model.isUpdatingIntelliSense.Value = true;
testHook.updateStatus(Status.IntelliSenseCompiling);
} else if (message.endsWith("IntelliSense Ready")) {
let settings: CppSettings = new CppSettings(this.RootUri);
if (settings.loggingLevel === "Debug") {
let out: logger.Logger = logger.getOutputChannelLogger();
let duration: number = Date.now() - timeStamp;
out.appendLine(`Update IntelliSense time (sec): ${duration / 1000}`);
}
this.model.isUpdatingIntelliSense.Value = false;
testHook.updateStatus(Status.IntelliSenseReady);
} else if (message.endsWith("Ready")) { // Tag Parser Ready
@@ -1028,7 +1184,7 @@ class DefaultClient implements Client {
util.setProgress(util.getProgressParseRootSuccess());
} else if (message.endsWith("No Squiggles")) {
util.setIntelliSenseProgress(util.getProgressIntelliSenseNoSquiggles());
} else if (message.endsWith("IntelliSense Fallback")) {
} else if (message.endsWith("Unresolved Headers")) {
let showIntelliSenseFallbackMessage: PersistentState<boolean> = new PersistentState<boolean>("CPP.showIntelliSenseFallbackMessage", true);
if (showIntelliSenseFallbackMessage.Value) {
ui.showConfigureIncludePathMessage(() => {
@@ -1043,8 +1199,8 @@ class DefaultClient implements Client {
case configJSON:
vscode.commands.getCommands(true).then((commands: string[]) => {
if (commands.indexOf("workbench.action.problems.focus") >= 0) {
vscode.commands.executeCommand("workbench.action.problems.focus");
}
vscode.commands.executeCommand("workbench.action.problems.focus");
}
});
this.handleConfigurationEditJSONCommand();
telemetry.logLanguageServerEvent("SettingsCommand", { "toast": "json" }, null);
@@ -1053,7 +1209,7 @@ class DefaultClient implements Client {
vscode.commands.getCommands(true).then((commands: string[]) => {
if (commands.indexOf("workbench.action.problems.focus") >= 0) {
vscode.commands.executeCommand("workbench.action.problems.focus");
}
}
});
this.handleConfigurationEditUICommand();
telemetry.logLanguageServerEvent("SettingsCommand", { "toast": "ui" }, null);
@@ -1074,47 +1230,33 @@ class DefaultClient implements Client {
this.model.tagParserStatus.Value = notificationBody.status;
}
private updateInactiveRegions(params: InactiveRegionParams): void {
let settings: CppSettings = new CppSettings(this.RootUri);
private getColorizationState(uri: string): ColorizationState {
let colorizationState: ColorizationState = this.colorizationState.get(uri);
if (!colorizationState) {
colorizationState = new ColorizationState(this.RootUri, this.colorizationSettings);
this.colorizationState.set(uri, colorizationState);
}
return colorizationState;
}
let decoration: vscode.TextEditorDecorationType = vscode.window.createTextEditorDecorationType({
opacity: settings.inactiveRegionOpacity.toString(),
backgroundColor: settings.inactiveRegionBackgroundColor,
color: settings.inactiveRegionForegroundColor,
rangeBehavior: vscode.DecorationRangeBehavior.ClosedOpen
});
// We must convert to vscode.Ranges in order to make use of the API's
let ranges: vscode.Range[] = [];
private updateSemanticColorizationRegions(params: SemanticColorizationRegionsParams): void {
// Convert the params to vscode.Range's before passing to colorizationState.updateSemantic()
let semanticRanges: vscode.Range[][] = new Array<vscode.Range[]>(TokenKind.Count);
for (let i: number = 0; i < TokenKind.Count; i++) {
semanticRanges[i] = [];
}
params.regions.forEach(element => {
let newRange : vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0);
ranges.push(newRange);
let newRange : vscode.Range = new vscode.Range(element.range.start.line, element.range.start.character, element.range.end.line, element.range.end.character);
semanticRanges[element.kind].push(newRange);
});
// Find entry for cached file and act accordingly
let valuePair: DecorationRangesPair = this.inactiveRegionsDecorations.get(params.uri);
if (valuePair) {
// Disposing of and resetting the decoration will undo previously applied text decorations
valuePair.decoration.dispose();
valuePair.decoration = decoration;
// As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible
valuePair.ranges = ranges;
} else { // The entry does not exist. Make a new one
let toInsert: DecorationRangesPair = {
decoration: decoration,
ranges: ranges
};
this.inactiveRegionsDecorations.set(params.uri, toInsert);
}
if (settings.dimInactiveRegions) {
// Apply the decorations to all *visible* text editors
let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === params.uri);
for (let e of editors) {
e.setDecorations(decoration, ranges);
}
}
let inactiveRanges: vscode.Range[] = [];
params.inactiveRegions.forEach(element => {
let newRange : vscode.Range = new vscode.Range(element.startLine, 0, element.endLine, 0);
inactiveRanges.push(newRange);
});
let colorizationState: ColorizationState = this.getColorizationState(params.uri);
colorizationState.updateSemantic(params.uri, semanticRanges, inactiveRanges, params.editVersion);
this.languageClient.sendNotification(SemanticColorizationRegionsReceiptNotification, { uri: params.uri } );
}
private promptCompileCommands(params: CompileCommandsPaths) : void {
@@ -1426,6 +1568,11 @@ class DefaultClient implements Client {
public dispose(): Thenable<void> {
let promise: Thenable<void> = (this.languageClient) ? this.languageClient.stop() : Promise.resolve();
return promise.then(() => {
this.colorizationState.forEach(colorizationState => {
colorizationState.dispose();
});
this.disposables.forEach((d) => d.dispose());
this.disposables = [];
@@ -1466,13 +1613,17 @@ class NullClient implements Client {
RootUri: vscode.Uri = vscode.Uri.file("/");
Name: string = "(empty)";
TrackedDocuments = new Set<vscode.TextDocument>();
onDidChangeSettings(): { [key: string] : string } { return {}; }
onDidChangeSettings(event: vscode.ConfigurationChangeEvent): { [key: string] : string } { return {}; }
onDidOpenTextDocument(document: vscode.TextDocument): void {}
onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {}
onDidChangeTextDocument(textDocumentChangeEvent: vscode.TextDocumentChangeEvent): void {}
onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void {}
onRegisterCustomConfigurationProvider(provider: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
updateCustomConfigurations(requestingProvider?: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
updateCustomBrowseConfiguration(requestingProvider?: CustomConfigurationProvider1): Thenable<void> { return Promise.resolve(); }
provideCustomConfiguration(document: vscode.TextDocument): Promise<void> { return Promise.resolve(); }
logDiagnostics(): Promise<void> { return Promise.resolve(); }
rescanFolder(): Promise<void> { return Promise.resolve(); }
getCurrentConfigName(): Thenable<string> { return Promise.resolve(""); }
getCompilerPath(): Thenable<string> { return Promise.resolve(""); }
getKnownCompilers(): Thenable<configs.KnownCompiler[]> { return Promise.resolve([]); }
@@ -0,0 +1,657 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as path from 'path';
import * as vscode from 'vscode';
import * as util from '../common';
import { CppSettings, OtherSettings, TextMateRule, TextMateRuleSettings } from './settings';
import * as jsonc from 'jsonc-parser';
import * as plist from 'plist';
export enum TokenKind {
// These need to match the token_kind enum in the server
// Semantic tokens
Macro,
Enumerator,
GlobalVariable,
LocalVariable,
Parameter,
Type,
RefType,
ValueType,
Function,
MemberFunction,
MemberField,
StaticMemberFunction,
StaticMemberField,
Property,
Event,
ClassTemplate,
GenericType,
FunctionTemplate,
Namespace,
Label,
UdlRaw,
UdlNumber,
UdlString,
OperatorFunction,
MemberOperator,
NewDelete,
Count
}
interface VersionedEdits {
editVersion: number;
changes: vscode.TextDocumentContentChangeEvent[];
}
class ThemeStyle {
foreground: string;
background: string;
fontStyle: string;
}
export class ColorizationSettings {
private uri: vscode.Uri;
private pendingTask: util.BlockingTask<any>;
private editorBackground: string;
public themeStyleCMap: ThemeStyle[] = [];
public themeStyleCppMap: ThemeStyle[] = [];
private static readonly scopeToTokenColorNameMap = new Map<string, string>([
["comment", "comments"],
["string", "strings"],
["keyword.operator", "keywords"],
["keyword.control", "keywords"],
["constant.numeric", "numbers"],
["entity.name.type", "types"],
["entity.name.class", "types"],
["entity.name.function", "functions"],
["variable", "variables"]
]);
constructor(uri: vscode.Uri) {
this.uri = uri;
this.reload();
}
// Given a TextMate rule 'settings' node, update a ThemeStyle to include any color or style information
private updateStyleFromTextMateRuleSettings(baseStyle: ThemeStyle, textMateRuleSettings: TextMateRuleSettings): void {
if (textMateRuleSettings.foreground) {
baseStyle.foreground = textMateRuleSettings.foreground;
}
if (textMateRuleSettings.background && textMateRuleSettings.background.toUpperCase() !== this.editorBackground.toUpperCase()) {
baseStyle.background = textMateRuleSettings.background;
}
// Any (even empty) string for fontStyle removes inherited value
if (textMateRuleSettings.fontStyle) {
baseStyle.fontStyle = textMateRuleSettings.fontStyle;
} else if (textMateRuleSettings.fontStyle === "") {
baseStyle.fontStyle = undefined;
}
}
// If the scope can be found in a set of TextMate rules, apply it to both C and Cpp ThemeStyle's
private findThemeStyleForScope(baseCStyle: ThemeStyle, baseCppStyle: ThemeStyle, scope: string, textMateRules: TextMateRule[]): void {
if (textMateRules) {
let match: TextMateRule = textMateRules.find(e => e.settings && (e.scope === scope || ((e.scope instanceof Array) && e.scope.indexOf(scope) > -1)));
if (match) {
if (baseCStyle) {
this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings);
}
if (baseCppStyle) {
this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings);
}
}
match = textMateRules.find(e => e.settings && (e.scope === "source " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source " + scope) > -1)));
if (match) {
if (baseCStyle) {
this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings);
}
if (baseCppStyle) {
this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings);
}
}
if (baseCStyle) {
match = textMateRules.find(e => e.settings && (e.scope === "source.c " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source.c " + scope) > -1)));
if (match) {
this.updateStyleFromTextMateRuleSettings(baseCStyle, match.settings);
}
}
if (baseCppStyle) {
match = textMateRules.find(e => e.settings && (e.scope === "source.cpp " + scope || ((e.scope instanceof Array) && e.scope.indexOf("source.cpp " + scope) > -1)));
if (match) {
this.updateStyleFromTextMateRuleSettings(baseCppStyle, match.settings);
}
}
}
}
// For a specific scope cascase all potential sources of style information to create a final ThemeStyle
private calculateThemeStyleForScope(baseCStyle: ThemeStyle, baseCppStyle: ThemeStyle, scope: string, themeName: string, themeTextMateRules: TextMateRule[][]): void {
// Search for settings with this scope in current theme
themeTextMateRules.forEach((rules) => {
this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, rules);
});
let otherSettings: OtherSettings = new OtherSettings(this.uri);
// Next in priority would be a global user override of token color of the equivilent scope
let colorTokenName: string | undefined = ColorizationSettings.scopeToTokenColorNameMap.get(scope);
if (colorTokenName) {
let settingValue: string = otherSettings.getCustomColorToken(colorTokenName);
if (settingValue) {
if (baseCStyle) {
baseCStyle.foreground = settingValue;
}
if (baseCppStyle) {
baseCppStyle.foreground = settingValue;
}
}
}
// Next in priority would be a global user override of this scope in textMateRules
this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, otherSettings.customTextMateRules);
// Next in priority would be a theme-specific user override of token color of the equivilent scope
if (colorTokenName) {
let settingValue: string = otherSettings.getCustomThemeSpecificColorToken(colorTokenName, themeName);
if (settingValue) {
if (baseCStyle) {
baseCStyle.foreground = settingValue;
}
if (baseCppStyle) {
baseCppStyle.foreground = settingValue;
}
}
}
// Next in priority would be a theme-specific user override of this scope in textMateRules
let textMateRules: TextMateRule[] = otherSettings.getCustomThemeSpecificTextMateRules(themeName);
this.findThemeStyleForScope(baseCStyle, baseCppStyle, scope, textMateRules);
}
// For each level of the scope, look of style information
private calculateStyleForToken(tokenKind: TokenKind, scope: string, themeName: string, themeTextMateRules: TextMateRule[][]): void {
// Try scopes, from most general to most specific, apply style in cascading manner
let parts: string[] = scope.split(".");
let accumulatedScope: string = "";
for (let i: number = 0; i < parts.length; i++) {
accumulatedScope += parts[i];
this.calculateThemeStyleForScope(this.themeStyleCMap[tokenKind], this.themeStyleCppMap[tokenKind], accumulatedScope, themeName, themeTextMateRules);
this.calculateThemeStyleForScope(this.themeStyleCMap[tokenKind], null, accumulatedScope + ".c", themeName, themeTextMateRules);
this.calculateThemeStyleForScope(null, this.themeStyleCppMap[tokenKind], accumulatedScope + ".cpp", themeName, themeTextMateRules);
accumulatedScope += ".";
}
}
public syncWithLoadingSettings(f: () => any): void {
this.pendingTask = new util.BlockingTask<void>(f, this.pendingTask);
}
public updateStyles(themeName: string, defaultStyle: ThemeStyle, textMateRules: TextMateRule[][]): void {
this.themeStyleCMap = new Array<ThemeStyle>(TokenKind.Count);
this.themeStyleCppMap = new Array<ThemeStyle>(TokenKind.Count);
// Populate with unique objects, as they will be individual modified in place
for (let i: number = 0; i < TokenKind.Count; i++) {
this.themeStyleCMap[i] = Object.assign({}, defaultStyle);
this.themeStyleCppMap[i] = Object.assign({}, defaultStyle);
}
this.calculateStyleForToken(TokenKind.Macro, "entity.name.function.preprocessor", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Enumerator, "variable.other.enummember", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.GlobalVariable, "variable.other.global", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.LocalVariable, "variable.other.local", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Parameter, "variable.parameter", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Type, "entity.name.type.class", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.RefType, "entity.name.type.class.reference", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.ValueType, "entity.name.type.class.value", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Function, "entity.name.function", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.MemberFunction, "entity.name.function.member", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.MemberField, "variable.other.property", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.StaticMemberFunction, "entity.name.function.member.static", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.StaticMemberField, "variable.other.property.static", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Property, "variable.other.property.cli", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Event, "variable.other.event", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.ClassTemplate, "entity.name.type.class.templated", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.GenericType, "entity.name.type.class.generic", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.FunctionTemplate, "entity.name.function.templated", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Namespace, "entity.name.namespace", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.Label, "entity.name.label", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.UdlRaw, "entity.name.operator.custom-literal", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.UdlNumber, "entity.name.operator.custom-literal.number", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.UdlString, "entity.name.operator.custom-literal.string", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.OperatorFunction, "entity.name.function.operator", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.MemberOperator, "entity.name.function.operator.member", themeName, textMateRules);
this.calculateStyleForToken(TokenKind.NewDelete, "keyword.operator.new", themeName, textMateRules);
}
public async loadTheme(themePath: string, defaultStyle: ThemeStyle): Promise<TextMateRule[][]> {
let rules: TextMateRule[][] = [];
if (await util.checkFileExists(themePath)) {
let themeContentText: string = await util.readFileText(themePath);
let themeContent: any;
let textMateRules: TextMateRule[];
if (themePath.endsWith("tmTheme")) {
themeContent = plist.parse(themeContentText);
if (themeContent) {
textMateRules = themeContent.settings;
}
} else {
themeContent = jsonc.parse(themeContentText);
if (themeContent) {
textMateRules = themeContent.tokenColors;
if (themeContent.include) {
// parse included theme file
let includedThemePath: string = path.join(path.dirname(themePath), themeContent.include);
rules = await this.loadTheme(includedThemePath, defaultStyle);
}
if (themeContent.colors && themeContent.colors["editor.background"]) {
this.editorBackground = themeContent.colors["editor.background"];
}
}
}
if (textMateRules) {
// Convert comma delimited scopes into an array
textMateRules.forEach(e => {
if (e.scope && e.scope.includes(',')) {
e.scope = e.scope.split(',').map((s: string) => s.trim());
}
});
let scopelessSetting: any = textMateRules.find(e => e.settings && !e.scope);
if (scopelessSetting) {
if (scopelessSetting.settings.background) {
this.editorBackground = scopelessSetting.settings.background;
}
this.updateStyleFromTextMateRuleSettings(defaultStyle, scopelessSetting.settings);
}
rules.push(textMateRules);
}
}
return rules;
}
public reload(): void {
let f: () => void = async () => {
let otherSettings: OtherSettings = new OtherSettings(this.uri);
let themeName: string = otherSettings.colorTheme;
// Enumerate through all extensions, looking for this theme. (Themes are implemented as extensions - even the default ones)
// Open each package.json to check for a theme path
for (let i: number = 0; i < vscode.extensions.all.length; i++) {
let extensionPath: string = vscode.extensions.all[i].extensionPath;
let extensionPackageJsonPath: string = path.join(extensionPath, "package.json");
if (!await util.checkFileExists(extensionPackageJsonPath)) {
continue;
}
let packageJsonText: string = await util.readFileText(extensionPackageJsonPath);
let packageJson: any = jsonc.parse(packageJsonText);
if (packageJson.contributes && packageJson.contributes.themes) {
let foundTheme: any = packageJson.contributes.themes.find(e => e.id === themeName || e.label === themeName);
if (foundTheme) {
let themeRelativePath: string = foundTheme.path;
let themeFullPath: string = path.join(extensionPath, themeRelativePath);
let defaultStyle: ThemeStyle = new ThemeStyle();
let rulesSet: TextMateRule[][] = await this.loadTheme(themeFullPath, defaultStyle);
this.updateStyles(themeName, defaultStyle, rulesSet);
return;
}
}
}
};
this.syncWithLoadingSettings(f);
}
public static createDecorationFromThemeStyle(themeStyle: ThemeStyle): vscode.TextEditorDecorationType {
if (themeStyle && (themeStyle.foreground || themeStyle.background || themeStyle.fontStyle)) {
let options: vscode.DecorationRenderOptions = {};
options.rangeBehavior = vscode.DecorationRangeBehavior.OpenOpen;
if (themeStyle.foreground) {
options.color = themeStyle.foreground;
}
if (themeStyle.background) {
options.backgroundColor = themeStyle.background;
}
if (themeStyle.fontStyle) {
let parts: string[] = themeStyle.fontStyle.split(" ");
parts.forEach((part) => {
switch (part) {
case "italic":
options.fontStyle = "italic";
break;
case "bold":
options.fontWeight = "bold";
break;
case "underline":
options.textDecoration = "underline";
break;
default:
break;
}
});
}
return vscode.window.createTextEditorDecorationType(options);
}
return null;
}
}
export class ColorizationState {
private uri: vscode.Uri;
private colorizationSettings: ColorizationSettings;
private decorations: vscode.TextEditorDecorationType[] = new Array<vscode.TextEditorDecorationType>(TokenKind.Count);
private semanticRanges: vscode.Range[][] = new Array<vscode.Range[]>(TokenKind.Count);
private inactiveDecoration: vscode.TextEditorDecorationType = null;
private inactiveRanges: vscode.Range[] = [];
private versionedEdits: VersionedEdits[] = [];
private currentSemanticVersion: number = 0;
private lastReceivedSemanticVersion: number = 0;
public constructor(uri: vscode.Uri, colorizationSettings: ColorizationSettings) {
this.uri = uri;
this.colorizationSettings = colorizationSettings;
}
private createColorizationDecorations(isCpp: boolean): void {
let settings: CppSettings = new CppSettings(this.uri);
if (settings.enhancedColorization) {
// Create new decorators
// The first decorator created takes precedence, so these need to be created in reverse order
for (let i: number = TokenKind.Count; i > 0;) {
i--;
let themeStyleMap: any;
if (isCpp) {
themeStyleMap = this.colorizationSettings.themeStyleCppMap;
} else {
themeStyleMap = this.colorizationSettings.themeStyleCMap;
}
this.decorations[i] = ColorizationSettings.createDecorationFromThemeStyle(themeStyleMap[i]);
}
}
if (settings.dimInactiveRegions) {
this.inactiveDecoration = vscode.window.createTextEditorDecorationType({
opacity: settings.inactiveRegionOpacity.toString(),
backgroundColor: settings.inactiveRegionBackgroundColor,
color: settings.inactiveRegionForegroundColor,
rangeBehavior: vscode.DecorationRangeBehavior.OpenOpen
});
}
}
private disposeColorizationDecorations(): void {
// Dispose of all old decorations
if (this.inactiveDecoration) {
this.inactiveDecoration.dispose();
this.inactiveDecoration = null;
}
for (let i: number = 0; i < TokenKind.Count; i++) {
if (this.decorations[i]) {
this.decorations[i].dispose();
this.decorations[i] = null;
}
}
}
public dispose(): void {
this.disposeColorizationDecorations();
}
private refreshInner(e: vscode.TextEditor): void {
let settings: CppSettings = new CppSettings(this.uri);
if (settings.enhancedColorization) {
for (let i: number = 0; i < TokenKind.Count; i++) {
if (this.decorations[i]) {
let ranges: vscode.Range[] = this.semanticRanges[i];
if (ranges && ranges.length > 0) {
e.setDecorations(this.decorations[i], ranges);
}
}
}
}
// Normally, decorators are honored in the order in which they were created, not the
// order in which they were applied. Decorators with opacity appear to be handled
// differently, in that the opacity is applied to overlapping decorators even if
// created afterwards.
if (settings.dimInactiveRegions && this.inactiveDecoration && this.inactiveRanges) {
e.setDecorations(this.inactiveDecoration, this.inactiveRanges);
}
}
public refresh(e: vscode.TextEditor): void {
this.applyEdits();
let f: () => void = async () => {
this.refreshInner(e);
};
this.colorizationSettings.syncWithLoadingSettings(f);
}
public onSettingsChanged(uri: vscode.Uri): void {
let f: () => void = async () => {
this.applyEdits();
this.disposeColorizationDecorations();
let isCpp: boolean = util.isEditorFileCpp(uri.toString());
this.createColorizationDecorations(isCpp);
let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri === uri);
for (let e of editors) {
this.refreshInner(e);
}
};
this.colorizationSettings.syncWithLoadingSettings(f);
}
// Utility function to convert a string and a start Position into a Range
private textToRange(text: string, startPosition: vscode.Position): vscode.Range {
let parts: string[] = text.split("\n");
let addedLines: number = parts.length - 1;
let newStartLine: number = startPosition.line;
let newStartCharacter: number = startPosition.character;
let newEndLine: number = newStartLine + addedLines;
let newEndCharacter: number = parts[parts.length - 1].length;
if (newStartLine === newEndLine) {
newEndCharacter += newStartCharacter;
}
return new vscode.Range(newStartLine, newStartCharacter, newEndLine, newEndCharacter);
}
// Utility function to shift a range back after removing content before it
private shiftRangeAfterRemove(range: vscode.Range, removeStartPosition: vscode.Position, removeEndPosition: vscode.Position): vscode.Range {
let lineDelta: number = removeStartPosition.line - removeEndPosition.line;
let startCharacterDelta: number = 0;
let endCharacterDelta: number = 0;
if (range.start.line === removeEndPosition.line) {
startCharacterDelta = removeStartPosition.character - removeEndPosition.character;
if (range.end.line === removeEndPosition.line) {
endCharacterDelta = startCharacterDelta;
}
}
let newStart: vscode.Position = range.start.translate(lineDelta, startCharacterDelta);
let newEnd: vscode.Position = range.end.translate(lineDelta, endCharacterDelta);
return new vscode.Range(newStart, newEnd);
}
// Utility function to shift a range forward after inserting content before it
private shiftRangeAfterInsert(range: vscode.Range, insertStartPosition: vscode.Position, insertEndPosition: vscode.Position): vscode.Range {
let addedLines: number = insertEndPosition.line - insertStartPosition.line;
let newStartLine: number = range.start.line + addedLines;
let newEndLine: number = range.end.line + addedLines;
let newStartCharacter: number = range.start.character;
let newEndCharacter: number = range.end.character;
// If starts on the same line as replacement ended
if (insertEndPosition.line === newStartLine) {
let endOffsetLength: number = insertEndPosition.character;
// If insertRange starts and ends on the same line, only offset by it's length
if (insertEndPosition.line === insertStartPosition.line) {
endOffsetLength -= insertStartPosition.character;
}
newStartCharacter += endOffsetLength;
if (insertEndPosition.line === newEndLine) {
newEndCharacter += endOffsetLength;
}
}
return new vscode.Range(newStartLine, newStartCharacter, newEndLine, newEndCharacter);
}
// Utility function to adjust a range to account for an insert and/or replace
private fixRange(range: vscode.Range, removeInsertStartPosition: vscode.Position, removeEndPosition: vscode.Position, insertEndPosition: vscode.Position): vscode.Range {
// If the replace/insert starts after this range ends, no adjustment is needed.
if (removeInsertStartPosition.isAfterOrEqual(range.end)) {
return range;
}
// Else, replace/insert range starts before this range ends.
// If replace/insert starts before/where this range starts, we don't need to extend the existing range, but need to shift it
if (removeInsertStartPosition.isBeforeOrEqual(range.start)) {
// If replace consumes the entire range, remove it
if (removeEndPosition.isAfterOrEqual(range.end)) {
return null;
}
// If replace ends within this range, we need to trim it before we shift it
let newRange: vscode.Range;
if (removeEndPosition.isAfterOrEqual(range.start)) {
newRange = new vscode.Range(removeEndPosition, range.end);
} else {
newRange = range;
}
// Else, if replace ends before this range starts, we just need to shift it.
newRange = this.shiftRangeAfterRemove(newRange, removeInsertStartPosition, removeEndPosition);
return this.shiftRangeAfterInsert(newRange, removeInsertStartPosition, insertEndPosition);
}
// Else, if replace/insert starts within (not before or after) range, extend it.
// If there replace/insert overlaps past the end of the original range, just extend existing range to the insert end position
if (removeEndPosition.isAfterOrEqual(range.end)) {
return new vscode.Range(range.start.line, range.start.character, insertEndPosition.line, insertEndPosition.character);
}
// Else, range has some left over at the end, which needs to be shifted after insertEndPosition.
// If the trailing segment is on the last line replace, we just need to extend by the remaining number of characters
if (removeEndPosition.line === range.end.line) {
return new vscode.Range(range.start.line, range.start.character, insertEndPosition.line, insertEndPosition.character + (range.end.character - removeEndPosition.character));
}
// Else, the trailing segment ends on another line, so the character position should remain the same. Just adjust based on added/removed lined.
let removedLines: number = removeEndPosition.line - removeInsertStartPosition.line;
let addedLines: number = insertEndPosition.line - removeInsertStartPosition.line;
let deltaLines: number = addedLines - removedLines;
return new vscode.Range(range.start.line, range.start.character, range.end.line + deltaLines, range.end.character);
}
private fixRanges(originalRanges: vscode.Range[], changes: vscode.TextDocumentContentChangeEvent[]): vscode.Range[] {
// outer loop needs to be the versioned edits, then changes within that edit, then ranges
let ranges: vscode.Range[] = originalRanges;
if (ranges && ranges.length > 0) {
changes.forEach((change) => {
let newRanges: vscode.Range[] = [];
let insertRange: vscode.Range = this.textToRange(change.text, change.range.start);
for (let i: number = 0; i < ranges.length; i++) {
let newRange: vscode.Range = this.fixRange(ranges[i], change.range.start, change.range.end, insertRange.end);
if (newRange !== null) {
newRanges.push(newRange);
}
}
ranges = newRanges;
});
}
return ranges;
}
// Add edits to be applied when/if cached tokens need to be reapplied.
public addEdits(changes: vscode.TextDocumentContentChangeEvent[], editVersion: number): void {
let edits: VersionedEdits = {
editVersion: editVersion,
changes: changes
};
this.versionedEdits.push(edits);
}
// Apply any pending edits to the currently cached tokens
private applyEdits() : void {
this.versionedEdits.forEach((edit) => {
if (edit.editVersion > this.currentSemanticVersion) {
for (let i: number = 0; i < TokenKind.Count; i++) {
this.semanticRanges[i] = this.fixRanges(this.semanticRanges[i], edit.changes);
}
this.inactiveRanges = this.fixRanges(this.inactiveRanges, edit.changes);
this.currentSemanticVersion = edit.editVersion;
}
});
}
// Remove any edits from the list if we will never receive tokens that old.
private purgeOldVersionedEdits(): void {
let minVersion: number = this.lastReceivedSemanticVersion;
let index: number = this.versionedEdits.findIndex((edit) => edit.editVersion > minVersion);
if (index === -1) {
this.versionedEdits = [];
} else if (index > 0) {
this.versionedEdits = this.versionedEdits.slice(index);
}
}
private updateColorizationRanges(uri: string): void {
let f: () => void = async () => {
this.applyEdits();
this.purgeOldVersionedEdits();
// The only way to un-apply decorators is to dispose them.
// If we dispose old decorators before applying new decorators, we see a flicker on Mac,
// likely due to a race with UI updates. Here we set aside the existing decorators to be
// disposed of after the new decorators have been applied, so there is not a gap
// in which decorators are not applied.
let oldInactiveDecoration: vscode.TextEditorDecorationType = this.inactiveDecoration;
let oldDecorations: vscode.TextEditorDecorationType[] = this.decorations;
this.inactiveDecoration = null;
this.decorations = new Array<vscode.TextEditorDecorationType>(TokenKind.Count);
let isCpp: boolean = util.isEditorFileCpp(uri);
this.createColorizationDecorations(isCpp);
// Apply the decorations to all *visible* text editors
let editors: vscode.TextEditor[] = vscode.window.visibleTextEditors.filter(e => e.document.uri.toString() === uri);
for (let e of editors) {
this.refreshInner(e);
}
// Dispose of the old decorators only after the new ones have been applied.
if (oldInactiveDecoration) {
oldInactiveDecoration.dispose();
}
if (oldDecorations) {
for (let i: number = 0; i < TokenKind.Count; i++) {
if (oldDecorations[i]) {
oldDecorations[i].dispose();
}
}
}
};
this.colorizationSettings.syncWithLoadingSettings(f);
}
public updateSemantic(uri: string, semanticRanges: vscode.Range[][], inactiveRanges: vscode.Range[], editVersion: number): void {
this.inactiveRanges = inactiveRanges;
for (let i: number = 0; i < TokenKind.Count; i++) {
this.semanticRanges[i] = semanticRanges[i];
}
this.currentSemanticVersion = editVersion;
this.lastReceivedSemanticVersion = editVersion;
this.updateColorizationRanges(uri);
}
}
+227 -159
View File
@@ -68,6 +68,11 @@ export interface ConfigurationErrors {
compilerPath?: string;
includePath?: string;
intelliSenseMode?: string;
macFrameworkPath?: string;
forcedInclude?: string;
compileCommands?: string;
browsePath?: string;
databaseFilename?: string;
}
export interface Browse {
@@ -227,22 +232,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();
}
@@ -273,53 +262,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;
}
}
@@ -397,26 +390,26 @@ 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.compilerName === "cl.exe") === (configuration.intelliSenseMode === "msvc-x64");
}
public addToIncludePathCommand(path: string): void {
this.handleConfigurationEditCommand(() => {
telemetry.logLanguageServerEvent("addToIncludePath");
this.parsePropertiesFile(true); // Clear out any modifications we may have made internally.
this.parsePropertiesFile(); // Clear out any modifications we may have made internally.
let config: Configuration = this.CurrentConfiguration;
if (config.includePath === undefined) {
config.includePath = ["${default}"];
@@ -431,7 +424,7 @@ export class CppProperties {
return new Promise<void>((resolve) => {
if (this.propertiesFile) {
this.handleConfigurationEditJSONCommand(() => {
this.parsePropertiesFile(true); // Clear out any modifications we may have made internally.
this.parsePropertiesFile(); // Clear out any modifications we may have made internally.
let config: Configuration = this.CurrentConfiguration;
if (providerId) {
config.configurationProvider = providerId;
@@ -457,7 +450,7 @@ export class CppProperties {
public setCompileCommands(path: string): void {
this.handleConfigurationEditJSONCommand(() => {
this.parsePropertiesFile(true); // Clear out any modifications we may have made internally.
this.parsePropertiesFile(); // Clear out any modifications we may have made internally.
let config: Configuration = this.CurrentConfiguration;
config.compileCommands = path;
this.writeToJson();
@@ -635,23 +628,33 @@ export class CppProperties {
});
}
private ensureSettingsPanelInitlialized(): void {
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.settingsPanel.ConfigSelectionChanged(() => this.onConfigSelectionChanged());
this.settingsPanel.AddConfigRequested((e) => this.onAddConfigRequested(e));
this.disposables.push(this.settingsPanel);
}
}
public handleConfigurationEditUICommand(onCreation: () => void, showDocument: (document: vscode.TextDocument) => void): void {
this.ensurePropertiesFile().then(() => {
if (this.propertiesFile) {
if (onCreation) {
onCreation();
}
if (this.parsePropertiesFile(false)) {
// Parse successful, show UI
if (this.settingsPanel === undefined) {
this.settingsPanel = new SettingsPanel();
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());
if (this.parsePropertiesFile()) {
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) => {
@@ -668,12 +671,15 @@ export class CppProperties {
if (this.configurationJson) {
this.ensurePropertiesFile().then(() => {
if (this.propertiesFile) {
if (this.parsePropertiesFile(false)) {
if (this.parsePropertiesFile()) {
// 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);
@@ -684,10 +690,35 @@ export class CppProperties {
}
private saveConfigurationUI(): void {
this.parsePropertiesFile(false); // Clear out any modifications we may have made internally.
this.parsePropertiesFile(); // 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();
}
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(); // Clear out any modifications we may have made internally.
// 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);
// Update UI
this.settingsPanel.selectedConfigIndex = this.configurationJson.configurations.length - 1;
this.settingsPanel.updateConfigUI(this.ConfigurationNames,
this.configurationJson.configurations[this.settingsPanel.selectedConfigIndex],
null);
// Save new config to file
this.writeToJson();
}
@@ -697,7 +728,7 @@ export class CppProperties {
}
this.configFileWatcherFallbackTime = new Date();
if (this.propertiesFile) {
this.parsePropertiesFile(true);
this.parsePropertiesFile();
// parsePropertiesFile can fail, but it won't overwrite an existing configurationJson in the event of failure.
// this.configurationJson should only be undefined here if we have never successfully parsed the propertiesFile.
if (this.configurationJson) {
@@ -753,7 +784,7 @@ export class CppProperties {
return;
}
private parsePropertiesFile(handleSquiggles: boolean): boolean {
private parsePropertiesFile(): boolean {
let success: boolean = true;
try {
let readResults: string = fs.readFileSync(this.propertiesFile.fsPath, 'utf8');
@@ -761,11 +792,6 @@ export class CppProperties {
return; // Repros randomly when the file is initially created. The parse will get called again after the file is written.
}
if (handleSquiggles) {
// Replace all \<escape character> with \\<character>, except for \"
// Otherwise, the JSON.parse result will have the \<escape character> missing.
readResults = util.escapeForSquiggles(readResults);
}
// Try to use the same configuration as before the change.
let newJson: ConfigurationJson = JSON.parse(readResults);
if (!newJson || !newJson.configurations || newJson.configurations.length === 0) {
@@ -839,7 +865,7 @@ export class CppProperties {
success = false;
}
if (handleSquiggles && success) {
if (success) {
this.handleSquiggles();
}
@@ -883,16 +909,17 @@ 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.
!(isWindows && compilerPathAndArgs.compilerPath.endsWith("cl.exe"))) {
!(isWindows && compilerPathAndArgs.compilerName === "cl.exe")) {
resolvedCompilerPath = resolvedCompilerPath.trim();
// Error when the compiler's path has spaces without quotes but args are used.
@@ -931,10 +958,13 @@ export class CppProperties {
}
}
}
if (!pathExists) {
let message: string = `Cannot find: ${resolvedCompilerPath}`;
compilerPathErrors.push(message);
} else if (compilerPathAndArgs.compilerPath === "") {
let message: string = `Invalid input, cannot resolve compiler path`;
compilerPathErrors.push(message);
} else if (!util.checkFileExistsSync(resolvedCompilerPath)) {
let message: string = `Path is not a file: ${resolvedCompilerPath}`;
compilerPathErrors.push(message);
@@ -945,53 +975,81 @@ export class CppProperties {
}
}
// Validate includePath
let includePathErrors: string[] = [];
if (this.CurrentConfiguration.includePath) {
for (let includePath of this.CurrentConfiguration.includePath) {
let pathExists: boolean = true;
let resolvedIncludePath: string = this.resolvePath(includePath, isWindows);
if (!resolvedIncludePath) {
continue;
}
// Validate paths (directories)
errors.includePath = this.validatePath(config.includePath);
errors.macFrameworkPath = this.validatePath(config.macFrameworkPath);
errors.browsePath = this.validatePath(config.browse ? config.browse.path : undefined);
// Check if resolved path exists
if (!fs.existsSync(resolvedIncludePath)) {
// Check for relative path if resolved path does not exists
const relativePath: string = this.rootUri.fsPath + path.sep + resolvedIncludePath;
if (!fs.existsSync(relativePath)) {
pathExists = false;
} else {
resolvedIncludePath = relativePath;
}
}
if (!pathExists) {
let message: string = `Cannot find: ${resolvedIncludePath}`;
includePathErrors.push(message);
continue;
}
// Check if path is a directory
if (!util.checkDirectoryExistsSync(resolvedIncludePath)) {
let message: string = `Path is not a directory: ${resolvedIncludePath}`;
includePathErrors.push(message);
}
}
if (includePathErrors.length > 0) {
errors.includePath = includePathErrors.join('\n');
}
}
// Validate files
errors.forcedInclude = this.validatePath(config.forcedInclude, false);
errors.compileCommands = this.validatePath(config.compileCommands, false);
errors.databaseFilename = this.validatePath((config.browse ? config.browse.databaseFilename : undefined), false);
// 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;
}
private validatePath(input: string|string[], isDirectory: boolean = true): string {
if (!input) {
return undefined;
}
const isWindows: boolean = os.platform() === 'win32';
let errorMsg: string = undefined;
let errors: string[] = [];
let paths: string[] = [];
if (util.isString(input)) {
paths.push(input);
} else {
paths = input;
}
for (let p of paths) {
let pathExists: boolean = true;
let resolvedPath: string = this.resolvePath(p, isWindows);
if (!resolvedPath) {
continue;
}
// Check if resolved path exists
if (!fs.existsSync(resolvedPath)) {
// Check for relative path if resolved path does not exists
const relativePath: string = this.rootUri.fsPath + path.sep + resolvedPath;
if (!fs.existsSync(relativePath)) {
pathExists = false;
} else {
resolvedPath = relativePath;
}
}
if (!pathExists) {
let message: string = `Cannot find: ${resolvedPath}`;
errors.push(message);
continue;
}
// Check if path is a directory or file
if (isDirectory && !util.checkDirectoryExistsSync(resolvedPath)) {
let message: string = `Path is not a directory: ${resolvedPath}`;
errors.push(message);
} else if (!isDirectory && !util.checkFileExistsSync(resolvedPath)) {
let message: string = `Path is not a file: ${resolvedPath}`;
errors.push(message);
}
}
if (errors.length > 0) {
errorMsg = errors.join('\n');
}
return errorMsg;
}
private handleSquiggles(): void {
if (!this.propertiesFile) {
return;
@@ -1013,11 +1071,18 @@ export class CppProperties {
// Get the text of the current configuration.
let curText: string = document.getText();
// Replace all \<escape character> with \\<character>, except for \"
// Otherwise, the JSON.parse result will have the \<escape character> missing.
let configurationsText: string = util.escapeForSquiggles(curText);
let configurations: ConfigurationJson = JSON.parse(configurationsText);
let currentConfiguration: Configuration = configurations.configurations[this.CurrentConfigurationIndex];
let curTextStartOffset: number = 0;
if (!this.CurrentConfiguration.name) {
if (!currentConfiguration.name) {
return;
}
const configStart: number = curText.search(new RegExp(`{\\s*"name"\\s*:\\s*"${escapeStringRegExp(this.CurrentConfiguration.name)}"`));
const configStart: number = curText.search(new RegExp(`{\\s*"name"\\s*:\\s*"${escapeStringRegExp(currentConfiguration.name)}"`));
if (configStart === -1) {
telemetry.logLanguageServerEvent("ConfigSquiggles", { "error": "config name not first" });
return;
@@ -1037,8 +1102,8 @@ export class CppProperties {
}
curText = curText.substr(0, nextNameStart2);
}
if (this.prevSquiggleMetrics[this.CurrentConfiguration.name] === undefined) {
this.prevSquiggleMetrics[this.CurrentConfiguration.name] = { PathNonExistent: 0, PathNotAFile: 0, PathNotADirectory: 0, CompilerPathMissingQuotes: 0, CompilerModeMismatch: 0 };
if (this.prevSquiggleMetrics[currentConfiguration.name] === undefined) {
this.prevSquiggleMetrics[currentConfiguration.name] = { PathNonExistent: 0, PathNotAFile: 0, PathNotADirectory: 0, CompilerPathMissingQuotes: 0, CompilerModeMismatch: 0 };
}
let newSquiggleMetrics: { [key: string]: number } = { PathNonExistent: 0, PathNotAFile: 0, PathNotADirectory: 0, CompilerPathMissingQuotes: 0, CompilerModeMismatch: 0 };
const isWindows: boolean = os.platform() === 'win32';
@@ -1053,8 +1118,8 @@ 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()) {
let message: string = `intelliSenseMode ${this.CurrentConfiguration.intelliSenseMode} is incompatible with compilerPath.`;
if (!this.isCompilerIntelliSenseModeCompatible(currentConfiguration)) {
let message: string = `intelliSenseMode ${currentConfiguration.intelliSenseMode} is incompatible with compilerPath.`;
let diagnostic: vscode.Diagnostic = new vscode.Diagnostic(
new vscode.Range(document.positionAt(curTextStartOffset + intelliSenseModeValueStart),
document.positionAt(curTextStartOffset + intelliSenseModeValueEnd)),
@@ -1067,21 +1132,21 @@ export class CppProperties {
// Check for path-related squiggles.
let paths: Set<string> = new Set<string>();
for (let pathArray of [ (this.CurrentConfiguration.browse ? this.CurrentConfiguration.browse.path : undefined),
this.CurrentConfiguration.includePath, this.CurrentConfiguration.macFrameworkPath, this.CurrentConfiguration.forcedInclude ] ) {
for (let pathArray of [ (currentConfiguration.browse ? currentConfiguration.browse.path : undefined),
currentConfiguration.includePath, currentConfiguration.macFrameworkPath, currentConfiguration.forcedInclude ] ) {
if (pathArray) {
for (let curPath of pathArray) {
paths.add(`${curPath}`);
}
}
}
if (this.CurrentConfiguration.compileCommands) {
paths.add(`${this.CurrentConfiguration.compileCommands}`);
if (currentConfiguration.compileCommands) {
paths.add(`${currentConfiguration.compileCommands}`);
}
if (this.CurrentConfiguration.compilerPath) {
if (currentConfiguration.compilerPath) {
// Unlike other cases, compilerPath may not start or end with " due to trimming of whitespace and the possibility of compiler args.
paths.add(`${this.CurrentConfiguration.compilerPath}`);
paths.add(`${currentConfiguration.compilerPath}`);
}
// Get the start/end for properties that are file-only.
@@ -1093,7 +1158,7 @@ export class CppProperties {
const compilerPathEnd: number = compilerPathStart === -1 ? -1 : curText.indexOf('"', curText.indexOf('"', curText.indexOf(":", compilerPathStart)) + 1) + 1;
for (let curPath of paths) {
const isCompilerPath: boolean = curPath === this.CurrentConfiguration.compilerPath;
const isCompilerPath: boolean = curPath === currentConfiguration.compilerPath;
// Resolve special path cases.
if (curPath === "${default}") {
// TODO: Add squiggles for when the C_Cpp.default.* paths are invalid.
@@ -1111,7 +1176,7 @@ export class CppProperties {
if (isCompilerPath) {
resolvedPath = resolvedPath.trim();
let compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(resolvedPath);
if (isWindows && compilerPathAndArgs.compilerPath.endsWith("cl.exe")) {
if (isWindows && compilerPathAndArgs.compilerName === "cl.exe") {
continue; // Don't squiggle invalid cl.exe paths because it could be for an older preview build.
}
// Squiggle when the compiler's path has spaces without quotes but args are used.
@@ -1158,7 +1223,7 @@ export class CppProperties {
// Create a pattern to search for the path with either a quote or semicolon immediately before and after,
// and extend that pattern to the next quote before and next quote after it.
let pattern: RegExp = new RegExp(`"[^"]*?(?<="|;)${escapedPath}(?="|;).*?"`);
let pattern: RegExp = new RegExp(`"[^"]*?(?<="|;)${escapedPath}(?="|;).*?"`, "g");
let matches: string[] = curText.match(pattern);
if (matches) {
let curOffset: number = 0;
@@ -1209,22 +1274,25 @@ export class CppProperties {
// Send telemetry on squiggle changes.
let changedSquiggleMetrics: { [key: string]: number } = {};
if (newSquiggleMetrics.PathNonExistent !== this.prevSquiggleMetrics[this.CurrentConfiguration.name].PathNonExistent) {
if (newSquiggleMetrics.PathNonExistent !== this.prevSquiggleMetrics[currentConfiguration.name].PathNonExistent) {
changedSquiggleMetrics.PathNonExistent = newSquiggleMetrics.PathNonExistent;
}
if (newSquiggleMetrics.PathNotAFile !== this.prevSquiggleMetrics[this.CurrentConfiguration.name].PathNotAFile) {
if (newSquiggleMetrics.PathNotAFile !== this.prevSquiggleMetrics[currentConfiguration.name].PathNotAFile) {
changedSquiggleMetrics.PathNotAFile = newSquiggleMetrics.PathNotAFile;
}
if (newSquiggleMetrics.PathNotADirectory !== this.prevSquiggleMetrics[this.CurrentConfiguration.name].PathNotADirectory) {
if (newSquiggleMetrics.PathNotADirectory !== this.prevSquiggleMetrics[currentConfiguration.name].PathNotADirectory) {
changedSquiggleMetrics.PathNotADirectory = newSquiggleMetrics.PathNotADirectory;
}
if (newSquiggleMetrics.CompilerPathMissingQuotes !== this.prevSquiggleMetrics[this.CurrentConfiguration.name].CompilerPathMissingQuotes) {
if (newSquiggleMetrics.CompilerPathMissingQuotes !== this.prevSquiggleMetrics[currentConfiguration.name].CompilerPathMissingQuotes) {
changedSquiggleMetrics.CompilerPathMissingQuotes = newSquiggleMetrics.CompilerPathMissingQuotes;
}
if (newSquiggleMetrics.CompilerModeMismatch !== this.prevSquiggleMetrics[currentConfiguration.name].CompilerModeMismatch) {
changedSquiggleMetrics.CompilerModeMismatch = newSquiggleMetrics.CompilerModeMismatch;
}
if (Object.keys(changedSquiggleMetrics).length > 0) {
telemetry.logLanguageServerEvent("ConfigSquiggles", null, changedSquiggleMetrics);
}
this.prevSquiggleMetrics[this.CurrentConfiguration.name] = newSquiggleMetrics;
this.prevSquiggleMetrics[currentConfiguration.name] = newSquiggleMetrics;
});
}
+51 -6
View File
@@ -326,6 +326,7 @@ function realActivation(): void {
disposables.push(vscode.window.onDidChangeActiveTextEditor(onDidChangeActiveTextEditor));
disposables.push(vscode.window.onDidChangeTextEditorSelection(onDidChangeTextEditorSelection));
disposables.push(vscode.window.onDidChangeVisibleTextEditors(onDidChangeVisibleTextEditors));
disposables.push(vscode.window.onDidChangeTextEditorVisibleRanges(onDidChangeTextEditorVisibleRanges));
updateLanguageConfigurations();
@@ -355,9 +356,14 @@ export function updateLanguageConfigurations(): void {
* workspace events
*********************************************/
function onDidChangeSettings(): void {
const changedActiveClientSettings: { [key: string] : string } = clients.ActiveClient.onDidChangeSettings();
clients.forEach(client => client.onDidChangeSettings());
function onDidChangeSettings(event: vscode.ConfigurationChangeEvent): void {
let activeClient: Client = clients.ActiveClient;
const changedActiveClientSettings: { [key: string] : string } = activeClient.onDidChangeSettings(event);
clients.forEach(client => {
if (client !== activeClient) {
client.onDidChangeSettings(event);
}
});
const newUpdateChannel: string = changedActiveClientSettings['updateChannel'];
if (newUpdateChannel) {
@@ -418,7 +424,30 @@ function onDidChangeTextEditorSelection(event: vscode.TextEditorSelectionChangeE
}
function onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
clients.forEach(client => client.onDidChangeVisibleTextEditors(editors));
clients.forEach(client => {
let editorsForThisClient: vscode.TextEditor[] = [];
editors.forEach(editor => {
if (editor.document.languageId === "c" || editor.document.languageId === "cpp") {
if (clients.checkOwnership(client, editor.document)) {
editorsForThisClient.push(editor);
}
}
});
if (editorsForThisClient.length > 0) {
client.onDidChangeVisibleTextEditors(editorsForThisClient);
}
});
}
function onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent: vscode.TextEditorVisibleRangesChangeEvent): void {
let languageId: String = textEditorVisibleRangesChangeEvent.textEditor.document.languageId;
if (languageId === "c" || languageId === "cpp") {
clients.forEach(client => {
if (clients.checkOwnership(client, textEditorVisibleRangesChangeEvent.textEditor.document)) {
client.onDidChangeTextEditorVisibleRanges(textEditorVisibleRangesChangeEvent);
}
});
}
}
function onInterval(): void {
@@ -694,6 +723,7 @@ export function registerCommands(): void {
disposables.push(vscode.commands.registerCommand('C_Cpp.ShowParsingCommands', onShowParsingCommands));
disposables.push(vscode.commands.registerCommand('C_Cpp.TakeSurvey', onTakeSurvey));
disposables.push(vscode.commands.registerCommand('C_Cpp.LogDiagnostics', onLogDiagnostics));
disposables.push(vscode.commands.registerCommand('C_Cpp.RescanWorkspace', onRescanWorkspace));
disposables.push(vscode.commands.registerCommand('cpptools.activeConfigName', onGetActiveConfigName));
getTemporaryCommandRegistrarInstance().executeDelayedCommands();
}
@@ -912,6 +942,11 @@ function onLogDiagnostics(): void {
clients.ActiveClient.logDiagnostics();
}
function onRescanWorkspace(): void {
onActivationEvent();
clients.forEach(client => client.rescanFolder());
}
function reportMacCrashes(): void {
if (process.platform === "darwin") {
prevCrashFile = "";
@@ -968,6 +1003,16 @@ function handleCrashFileRead(err: NodeJS.ErrnoException, data: string): void {
return logCrashTelemetry("readFile: " + err.code);
}
// Extract the crashing process version, because the version might not match
// if multiple VS Codes are running with different extension versions.
let binaryVersion: string = "";
let startVersion: number = data.indexOf("Version:");
if (startVersion >= 0) {
data = data.substr(startVersion);
const binaryVersionMatches: string[] = data.match(/^Version:\s*(\d|\d*\.\d*\.\d*\.\d*)/);
binaryVersion = binaryVersionMatches && binaryVersionMatches.length > 1 ? binaryVersionMatches[1] : "";
}
// Extract the crashing thread's call stack.
const crashStart: string = " Crashed:";
let startCrash: number = data.indexOf(crashStart);
@@ -993,10 +1038,10 @@ function handleCrashFileRead(err: NodeJS.ErrnoException, data: string): void {
const process2: string = "Microsoft.VSCode.CPP.Extension.darwin\t";
if (data.includes(process1)) {
data = data.replace(new RegExp(process1, "g"), "");
data = process1 + "\n" + data;
data = `${process1}${binaryVersion}\n${data}`;
} else if (data.includes(process2)) {
data = data.replace(new RegExp(process2, "g"), "");
data = process2 + "\n" + data;
data = `${process2}${binaryVersion}\n${data}`;
} else {
return logCrashTelemetry("No process"); // Not expected, but just in case.
}
@@ -32,14 +32,17 @@ export function createProtocolFilter(me: Client, clients: ClientCollection): Mid
me.addFileAssociations(mappingString, false);
}
me.provideCustomConfiguration(document).then(() => {
sendMessage(document);
}, () => {
sendMessage(document);
});
me.onDidOpenTextDocument(document);
me.provideCustomConfiguration(document);
me.notifyWhenReady(() => sendMessage(document));
}
},
didChange: (textDocumentChangeEvent, sendMessage) => {
if (clients.ActiveClient === me) {
me.onDidChangeTextDocument(textDocumentChangeEvent);
me.notifyWhenReady(() => sendMessage(textDocumentChangeEvent));
}
},
didChange: defaultHandler,
willSave: defaultHandler,
willSaveWaitUntil: (event, sendMessage) => {
if (clients.ActiveClient === me) {
+32 -2
View File
@@ -42,7 +42,6 @@ export class CppSettings extends Settings {
public get intelliSenseCachePath(): string { return super.Section.get<string>("intelliSenseCachePath"); }
public get intelliSenseCacheSize(): number { return super.Section.get<number>("intelliSenseCacheSize"); }
public get errorSquiggles(): string { return super.Section.get<string>("errorSquiggles"); }
public get dimInactiveRegions(): boolean { return super.Section.get<boolean>("dimInactiveRegions"); }
public get inactiveRegionOpacity(): number { return super.Section.get<number>("inactiveRegionOpacity"); }
public get inactiveRegionForegroundColor(): string { return super.Section.get<string>("inactiveRegionForegroundColor"); }
public get inactiveRegionBackgroundColor(): string { return super.Section.get<string>("inactiveRegionBackgroundColor"); }
@@ -74,6 +73,18 @@ export class CppSettings extends Settings {
public get defaultSystemIncludePath(): string[] { return super.Section.get<string[]>("default.systemIncludePath"); }
public get defaultEnableConfigurationSquiggles(): boolean { return super.Section.get<boolean>("default.enableConfigurationSquiggles"); }
public get enhancedColorization(): boolean {
return super.Section.get<string>("enhancedColorization") === "Enabled"
&& super.Section.get<string>("intelliSenseEngine") === "Default"
&& vscode.workspace.getConfiguration("workbench").get<string>("colorTheme") !== "Default High Contrast";
}
public get dimInactiveRegions(): boolean {
return super.Section.get<boolean>("dimInactiveRegions")
&& super.Section.get<string>("intelliSenseEngine") === "Default"
&& vscode.workspace.getConfiguration("workbench").get<string>("colorTheme") !== "Default High Contrast";
}
public toggleSetting(name: string, value1: string, value2: string): void {
let value: string = super.Section.get<string>(name);
super.Section.update(name, value === value1 ? value2 : value1, getTarget());
@@ -83,6 +94,17 @@ export class CppSettings extends Settings {
}
}
export interface TextMateRuleSettings {
foreground: string | undefined;
background: string | undefined;
fontStyle: string | undefined;
}
export interface TextMateRule {
scope: any;
settings: TextMateRuleSettings;
}
export class OtherSettings {
private resource: vscode.Uri;
@@ -99,7 +121,15 @@ export class OtherSettings {
public get searchExclude(): vscode.WorkspaceConfiguration { return vscode.workspace.getConfiguration("search", this.resource).get("exclude"); }
public get settingsEditor(): string { return vscode.workspace.getConfiguration("workbench.settings").get<string>("editor"); }
public get colorTheme(): string { return vscode.workspace.getConfiguration("workbench").get<string>("colorTheme"); }
public getCustomColorToken(colorTokenName: string): string { return vscode.workspace.getConfiguration("editor.tokenColorCustomizations").get<string>(colorTokenName); }
public getCustomThemeSpecificColorToken(themeName: string, colorTokenName: string): string { return vscode.workspace.getConfiguration(`editor.tokenColorCustomizations.[${themeName}]`, this.resource).get<string>(colorTokenName); }
public get customTextMateRules(): TextMateRule[] { return vscode.workspace.getConfiguration("editor.tokenColorCustomizations").get<TextMateRule[]>("textMateRules"); }
public getCustomThemeSpecificTextMateRules(themeName: string): TextMateRule[] { return vscode.workspace.getConfiguration(`editor.tokenColorCustomizations.[${themeName}]`, this.resource).get<TextMateRule[]>("textMateRules"); }
public set filesAssociations(value: any) {
vscode.workspace.getConfiguration("files", null).update("associations", value, vscode.ConfigurationTarget.Workspace);
}
}
}
+174 -21
View File
@@ -9,25 +9,64 @@ import * as fs from 'fs';
import * as vscode from 'vscode';
import * as util from '../common';
import * as config from './configurations';
import * as telemetry from '../telemetry';
// TODO: share ElementId between SettingsPanel and SettingsApp. Investigate why SettingsApp cannot import/export
const elementId: { [key: string]: string } = {
activeConfig: "activeConfig",
// 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",
// Advanced 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 {
private configValues: config.Configuration;
private isIntelliSenseModeDefined: boolean = false;
private telemetry: { [key: string]: number } = {};
private disposable: vscode.Disposable = undefined;
// Events
private settingsPanelActivated = new vscode.EventEmitter<void>();
private configValuesChanged = new vscode.EventEmitter<void>();
private configSelectionChanged = new vscode.EventEmitter<void>();
private addConfigRequested = new vscode.EventEmitter<string>();
// Configuration data
private configValues: config.Configuration;
private isIntelliSenseModeDefined: boolean = false;
private configIndexSelected: number = 0;
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';
@@ -36,11 +75,13 @@ export class SettingsPanel {
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;
@@ -80,7 +121,7 @@ export class SettingsPanel {
this.panel.webview.html = this.getHtml();
this.updateWebview(activeConfiguration, errors);
this.updateWebview(configSelection, activeConfiguration, errors);
}
public get SettingsPanelActivated(): vscode.Event<void> {
@@ -91,13 +132,47 @@ export class SettingsPanel {
return this.configValuesChanged.event;
}
public get ConfigSelectionChanged(): vscode.Event<void> {
return this.configSelectionChanged.event;
}
public get AddConfigRequested(): vscode.Event<string> {
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);
}
}
public setKnownCompilers(knownCompilers: config.KnownCompiler[], pathSeparator: string): void {
if (knownCompilers.length > 0) {
for (let compiler of knownCompilers) {
// Normalize path separators.
let path: string = compiler.path;
if (pathSeparator === "Forward Slash") {
path = path.replace(/\\/g, '/');
} else {
path = path.replace(/\//g, '\\');
}
// Do not add duplicate paths in case the default compilers for cpp and c are the same.
if (this.compilerPaths.indexOf(path) === -1) {
this.compilerPaths.push(path);
}
}
}
}
@@ -108,6 +183,11 @@ export class SettingsPanel {
}
public dispose(): void {
// Log any telemetry
if (Object.keys(this.telemetry).length > 0) {
telemetry.logLanguageServerEvent("ConfigUI", null, this.telemetry);
}
// Clean up resources
this.panel.dispose();
@@ -127,13 +207,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) {
// Send a message to the webview to update the values and errors
this.panel.webview.postMessage({ command: 'updateConfig', config: this.configValues});
this.panel.webview.postMessage({ command: 'updateErrors', errors: errors});
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});
if (errors !== null) {
this.panel.webview.postMessage({ command: 'updateErrors', errors: errors});
}
}
}
@@ -156,26 +239,55 @@ 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;
case 'knownCompilerSelect':
this.knownCompilerSelect();
break;
}
}
private addConfig(name: string): void {
this.addConfigRequested.fire(name);
this.logTelemetryForElement(elementId.addConfigName);
}
private configSelect(index: number): void {
this.configIndexSelected = index;
this.configSelectionChanged.fire();
this.logTelemetryForElement(elementId.configSelection);
}
private knownCompilerSelect(): void {
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]--;
}
}
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.activeConfig:
case elementId.configName:
this.configValues.name = message.value;
break;
case elementId.compilerPath:
this.configValues.compilerPath = message.value;
break;
case elementId.includePath:
entries = message.value.split("\n");
this.configValues.includePath = entries.filter(e => e);
this.configValues.includePath = splitEntries(message.value);
break;
case elementId.defines:
entries = message.value.split("\n");
this.configValues.defines = entries.filter(e => e);
this.configValues.defines = splitEntries(message.value);
break;
case elementId.intelliSenseMode:
if (message.value !== "${default}" || this.isIntelliSenseModeDefined) {
@@ -190,9 +302,50 @@ export class SettingsPanel {
case elementId.cppStandard:
this.configValues.cppStandard = message.value;
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;
break;
case elementId.databaseFilename:
this.initializeBrowseProperties();
this.configValues.browse.databaseFilename = message.value;
break;
}
this.configValuesChanged.fire();
this.logTelemetryForElement(message.key);
}
private logTelemetryForElement(elementId: string): void {
if (this.telemetry[elementId] === undefined) {
this.telemetry[elementId] = 0;
}
this.telemetry[elementId]++;
}
private initializeBrowseProperties(): void {
if (this.configValues.browse === undefined) {
this.configValues.browse = {};
}
}
private getHtml(): string {
+13 -3
View File
@@ -17,6 +17,7 @@ interface Settings {
defaultIntelliSenseEngine?: number;
recursiveIncludes?: number;
gotoDefIntelliSense?: number;
enhancedColorization?: number;
}
export class ABTestSettings {
@@ -24,16 +25,19 @@ export class ABTestSettings {
private intelliSenseEngineDefault: PersistentState<number>;
private recursiveIncludesDefault: PersistentState<number>;
private gotoDefIntelliSenseDefault: PersistentState<number>;
private enhancedColorizationDefault: PersistentState<number>;
private bucket: PersistentState<number>;
constructor() {
this.intelliSenseEngineDefault = new PersistentState<number>("ABTest.1", 100);
this.recursiveIncludesDefault = new PersistentState<number>("ABTest.2", 100);
this.gotoDefIntelliSenseDefault = new PersistentState<number>("ABTest.3", 100);
this.enhancedColorizationDefault = new PersistentState<number>("ABTest.4", 100);
this.settings = {
defaultIntelliSenseEngine: this.intelliSenseEngineDefault.Value,
recursiveIncludes: this.recursiveIncludesDefault.Value,
gotoDefIntelliSense: this.gotoDefIntelliSenseDefault.Value
gotoDefIntelliSense: this.gotoDefIntelliSenseDefault.Value,
enhancedColorization: this.enhancedColorizationDefault.Value
};
this.bucket = new PersistentState<number>(userBucketString, -1);
if (this.bucket.Value === -1) {
@@ -61,6 +65,10 @@ export class ABTestSettings {
return util.isNumber(this.settings.gotoDefIntelliSense) ? this.settings.gotoDefIntelliSense >= this.bucket.Value : true;
}
public get UseEnhancedColorization(): boolean {
return util.isNumber(this.settings.enhancedColorization) ? this.settings.enhancedColorization >= this.bucket.Value : true;
}
private updateSettings(): void {
const cpptoolsJsonFile: string = util.getExtensionFilePath(localConfigFile);
@@ -72,10 +80,12 @@ export class ABTestSettings {
this.intelliSenseEngineDefault.Value = util.isNumber(newSettings.defaultIntelliSenseEngine) ? newSettings.defaultIntelliSenseEngine : this.intelliSenseEngineDefault.DefaultValue;
this.recursiveIncludesDefault.Value = util.isNumber(newSettings.recursiveIncludes) ? newSettings.recursiveIncludes : this.recursiveIncludesDefault.DefaultValue;
this.gotoDefIntelliSenseDefault.Value = util.isNumber(newSettings.gotoDefIntelliSense) ? newSettings.gotoDefIntelliSense : this.gotoDefIntelliSenseDefault.DefaultValue;
this.enhancedColorizationDefault.Value = util.isNumber(newSettings.enhancedColorization) ? newSettings.enhancedColorization : this.enhancedColorizationDefault.DefaultValue;
this.settings = {
defaultIntelliSenseEngine: this.intelliSenseEngineDefault.Value,
recursiveIncludes: this.recursiveIncludesDefault.Value,
gotoDefIntelliSense: this.gotoDefIntelliSenseDefault.Value
gotoDefIntelliSense: this.gotoDefIntelliSenseDefault.Value,
enhancedColorization: this.enhancedColorizationDefault.Value
};
}
} catch (error) {
@@ -87,7 +97,7 @@ export class ABTestSettings {
let hasError: boolean = false;
let telemetryProperties: { [key: string]: string } = {};
const localConfigPath: string = util.getExtensionFilePath(localConfigFile);
return util.downloadFileToDestination("https://go.microsoft.com/fwlink/?linkid=2026205", localConfigPath)
return util.downloadFileToDestination("https://go.microsoft.com/fwlink/?linkid=2097702", localConfigPath)
.catch((error) => {
// More specific error info is not likely to be helpful, and we get detailed download data from the initial install.
hasError = true;
+2 -1
View File
@@ -34,7 +34,8 @@ class TemporaryCommandRegistrar {
"C_Cpp.ResumeParsing",
"C_Cpp.ShowParsingCommands",
"C_Cpp.TakeSurvey",
"C_Cpp.LogDiagnostics"
"C_Cpp.LogDiagnostics",
"C_Cpp.RescanWorkspace",
];
constructor() {
+66 -2
View File
@@ -103,6 +103,11 @@ export function fileIsCOrCppSource(file: string): boolean {
return [".C", ".c", ".cpp", ".cc", ".cxx", ".mm", ".ino", ".inl"].some(ext => fileExtLower === ext);
}
export function isEditorFileCpp(file: string): boolean {
let editor: vscode.TextEditor = vscode.window.visibleTextEditors.find(e => e.document.uri.toString() === file);
return editor && editor.document.languageId === "cpp";
}
// This function is used to stringify the rawPackageJson.
// Do not use with util.packageJson or else the expanded
// package.json will be written back.
@@ -287,6 +292,19 @@ export function isOptionalArrayOfString(input: any): input is string[]|undefined
return input === undefined || isArrayOfString(input);
}
export function resolveCachePath(input: string, additionalEnvironment: {[key: string]: string | string[]}): string {
let resolvedPath: string = "";
if (!input) {
// If no path is set, return empty string to language service process, where it will set the default path as
// Windows: %LocalAppData%/Microsoft/vscode-cpptools/
// Linux and Mac: ~/.vscode-cpptools/
return resolvedPath;
}
resolvedPath = resolveVariables(input, additionalEnvironment);
return resolvedPath;
}
export function resolveVariables(input: string, additionalEnvironment: {[key: string]: string | string[]}): string {
if (!input) {
return "";
@@ -766,22 +784,31 @@ export function downloadFileToStr(urlStr: string, headers?: OutgoingHttpHeaders)
export interface CompilerPathAndArgs {
compilerPath: string;
compilerName: string;
additionalArgs: string[];
}
export function extractCompilerPathAndArgs(inputCompilerPath: string): CompilerPathAndArgs {
let compilerPath: string = inputCompilerPath;
let compilerName: string = "";
let additionalArgs: string[];
let isWindows: boolean = os.platform() === 'win32';
if (compilerPath) {
if (compilerPath.startsWith("\"")) {
if (compilerPath === "cl.exe") {
// Input is only compiler name, this is only for cl.exe
compilerName = compilerPath;
} else if (compilerPath.startsWith("\"")) {
// Input has quotes around compiler path
let endQuote: number = compilerPath.substr(1).search("\"") + 1;
if (endQuote !== -1) {
additionalArgs = compilerPath.substr(endQuote + 1).split(" ");
additionalArgs = additionalArgs.filter((arg: string) => { return arg.trim().length !== 0; }); // Remove empty args.
compilerPath = compilerPath.substr(1, endQuote - 1);
compilerName = compilerPath.replace(/^.*(\\|\/|\:)/, '');
}
} else {
// Input has no quotes but can have a compiler path with spaces and args.
// Go from right to left checking if a valid path is to the left of a space.
let spaceStart: number = compilerPath.lastIndexOf(" ");
if (spaceStart !== -1 && (!isWindows || !compilerPath.endsWith("cl.exe")) && !checkFileExistsSync(compilerPath)) {
@@ -802,9 +829,13 @@ export function extractCompilerPathAndArgs(inputCompilerPath: string): CompilerP
compilerPath = potentialCompilerPath;
}
}
// Get compiler name if there are no args but path is valid or a valid path was found with args.
if (compilerPath === "cl.exe" || checkFileExistsSync(compilerPath)) {
compilerName = compilerPath.replace(/^.*(\\|\/|\:)/, '');
}
}
}
return { compilerPath, additionalArgs };
return { compilerPath, compilerName, additionalArgs };
}
export function escapeForSquiggles(s: string): string {
@@ -837,3 +868,36 @@ export function escapeForSquiggles(s: string): string {
}
return newResults;
}
export class BlockingTask<T> {
private dependency: BlockingTask<any>;
private done: boolean = false;
private promise: Thenable<T>;
constructor(task: () => Thenable<T>, dependency?: BlockingTask<any>) {
if (!dependency) {
this.promise = task();
} else {
this.dependency = dependency;
this.promise = new Promise<T>((resolve, reject) => {
let f1: () => void = () => {
task().then(resolve, reject);
};
let f2: (err: any) => void = (err) => {
console.log(err);
task().then(resolve, reject);
};
this.dependency.promise.then(f1, f2);
});
}
this.promise.then(() => this.done = true, () => this.done = true);
}
public get Done(): boolean {
return this.done;
}
public getPromise(): Thenable<T> {
return this.promise;
}
}
+20 -5
View File
@@ -303,10 +303,11 @@ async function finalizeExtensionActivation(): Promise<void> {
// Update default for C_Cpp.intelliSenseEngine based on A/B testing settings.
// (this may result in rewriting the package.json file)
let abTestSettings: cpptoolsJsonUtils.ABTestSettings = cpptoolsJsonUtils.getABTestSettings();
let packageJson: any = util.getRawPackageJson();
let writePackageJson: boolean = false;
let packageJsonPath: string = util.getExtensionFilePath("package.json");
if (!packageJsonPath.includes(".vscode-insiders") && !packageJsonPath.includes(".vscode-exploration")) {
let abTestSettings: cpptoolsJsonUtils.ABTestSettings = cpptoolsJsonUtils.getABTestSettings();
let packageJson: any = util.getRawPackageJson();
let prevIntelliSenseEngineDefault: any = packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default;
if (abTestSettings.UseDefaultIntelliSenseEngine) {
packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default = "Default";
@@ -314,15 +315,28 @@ async function finalizeExtensionActivation(): Promise<void> {
packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default = "Tag Parser";
}
if (prevIntelliSenseEngineDefault !== packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default) {
return util.writeFileText(util.getPackageJsonPath(), util.stringifyPackageJson(packageJson));
writePackageJson = true;
}
} else {
let packageJson: any = util.getRawPackageJson();
if (packageJson.contributes.configuration.properties['C_Cpp.updateChannel'].default === 'Default') {
packageJson.contributes.configuration.properties['C_Cpp.updateChannel'].default = 'Insiders';
return util.writeFileText(util.getPackageJsonPath(), util.stringifyPackageJson(packageJson));
writePackageJson = true;
}
}
let prevEnhancedColorizationDefault: any = packageJson.contributes.configuration.properties["C_Cpp.enhancedColorization"].default;
if (abTestSettings.UseEnhancedColorization) {
packageJson.contributes.configuration.properties["C_Cpp.enhancedColorization"].default = "Enabled";
} else {
packageJson.contributes.configuration.properties["C_Cpp.enhancedColorization"].default = "Disabled";
}
if (prevEnhancedColorizationDefault !== packageJson.contributes.configuration.properties["C_Cpp.enhancedColorization"].default) {
writePackageJson = true;
}
if (writePackageJson) {
return util.writeFileText(util.getPackageJsonPath(), util.stringifyPackageJson(packageJson));
}
}
function rewriteManifest(): Promise<void> {
@@ -354,6 +368,7 @@ function rewriteManifest(): Promise<void> {
"onCommand:C_Cpp.ShowParsingCommands",
"onCommand:C_Cpp.TakeSurvey",
"onCommand:C_Cpp.LogDiagnostics",
"onCommand:C_Cpp.RescanWorkspace",
"onDebug",
"workspaceContains:/.vscode/c_cpp_properties.json"
];
+6 -1
View File
@@ -196,6 +196,11 @@
},
"default": []
},
"envFile": {
"type": "string",
"description": "Absolute path to a file containing environment variable definitions. This file has key value pairs separated by an equals sign per line. E.g. KEY=VALUE",
"default": "${workspaceFolder}/.env"
},
"additionalSOLibSearchPath": {
"type": "string",
"description": "Semicolon separated list of directories to use to search for .so files. Example: \"c:\\dir1;c:\\dir2\".",
@@ -431,7 +436,7 @@
},
"envFile": {
"type": "string",
"description": "Absolute path to a file containing environment variable definitions. These file has key value pairs sepearted by an equals sign per line. E.g. KEY=VALUE",
"description": "Absolute path to a file containing environment variable definitions. This file has key value pairs separated by an equals sign per line. E.g. KEY=VALUE",
"default": "${workspaceFolder}/.env"
},
"symbolSearchPath": {
+501 -271
View File
@@ -6,291 +6,393 @@
<meta http-equiv="Content-Security-Policy" content="style-src 'unsafe-inline'; img-src vscode-resource:; script-src 'nonce-{{nonce}}';">
<style type="text/css">
@media (max-width: 1140px) {
#sidebar {
display: none;
}
#main {
@media (max-width: 1140px) {
#sidebar {
display: none;
}
#main {
max-width: 800px;
padding: 0px 20px;
margin: auto;
}
}
.page-margins {
vertical-align: top;
padding-top: 40px;
padding-bottom: 10px
}
.sidebar {
width: 290px;
position: fixed;
z-index: 1;
left: 45px;
overflow-x: hidden;
}
.error {
color: var(--vscode-inputValidation-errorForeground);
background: var(--vscode-inputValidation-errorBackground);
border: solid 1px var(--vscode-inputValidation-errorBorder);
white-space: pre-wrap;
display: none;
padding: 1px 4px 4px 4px;
}
.headerBtn,
.headerBtn:hover,
.headerBtn:active {
cursor: pointer;
color: var(--vscode-foreground);
background: var(--vscode-background);
border: 0px;
padding: 0px;
outline: none;
}
.headerBtn:focus {
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(270deg);
}
.collapse:after {
font-weight: bold;
float: right;
margin-right: 6px;
margin-top: -4px;
content: '\276E';
transform: rotate(90deg);
}
.main {
max-width: 800px;
padding: 0px 20px;
margin-left: 320px;
padding: 0px 30px;
}
.main-title {
font-weight: 500;
font-size: 22px;
padding-bottom: 6px;
color: var(--vscode-foreground);
}
.section {
padding-bottom: 35px;
}
.section-title {
font-weight: 500;
font-size: 14px;
padding-bottom: 4px;
color: var(--vscode-foreground);
}
.section-text {
font-size: 14px;
padding-bottom: 8px;
color: var(--vscode-foreground);
}
.section-note {
font-size: 14px;
font-style: italic;
padding-bottom: 2px;
color: var(--vscode-foreground);
}
.codeblock {
vertical-align: middle;
padding: 2px 8px;
margin-top: 8px;
display: inline-block;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
border-radius: 5px;
}
body {
line-height: 19px
}
body:not(.tabbing) button:focus {
outline: none;
}
a {
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,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px
}
hr {
border: 0;
height: 1px;
border-bottom: 1px solid;
}
h1 {
padding-bottom: .3em;
}
h1,
h2,
h3 {
font-weight: 400
}
a:hover {
text-decoration: underline
}
::placeholder {
color: var(--vscode-input-placeholderForeground);
}
input {
height: 17px;
padding: 6px;
border: solid 1px;
font-size: 13px;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
border: 1px solid var(--vscode-settings-textInputBorder);
}
textarea {
white-space: nowrap;
padding: 4px, 4px;
font-size: 13px;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
border: 1px solid var(--vscode-settings-textInputBorder);
}
button {
color: var(--vscode-button-foreground);
background-color: var(--vscode-button-background);
border: solid 1px var(--vscode-contrastBorder);
padding: 6px 14px;
}
button:hover {
background-color: var(--vscode-button-hoverBackground);
}
button:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: 2px
}
button:active {
outline: none;
}
.select-default {
width: 300px;
height: 27px;
font-size: 13px;
font-family:sans-serif;
color: var(--vscode-settings-dropdownForeground);
background: var(--vscode-settings-dropdownBackground);
border: 1px solid var(--vscode-settings-dropdownBorder);
}
.select-editable {
position: relative;
background-color: var(--vscode-settings-textInputBackground);
width: 800px;
height: 31px;
}
.select-editable select {
position: absolute;
font-size: 13px;
font-family: sans-serif;
border: 1px solid var(--vscode-settings-textInputBorder);
height: 31px;
margin: auto;
}
}
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
}
.page-margins {
vertical-align: top;
padding-top: 40px;
padding-bottom: 10px
}
.select-editable input {
position: absolute;
top: 1px;
left: 1px;
right: 1px;
bottom: 1px;
height: 17px;
font-size: 13px;
border: none;
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
}
.sidebar {
width: 290px;
position: fixed;
z-index: 1;
left: 45px;
overflow-x: hidden;
}
.select-editable input:focus {
outline-offset: 0px;
}
.error {
color: var(--vscode-inputValidation-errorForeground);
background: var(--vscode-inputValidation-errorBackground);
border: solid 1px var(--vscode-inputValidation-errorBorder);
white-space: pre-wrap;
visibility: hidden;
display: block;
padding: 1px 4px 4px 4px;
}
blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left: 5px solid;
}
.main {
max-width: 800px;
margin-left: 320px;
padding: 0px 30px;
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
line-height: 19px
}
.main-title {
font-weight: 500;
font-size: 22px;
padding-bottom: 6px;
color: var(--vscode-foreground);
}
.mac code {
line-height: 18px
}
.section {
padding-bottom: 35px;
}
code > div {
padding: 16px;
border-radius: 3px;
overflow: auto
}
.section-title {
font-weight: 500;
font-size: 14px;
padding-bottom: 4px;
color: var(--vscode-foreground);
}
.monaco-tokenized-source {
white-space: pre
}
.section-text {
font-size: 14px;
padding-bottom: 8px;
color: var(--vscode-foreground);
}
/** Theming */
.section-note {
font-size: 14px;
font-style: italic;
padding-bottom: 2px;
color: var(--vscode-foreground);
}
.vscode-light {
color: #1e1e1e
}
.codeblock {
vertical-align: middle;
padding: 2px 8px;
margin-top: 8px;
display: inline-block;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
border-radius: 5px;
}
.vscode-dark {
color: #ddd
}
body {
line-height: 19px
}
.vscode-high-contrast {
color: #fff
}
a {
text-decoration: none
}
.vscode-light code {
color: #a31515
}
a:focus,
input:focus,
select:focus,
textarea:focus {
outline: 1px solid -webkit-focus-ring-color;
outline-offset: -1px
}
.vscode-dark code {
color: #d7ba7d
}
hr {
border: 0;
height: 1px;
border-bottom: 1px solid;
}
.vscode-light code > div {
background-color: rgba(220, 220, 220, .4)
}
h1 {
padding-bottom: .3em;
}
.vscode-dark code > div {
background-color: rgba(10, 10, 10, .4)
}
h1,
h2,
h3 {
font-weight: 400
}
.vscode-light .input-disabled {
background-color:rgba(255, 255, 255, 0.4);
color: rgb(138, 138, 138);
border: solid 1px rgb(201, 198, 198);
}
a:hover {
text-decoration: underline
}
.vscode-dark .input-disabled {
background-color: rgba(255, 255, 255, 0.1);
color: rgb(167, 167, 167);
}
input {
height: 17px;
padding: 6px;
border: solid 1px;
font-size: 13px;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
border: 1px solid var(--vscode-settings-textInputBorder);
}
.vscode-high-contrast .input-disabled {
background-color: transparent;
color: #fff;
border: solid 1px rgb(255, 255, 255);
}
textarea {
white-space: nowrap;
padding: 4px, 4px;
font-size: 13px;
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
color: var(--vscode-settings-textInputForeground);
background: var(--vscode-settings-textInputBackground);
border: 1px solid var(--vscode-settings-textInputBorder);
}
.vscode-high-contrast code > div {
background-color: #000
}
select {
width: 300px;
height: 27px;
font-size: 13px;
font-family:sans-serif;
color: var(--vscode-settings-dropdownForeground);
background: var(--vscode-settings-dropdownBackground);
border: 1px solid var(--vscode-settings-dropdownBorder);
}
.vscode-high-contrast h1 {
border-color: #000
}
blockquote {
margin: 0 7px 0 5px;
padding: 0 16px 0 10px;
border-left: 5px solid;
}
.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, .69)
}
code {
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
line-height: 19px
}
.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, .69)
}
.mac code {
line-height: 18px
}
.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, .18)
}
code > div {
padding: 16px;
border-radius: 3px;
overflow: auto
}
.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18)
}
.monaco-tokenized-source {
white-space: pre
}
.vscode-light blockquote,
.vscode-dark blockquote {
background: rgba(127, 127, 127, .1);
border-color: rgba(0, 122, 204, .5)
}
/** Theming */
.vscode-high-contrast blockquote {
background: transparent;
border-color: #fff
}
.vscode-light {
color: #1e1e1e
}
.vscode-light div.codeblock {
background-color: rgba(0, 0, 0, 0.048)
}
.vscode-dark {
color: #ddd
}
.vscode-dark div.codeblock {
background-color: rgba(255, 255, 255, 0.1)
}
.vscode-high-contrast {
color: #fff
}
.vscode-high-contrast div.codeblock {
background-color: rgba(255, 255, 255, 0.15)
}
.vscode-light code {
color: #a31515
}
.footer {
padding: 25px;
text-align: center
}
.vscode-dark code {
color: #d7ba7d
}
.vscode-light a {
color: #4080D0
}
.vscode-light code > div {
background-color: rgba(220, 220, 220, .4)
}
.vscode-dark a {
color: #a2c1e8
}
.vscode-dark code > div {
background-color: rgba(10, 10, 10, .4)
}
.vscode-light .input-disabled {
background-color:rgba(255, 255, 255, 0.4);
color: rgb(138, 138, 138);
border: solid 1px rgb(201, 198, 198);
}
.vscode-dark .input-disabled {
background-color: rgba(255, 255, 255, 0.1);
color: rgb(167, 167, 167);
}
.vscode-high-contrast .input-disabled {
background-color: transparent;
color: #fff;
border: solid 1px rgb(255, 255, 255);
}
.vscode-high-contrast code > div {
background-color: #000
}
.vscode-high-contrast h1 {
border-color: #000
}
.vscode-light table > thead > tr > th {
border-color: rgba(0, 0, 0, .69)
}
.vscode-dark table > thead > tr > th {
border-color: rgba(255, 255, 255, .69)
}
.vscode-light h1,
.vscode-light hr,
.vscode-light table > tbody > tr + tr > td {
border-color: rgba(0, 0, 0, .18)
}
.vscode-dark h1,
.vscode-dark hr,
.vscode-dark table > tbody > tr + tr > td {
border-color: rgba(255, 255, 255, 0.18)
}
.vscode-light blockquote,
.vscode-dark blockquote {
background: rgba(127, 127, 127, .1);
border-color: rgba(0, 122, 204, .5)
}
.vscode-high-contrast blockquote {
background: transparent;
border-color: #fff
}
.vscode-light div.codeblock {
background-color: rgba(0, 0, 0, 0.048)
}
.vscode-dark div.codeblock {
background-color: rgba(255, 255, 255, 0.1)
}
.vscode-high-contrast div.codeblock {
background-color: rgba(255, 255, 255, 0.15)
}
.footer {
padding: 25px;
text-align: center
}
.vscode-light a {
color: #4080D0
}
.vscode-dark a {
color: #a2c1e8
}
</style>
</style>
</head>
@@ -333,8 +435,8 @@
<div class="main-title">IntelliSense Configurations</div>
<div style="color: var(--vscode-foreground);">
Use this editor to edit basic IntelliSense settings defined in the underlying <a href="command:C_Cpp.ConfigurationEditJSON" title="Edit configurations in JSON file">c_cpp_properties.json</a> file.
Changes made in this editor only apply to the active configuration. To modify other configurations <a href="command:C_Cpp.ConfigurationSelect" title="Change the active configuration">change the active configuration</a>.
To edit multiple configurations at once, or additional settings not shown here, go to <a href="command:C_Cpp.ConfigurationEditJSON" title="Edit configurations in JSON file">c_cpp_properties.json</a>.
Changes made in this editor only apply to the selected configuration.
To edit multiple configurations at once go to <a href="command:C_Cpp.ConfigurationEditJSON" title="Edit configurations in JSON file">c_cpp_properties.json</a>.
</div>
</div>
@@ -346,23 +448,48 @@
<div class="section-title">Configuration name</div>
<div class="section-text">
A friendly name that identifies a configuration. <code>Mac</code>, <code>Linux</code>, and <code>Win32</code> 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 <a href="command:C_Cpp.ConfigurationEditJSON" title="Edit configurations in JSON file">c_cpp_properties.json</a> file and edit the <code>name</code> property.
</div>
<div><input class="input-disabled" type="text" id=activeConfig style="width: 290px" disabled>
<a style="padding-left: 6px;" href="command:C_Cpp.ConfigurationSelect" title="Change the active configuration">Change the active configuration</a>
</div>
<div>
<div class="section-note">Select a configuration set to edit.</div>
<table>
<tr>
<!-- select configuration name -->
<td>
<div class="select-editable" style="width: 300px; margin-right: 10px">
<select id="configSelection" style="width: 300px"></select>
<input id=configName style="width: 267px" type="text"/>
</div>
</td>
<!-- input configuration name -->
<td style="vertical-align: middle;">
<div id=addConfigDiv style="display: block">
<button id=addConfigBtn >Add Configuration</button>
</div>
<div id=addConfigInputDiv style="display: none; width: 400px;">
<input id=addConfigName type=text style="width: 200px; margin-right: 6px" placeholder="Configuration name..."/>
<button id=addConfigOk style="margin-right: 6px">OK</button>
<button id=addConfigCancel>CANCEL</button>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="section">
<div class="section-title">Compiler path</div>
<div class="section-text">
The full path of the compiler being used to build, e.g. <code>/usr/bin/gcc</code>, to enable more accurate IntelliSense.
Args can be added to modify the includes/defines used, e.g. <code>-nostdinc++</code>, <code>-m32</code>, etc., but paths with spaces must be surrounded by double quotes <code>"</code> if args are used.
</div>
<div>
<input id="compilerPath" style="width: 798px"></input>
<div id="compilerPathInvalid" class="error" style="width: 800px"></div>
Arguments can be added to modify the includes/defines used, e.g. <code>-nostdinc++</code>, <code>-m32</code>, etc., but paths with spaces must be surrounded by double quotes <code>"</code> if arguments are used.
</div>
<!-- input compilerPath -->
<div class="section-note">Specify a compiler path or select a detected compiler path from the drop-down list.</div>
<div class="select-editable">
<select id="knownCompilers" style="width: 810px"></select>
<input name="inputValue" id="compilerPath" style="width: 777px" type="text"/>
</div>
<div id="compilerPathInvalid" class="error" style="width: 800px"></div>
<!-- input compilerPath end -->
</div>
<div class="section">
@@ -373,7 +500,7 @@
Select a specific IntelliSense mode to override the <code>${default}</code> mode.
</div>
<div>
<select id="intelliSenseMode">
<select name="inputValue" id="intelliSenseMode" class="select-default">
<option value="${default}">${default}</option>
<option value="msvc-x64">msvc-x64</option>
<option value="gcc-x64">gcc-x64</option>
@@ -386,11 +513,13 @@
<div class="section">
<div class="section-title">Include path</div>
<div class="section-text">
A list of paths for the IntelliSense engine to use while searching for included headers. If a path ends with <code>/**</code> the IntelliSense engine will do a recursive search for headers starting from that directory.
An include path is a folder that contains header files (such as <code>#include "myHeaderFile.h"</code>) that are included in a source file.
Specify a list paths for the IntelliSense engine to use while searching for included header files.
If a path ends with <code>/**</code> the IntelliSense engine will do a recursive search for header files starting from that directory.
</div>
<div>
<div class="section-note">One include path per line.</div>
<textarea id="includePath" rows="4" cols="93" style="width: 800px"></textarea>
<textarea name="inputValue" id="includePath" rows="4" cols="93" style="width: 800px"></textarea>
<div id="includePathInvalid" class="error" style="margin-top: -4px; width: 794px"></div>
</div>
</div>
@@ -402,15 +531,15 @@
</div>
<div>
<div class="section-note">One definition per line.</div>
<textarea id="defines" rows="4" cols="39"></textarea>
<textarea name="inputValue" id="defines" rows="4" cols="39"></textarea>
</div>
</div>
<div class="section">
<div class="section-title">C Standard</div>
<div class="section-title">C standard</div>
<div class="section-text">The version of the C language standard to use for IntelliSense.</div>
<div>
<select id="cStandard">
<select name="inputValue" id="cStandard" class="select-default">
<option value="c11">c11</option>
<option value="c99">c99</option>
<option value="c89">c89</option>
@@ -419,20 +548,121 @@
</div>
<div class="section">
<div class="section-title">C++ Standard</div>
<div class="section-title">C++ standard</div>
<div class="section-text">The version of the C++ language standard to use for IntelliSense.</div>
<div>
<select id="cppStandard">
<select name="inputValue" id="cppStandard" class="select-default">
<option value="c++17">c++17</option>
<option value="c++14">c++14</option>
<option value="c++11">c++11</option>
<option value="c++03">c++03</option>
<option value="c++98">c++98</option>
</select>
</div> <!-- sections end -->
</div>
</div>
<hr>
<button id=showAdvanced class="headerBtn" style="margin-top: 5px; font-size: 20px; font-weight: 500; width: 100%; text-align: left">
Advanced Settings
</button>
<div style="height: 30px; display: block"></div>
<div id=advancedSection>
<div class="section">
<div class="section-title">Configuration provider</div>
<div class="section-text">
The ID of a VS Code extension that can provide IntelliSense configuration information for source files.
</div>
<div>
<input name="inputValue" id="configurationProvider" style="width: 290px"></input>
</div>
</div>
<div class="section">
<div class="section-title">Windows SDK version</div>
<div class="section-text">
Version of the Windows SDK include path to use on Windows, e.g. <code>10.0.17134.0</code>.
</div>
<div>
<input name="inputValue" id="windowsSdkVersion" style="width: 290px"></input>
</div>
</div>
<div class="section">
<div class="section-title">Mac framework path</div>
<div class="section-text">
A list of paths for the Intellisense engine to use while searching for included headers from Mac frameworks. Only supported on Mac configuration.
</div>
<div>
<div class="section-note">One path per line.</div>
<textarea name="inputValue" id="macFrameworkPath" rows="4" cols="93" style="width: 800px"></textarea>
<div id="macFrameworkPathInvalid" class="error" style="margin-top: -4px; width: 794px"></div>
</div>
</div>
<div class="section">
<div class="section-title">Forced include</div>
<div class="section-text">
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.
</div>
<div>
<div class="section-note">One file per line.</div>
<textarea name="inputValue" id="forcedInclude" rows="4" cols="93" style="width: 800px"></textarea>
<div id="forcedIncludeInvalid" class="error" style="margin-top: -4px; width: 794px"></div>
</div>
</div>
<div class="section">
<div class="section-title">Compile commands</div>
<div class="section-text">
Full path to <code>compile_commands.json</code> file for the workspace.
</div>
<div>
<input name="inputValue" id="compileCommands" style="width: 798px"></input>
<div id="compileCommandsInvalid" class="error" style="width: 800px"></div>
</div>
</div>
<div class="section">
<div class="section-title">Browse: path</div>
<div class="section-text">
A list of paths for the tag parser to use while searching for included headers.
Searching on these paths is recursive by default. Specify <code>*</code> to indicate non-recursive search.
For example: <code>/usr/include</code> will search through all subdirectories while <code>/usr/include/*</code> will not.
</div>
<div>
<div class="section-note">One browse path per line.</div>
<textarea name="inputValue" id="browsePath" rows="4" cols="93" style="width: 800px"></textarea>
<div id="browsePathInvalid" class="error" style="margin-top: -4px; width: 794px"></div>
</div>
</div>
<div class="section">
<div class="section-title">Browse: limit symbols to included headers</div>
<div>
<input type="checkbox" id="limitSymbolsToIncludedHeaders" style="vertical-align: middle; transform: scale(1.5)">
Process only those files directly or indirectly included as headers. If not set, process all files under the specified include paths.
</input>
</div>
</div>
<div class="section">
<div class="section-title">Browse: database filename</div>
<div class="section-text">
Path to the generated symbol database. If a relative path is specified,
it will be made relative to the workspace's default storage location.
</div>
<div>
<input name="inputValue" id="databaseFilename" style="width: 798px"></input>
<div id="databaseFilenameInvalid" class="error" style="width: 800px"></div>
</div>
</div>
</div> <!-- advanced settings end -->
<!-- sections end -->
</div> <!-- main end -->
<script nonce="{{nonce}}" src="{{root}}/out/ui/settings.js"></script>
+289 -34
View File
@@ -5,16 +5,48 @@
'use strict';
const elementId: { [key: string]: string } = {
activeConfig: "activeConfig",
// Basic settings
configName: "configName",
configSelection: "configSelection",
addConfigDiv: "addConfigDiv",
addConfigBtn: "addConfigBtn",
addConfigInputDiv: "addConfigInputDiv",
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",
compilerPathInvalid: "compilerPathInvalid",
intelliSenseModeInvalid: "intelliSenseModeInvalid",
includePathInvalid: "includePathInvalid"
// Advanced settings
windowsSdkVersion: "windowsSdkVersion",
macFrameworkPath: "macFrameworkPath",
macFrameworkPathInvalid: "macFrameworkPathInvalid",
compileCommands: "compileCommands",
compileCommandsInvalid: "compileCommandsInvalid",
configurationProvider: "configurationProvider",
forcedInclude: "forcedInclude",
forcedIncludeInvalid: "forcedIncludeInvalid",
// Browse properties
browsePath: "browsePath",
browsePathInvalid: "browsePathInvalid",
limitSymbolsToIncludedHeaders: "limitSymbolsToIncludedHeaders",
databaseFilename: "databaseFilename",
databaseFilenameInvalid: "databaseFilenameInvalid",
// Other
showAdvanced: "showAdvanced",
advancedSection: "advancedSection"
};
interface VsCodeApi {
@@ -32,18 +64,151 @@ class SettingsApp {
constructor() {
this.vsCodeApi = acquireVsCodeApi();
window.addEventListener('message', this.onMessageReceived.bind(this));
window.addEventListener("keydown", this.onTabKeyDown.bind(this));
window.addEventListener("message", this.onMessageReceived.bind(this));
document.getElementById(elementId.activeConfig).addEventListener("change", this.onChanged.bind(this, elementId.activeConfig));
document.getElementById(elementId.compilerPath).addEventListener("change", this.onChanged.bind(this, elementId.compilerPath));
document.getElementById(elementId.intelliSenseMode).addEventListener("change", this.onChanged.bind(this, elementId.intelliSenseMode));
// Add event listeners to UI elements
this.addEventsToConfigNameChanges();
this.addEventsToInputValues();
document.getElementById(elementId.knownCompilers).addEventListener("change", this.onKnownCompilerSelect.bind(this));
document.getElementById(elementId.includePath).addEventListener("change", this.onChanged.bind(this, elementId.includePath));
document.getElementById(elementId.defines).addEventListener("change", this.onChanged.bind(this, elementId.defines));
// 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));
}
document.getElementById(elementId.cStandard).addEventListener("change", this.onChanged.bind(this, elementId.cStandard));
document.getElementById(elementId.cppStandard).addEventListener("change", this.onChanged.bind(this, elementId.cppStandard));
private addEventsToInputValues(): void {
const elements: NodeListOf<HTMLElement> = 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));
}
private onTabKeyDown(e: any): void {
if (e.keyCode === 9) {
document.body.classList.add("tabbing");
window.removeEventListener("keydown", this.onTabKeyDown);
window.addEventListener("mousedown", this.onMouseDown.bind(this));
}
}
private onMouseDown(): void {
document.body.classList.remove("tabbing");
window.removeEventListener("mousedown", this.onMouseDown);
window.addEventListener("keydown", this.onTabKeyDown.bind(this));
}
private onShowAdvanced(): void {
const isShown: boolean = (document.getElementById(elementId.advancedSection).style.display === "block");
document.getElementById(elementId.advancedSection).style.display = isShown ? "none" : "block";
// 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 {
this.showElement(elementId.addConfigDiv, false);
this.showElement(elementId.addConfigInputDiv, true);
}
private OnAddConfigConfirm(request: boolean): void {
this.showElement(elementId.addConfigInputDiv, false);
this.showElement(elementId.addConfigDiv, true);
// If request is yes, send message to create new config
if (request) {
const el: HTMLInputElement = <HTMLInputElement>document.getElementById(elementId.addConfigName);
if (el.value !== undefined && el.value !== "") {
this.vsCodeApi.postMessage({
command: "addConfig",
name: el.value
});
el.value = "";
}
}
}
private onConfigNameChanged(): void {
if (this.updating) {
return;
}
const configName: HTMLInputElement = <HTMLInputElement>document.getElementById(elementId.configName);
let list: HTMLSelectElement = <HTMLSelectElement>document.getElementById(elementId.configSelection);
if (configName.value === "") {
(<HTMLInputElement>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 el: HTMLSelectElement = <HTMLSelectElement>document.getElementById(elementId.configSelection);
(<HTMLInputElement>document.getElementById(elementId.configName)).value = el.value;
this.vsCodeApi.postMessage({
command: "configSelect",
index: el.selectedIndex
});
}
private onKnownCompilerSelect(): void {
if (this.updating) {
return;
}
const el: HTMLInputElement = <HTMLInputElement>document.getElementById(elementId.knownCompilers);
(<HTMLInputElement>document.getElementById(elementId.compilerPath)).value = el.value;
this.onChanged(elementId.compilerPath);
// Post message that this control was used for telemetry
this.vsCodeApi.postMessage({
command: "knownCompilerSelect"
});
// Reset selection to none
el.value = "";
}
private onChangedCheckbox(id: string): void {
if (this.updating) {
return;
}
const el: HTMLInputElement = <HTMLInputElement>document.getElementById(id);
this.vsCodeApi.postMessage({
command: "change",
key: id,
value: el.checked
});
}
private onChanged(id: string): void {
@@ -51,11 +216,11 @@ class SettingsApp {
return;
}
const x: HTMLInputElement = <HTMLInputElement>document.getElementById(id);
const el: HTMLInputElement = <HTMLInputElement>document.getElementById(id);
this.vsCodeApi.postMessage({
command: "change",
key: id,
value: x.value
value: el.value
});
}
@@ -66,16 +231,22 @@ class SettingsApp {
this.updateConfig(message.config);
break;
case 'updateErrors':
this.updateErrors(message.errors);
break;
this.updateErrors(message.errors);
break;
case 'setKnownCompilers':
this.setKnownCompilers(message.compilers);
break;
case 'updateConfigSelection':
this.updateConfigSelection(message);
break;
}
}
private updateConfig(config: any): void {
this.updating = true;
try {
(<HTMLInputElement>document.getElementById(elementId.activeConfig)).value = config.name;
// Basic settings
(<HTMLInputElement>document.getElementById(elementId.configName)).value = config.name;
(<HTMLInputElement>document.getElementById(elementId.compilerPath)).value = config.compilerPath ? config.compilerPath : "";
(<HTMLInputElement>document.getElementById(elementId.intelliSenseMode)).value = config.intelliSenseMode ? config.intelliSenseMode : "${default}";
@@ -87,6 +258,30 @@ class SettingsApp {
(<HTMLInputElement>document.getElementById(elementId.cStandard)).value = config.cStandard;
(<HTMLInputElement>document.getElementById(elementId.cppStandard)).value = config.cppStandard;
// Advanced settings
(<HTMLInputElement>document.getElementById(elementId.windowsSdkVersion)).value = config.windowsSdkVersion ? config.windowsSdkVersion : "";
(<HTMLInputElement>document.getElementById(elementId.macFrameworkPath)).value =
(config.macFrameworkPath && config.macFrameworkPath.length > 0) ? config.macFrameworkPath.join("\n") : "";
(<HTMLInputElement>document.getElementById(elementId.compileCommands)).value = config.compileCommands ? config.compileCommands : "";
(<HTMLInputElement>document.getElementById(elementId.configurationProvider)).value = config.configurationProvider ? config.configurationProvider : "";
(<HTMLInputElement>document.getElementById(elementId.forcedInclude)).value =
(config.forcedInclude && config.forcedInclude.length > 0) ? config.forcedInclude.join("\n") : "";
if (config.browse) {
(<HTMLInputElement>document.getElementById(elementId.browsePath)).value =
(config.browse.path && config.browse.path.length > 0) ? config.browse.path.join("\n") : "";
(<HTMLInputElement>document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked =
(config.browse.limitSymbolsToIncludedHeaders && config.browse.limitSymbolsToIncludedHeaders);
(<HTMLInputElement>document.getElementById(elementId.databaseFilename)).value = config.browse.databaseFilename ? config.browse.databaseFilename : "";
} else {
(<HTMLInputElement>document.getElementById(elementId.browsePath)).value = "";
(<HTMLInputElement>document.getElementById(elementId.limitSymbolsToIncludedHeaders)).checked = false;
(<HTMLInputElement>document.getElementById(elementId.databaseFilename)).value = "";
}
} finally {
this.updating = false;
}
@@ -95,25 +290,85 @@ class SettingsApp {
private updateErrors(errors: any): void {
this.updating = true;
try {
this.showErrorWithInfo(elementId.intelliSenseModeInvalid,
errors.intelliSenseMode ? true : false,
errors.intelliSenseMode);
this.showErrorWithInfo(elementId.compilerPathInvalid,
errors.compilerPath ? true : false,
errors.compilerPath);
this.showErrorWithInfo(elementId.includePathInvalid,
errors.includePath ? true : false,
errors.includePath);
this.showErrorWithInfo(elementId.intelliSenseModeInvalid, errors.intelliSenseMode);
this.showErrorWithInfo(elementId.compilerPathInvalid, errors.compilerPath);
this.showErrorWithInfo(elementId.includePathInvalid, errors.includePath);
this.showErrorWithInfo(elementId.macFrameworkPathInvalid, errors.macFrameworkPath);
this.showErrorWithInfo(elementId.forcedIncludeInvalid, errors.forcedInclude);
this.showErrorWithInfo(elementId.compileCommandsInvalid, errors.compileCommands);
this.showErrorWithInfo(elementId.browsePathInvalid, errors.browsePath);
this.showErrorWithInfo(elementId.databaseFilenameInvalid, errors.databaseFilename);
} finally {
this.updating = false;
}
}
private showErrorWithInfo(elementID: string, show: boolean, errorInfo: string): void {
document.getElementById(elementID).style.visibility = show ? "visible" : "hidden";
document.getElementById(elementID).innerHTML = errorInfo ? errorInfo : "";
private showErrorWithInfo(elementID: string, errorInfo: string): void {
this.showElement(elementID, errorInfo ? true : false);
document.getElementById(elementID).innerHTML = errorInfo ? errorInfo : "";
}
private updateConfigSelection(message: any): void {
this.updating = true;
try {
let list: HTMLSelectElement = <HTMLSelectElement>document.getElementById(elementId.configSelection);
// Clear list before updating
list.options.length = 0;
// Update list
for (let name of message.selections) {
let option: HTMLOptionElement = document.createElement("option");
option.text = name;
option.value = name;
list.append(option);
}
list.selectedIndex = message.selectedIndex;
} finally {
this.updating = false;
}
}
private setKnownCompilers(compilers: string[]): void {
this.updating = true;
try {
let list: HTMLSelectElement = <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.
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;
}
}
private showElement(elementID: string, show: boolean): void {
document.getElementById(elementID).style.display = show ? "block" : "none";
}
}
+3
View File
@@ -36,6 +36,9 @@ const config = {
}]
}]
},
optimization: {
minimize: false
}
}
module.exports = config;
+1 -1
View File
@@ -28,4 +28,4 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
### Data/Telemetry
This project collects usage data and sends it to Microsoft to help improve our products and services. Read our [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more.
This extension collects usage data and sends it to Microsoft to help improve our products and services. Collection of telemetry is controlled via the same setting provided by Visual Studio Code: `"telemetry.enableTelemetry"`. Read our [privacy statement](https://privacy.microsoft.com/en-us/privacystatement) to learn more.