Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa4d7b22c1 | ||
|
|
3cb7f7e61f | ||
|
|
779f2ce2b5 | ||
|
|
0c4c83e5bd | ||
|
|
a369ede8d9 | ||
|
|
36ce8f885f | ||
|
|
347794b0c7 | ||
|
|
3ed087134c | ||
|
|
902355e021 | ||
|
|
32e98912df | ||
|
|
6bc49d595e | ||
|
|
6b3c0f1b10 | ||
|
|
35501431f8 | ||
|
|
27a3c9958d | ||
|
|
5b3d4ebf44 | ||
|
|
cfc064efcd | ||
|
|
4f7a64a1a2 | ||
|
|
c84cb36004 | ||
|
|
0502351002 | ||
|
|
5de420ee70 | ||
|
|
6a73275924 | ||
|
|
d12591062e | ||
|
|
3926110b33 | ||
|
|
f5975e6534 | ||
|
|
b55e2c7ac5 | ||
|
|
73fda38d71 | ||
|
|
9211292b60 | ||
|
|
f63a8da581 | ||
|
|
fd314b1b04 | ||
|
|
ea52c76595 | ||
|
|
7659e2826b | ||
|
|
8e898151f6 | ||
|
|
b2b0ad37af | ||
|
|
cee6ebe1d9 | ||
|
|
566e657fad | ||
|
|
db1f631396 | ||
|
|
426c08293d | ||
|
|
631a4452d0 | ||
|
|
9b29698b0e | ||
|
|
b5c94e9e1f | ||
|
|
384cd35d6b | ||
|
|
2d4df9149f | ||
|
|
d3c2ccbb93 | ||
|
|
c637221b92 | ||
|
|
814f01b263 | ||
|
|
b763aa57d3 | ||
|
|
54b1e69975 | ||
|
|
dacfe08033 | ||
|
|
f5aa7dc33e | ||
|
|
90c6e9876a | ||
|
|
9fa950db6a | ||
|
|
8ea627e085 | ||
|
|
536d38e3bf | ||
|
|
c10c626869 | ||
|
|
24d37bc233 | ||
|
|
158719cf46 | ||
|
|
b6327ed6c3 | ||
|
|
c60a2c6752 | ||
|
|
1f7c27d7f9 | ||
|
|
1d82458a3a | ||
|
|
25d122c3f7 | ||
|
|
627acc535e | ||
|
|
515d858b4d | ||
|
|
7ec15af47c | ||
|
|
cac58e9f88 | ||
|
|
0c28725628 |
@@ -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"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
````
|
||||
Vendored
-3
@@ -64,9 +64,6 @@
|
||||
"run",
|
||||
"compileDev"
|
||||
],
|
||||
"dependsOn": [
|
||||
"TypeScript Compile"
|
||||
],
|
||||
"problemMatcher": "$tsc-watch"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
[](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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
+863
-2064
File diff suppressed because it is too large
Load Diff
@@ -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,5 +2,6 @@
|
||||
"intelliSenseEngine_default_percentage": 100,
|
||||
"defaultIntelliSenseEngine": 100,
|
||||
"recursiveIncludes": 100,
|
||||
"gotoDefIntelliSense": 100
|
||||
"gotoDefIntelliSense": 100,
|
||||
"enhancedColorization": 100
|
||||
}
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "C",
|
||||
"scopeName": "source.c",
|
||||
"version": "0",
|
||||
"information_for_contributors": [
|
||||
],
|
||||
"patterns": [
|
||||
],
|
||||
"repository": {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "C++",
|
||||
"scopeName": "source.cpp",
|
||||
"version": "0",
|
||||
"information_for_contributors": [
|
||||
],
|
||||
"patterns": [
|
||||
],
|
||||
"repository": {
|
||||
}
|
||||
}
|
||||
Generated
+275
-392
File diff suppressed because it is too large
Load Diff
+47
-24
@@ -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,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
@@ -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"
|
||||
}
|
||||
@@ -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": "重新扫描工作区"
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -40,7 +40,7 @@ function createLaunchString(name: string, type: string, executable: string): str
|
||||
"stopAtEntry": false,
|
||||
"cwd": "$\{workspaceFolder\}",
|
||||
"environment": [],
|
||||
"externalConsole": true
|
||||
"externalConsole": false
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
];
|
||||
|
||||
@@ -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
@@ -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
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ const config = {
|
||||
}]
|
||||
}]
|
||||
},
|
||||
optimization: {
|
||||
minimize: false
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user