Compare commits

..
16 Commits
Author SHA1 Message Date
Sean McManus 3263fab54f Merge pull request #9455 from microsoft/seanmcm/1_10_7_cherrypick
Update version and changelog for 1.10.7. (#9454)
2022-06-15 14:10:00 -07:00
Sean McManus 3254d7db33 Update version and changelog for 1.10.7. (#9454) 2022-06-15 13:52:15 -07:00
Sean McManus 77bdf4b028 Merge pull request #9449 from microsoft/seanmcm/1_10_6_cherryPick2
1.10.6 another cherry-pick
2022-06-14 16:40:59 -07:00
Elaheh Rashedi ca16d85890 resolve tasks when IntelliSense is disabled (#9448) 2022-06-14 16:38:11 -07:00
Sean McManus 74f12d8071 Merge pull request #9447 from microsoft/seanmcm/1_10_6_cherryPick
Merge for 1.10.6
2022-06-14 14:30:26 -07:00
Sean McManus dc6b33eda2 Update version and changelog. (#9440)
* Update version and changelog.
2022-06-14 14:09:36 -07:00
Sean McManus bde931bc3a Remove legacyCompilerArgsBehavior deprecation. (#9439) 2022-06-14 14:09:07 -07:00
Sean McManus 872c86ad20 Fix error that occurred when resolving a merge conflict. (#9424) 2022-06-08 10:47:07 -07:00
Sean McManus 6736b6771f Merge pull request #9421 from microsoft/seanmcm/1_10_5_release
Merge for 1.10.5
2022-06-08 10:07:33 -07:00
Sean McManus 4b4ea51138 Merge branch 'release' into seanmcm/1_10_5_release 2022-06-07 21:48:48 -07:00
Colen Garoutte-Carson 380dcbbb58 Fix changelog release date for 1.9.8 (#9210) 2022-04-20 11:26:20 -07:00
Colen Garoutte-Carson 0a002db1e5 Merge pull request #9206 from microsoft/coleng/1.9.8-cherry-picks 2022-04-19 17:12:24 -07:00
Colen Garoutte-Carson b5b1c2b9df Update changelog for 1.9.8 (#9207) 2022-04-19 17:10:46 -07:00
Colen Garoutte-Carson dd8f358076 Fix exception when IntelliSenseEngine is Diabled (#9178) 2022-04-19 16:34:07 -07:00
Andrew Wang 34cd49174e Add back 'aiKey' in package.json (#9183)
* Add back 'aiKey' in package.json

* Add _aiKeyComment
2022-04-19 16:33:47 -07:00
Sean McManus 2874fd2600 Merge pull request #9070 from microsoft/main
Merge for 1.9.7
2022-03-22 18:52:16 -07:00
49 changed files with 3633 additions and 7000 deletions
-1
View File
@@ -33,4 +33,3 @@ localized_string_ids.h
# ignore generate files. It will be generated when building
src/nativeStrings.ts
vscode*.d.ts
-37
View File
@@ -1,42 +1,5 @@
# C/C++ for Visual Studio Code Change Log
## Version 1.11.2 (pre-release): July 8, 2022
### Enhancements
* Add deploySteps and variables to cppdbg. [PR #9418](https://github.com/microsoft/vscode-cpptools/pull/9418)
## Version 1.11.1 (pre-release): July 7, 2022
### Enhancements
* Move "auto" inlay hints to the right by default and add `C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft`. [#9478](https://github.com/microsoft/vscode-cpptools/issues/9478)
* Allow breakpoints for Rust debugging. [PR #9484](https://github.com/microsoft/vscode-cpptools/pull/9484)
* Remove `_` from the start of parameter inlay hints and add `C_Cpp.inlayHints.parameterNames.hideLeadingUnderscores`. [#9485](https://github.com/microsoft/vscode-cpptools/issues/9485)
* Add `C_Cpp.inlayHints.referenceOperator.showSpace` setting. [#9486](https://github.com/microsoft/vscode-cpptools/issues/9486)
* Make `C_Cpp.debugShortcut` settable per-workspace folder. [PR #9514](https://github.com/microsoft/vscode-cpptools/pull/9514)
### Bug Fixes
* Fix "unknown register name" IntelliSense error. [#4382](https://github.com/microsoft/vscode-cpptools/issues/4382)
* Fix performance issue with tag parsing a file with a lot of defines. [#6454](https://github.com/microsoft/vscode-cpptools/issues/6454)
* Fix missing logging when `C_Cpp.intelliSenseEngine` is set to `"Disabled"`. [#9277](https://github.com/microsoft/vscode-cpptools/issues/9277)
* Fix the code analysis "disable" option not automatically clearing the disabled diagnostics. [#9364](https://github.com/microsoft/vscode-cpptools/issues/9364)
* Fix `-isystem` not being used for system headers with code analysis. [#9366](https://github.com/microsoft/vscode-cpptools/issues/9366)
* Fix compiler querying for EDG-based compilers. [#9410](https://github.com/microsoft/vscode-cpptools/issues/9410)
* Fix bug with the environment being incorrect when compiler querying. [#9472](https://github.com/microsoft/vscode-cpptools/issues/9472)
* Fix inlay hints not having padding on the left if there is no existing space. [#9479](https://github.com/microsoft/vscode-cpptools/issues/9479)
* Fix duplicate inlay hints appearing sometimes. [#9487](https://github.com/microsoft/vscode-cpptools/issues/9487)
* Fix duplicate compiler args in compiler query with custom configuration providers using cpptools-api prior to v6. [#9531](https://github.com/microsoft/vscode-cpptools/issues/9531)
* Fix cl.exe build tasks not showing for .c files and .c build tasks being cached for .cpp files (and vice versa). [PR #9544](https://github.com/microsoft/vscode-cpptools/pull/9544)
* Fix process launching concurrency issues on Windows.
## Version 1.11.0 (pre-release): June 20, 2022
### New Features
* Add inlay hints for parameters and auto types. [#5845](https://github.com/microsoft/vscode-cpptools/issues/5845)
### Bug Fixes
* Fix doxygen comments not being displayed for multiple adjacent `@brief` or `@return` tags. [#9316](https://github.com/microsoft/vscode-cpptools/issues/9316)
* Fix crash if clang-tidy returns a replacement with an empty FilePath. [#9437](https://github.com/microsoft/vscode-cpptools/issues/9437)
* Fix hiding IntelliSense dependent commands when `C_Cpp.intelliSenseEngine` is `"Disabled"`. [#9451](https://github.com/microsoft/vscode-cpptools/issues/9451)
* Fix skipping the compiler argument after `-c`. [#9453](https://github.com/microsoft/vscode-cpptools/issues/9453)
* Fix `-std:c++20` not being handled with cl.exe. [#9458](https://github.com/microsoft/vscode-cpptools/issues/9458)
## Version 1.10.7: June 15, 2022
### Bug Fixes
* Fix bugs with process creation on Windows (which caused IntelliSense to fail). [#9431](https://github.com/microsoft/vscode-cpptools/issues/9431)
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -3457,9 +3457,5 @@
"znaková konstanta UTF-16 nemůže zabírat více než jednu jednotku kódu; hodnota byla zkrácena",
"oba argumenty musí mít stejný typ",
"typ %t není platný jako argument pro tento předdefinovan.",
"voláno z %nd:",
"kvalifikovaný typ je pro anonymní bitová pole nestandardní.",
"typ elementu vektorové podmínky (%t1) musí mít stejnou velikost jako typ elementu výsledku (%t2).",
"typ operandu vektoru s plovoucí desetinnou čárkou (%t) nemá žádný odpovídající celočíselný vektorový typ.",
"mangling pro výrazy requires ještě není implementovaný."
"voláno z %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"Eine UTF-16-Zeichenkonstante darf nicht mehrere Codeeinheiten belegen. Wert abgeschnitten.",
"Beide Argumente müssen denselben Typ aufweisen.",
"Der Typ \"%t\" ist als Argument für dieses integrierte Element ungültig.",
"aufgerufen von %nd:",
"ein qualifizierter Typ ist kein Standard für anonyme Bitfelder",
"der Elementtyp der Vektorbedingung (%t1) muss dieselbe Größe haben wie der Elementtyp des Ergebnisses (%t2)",
"der Gleitkomma-Vektoroperandentyp (%t) hat keinen übereinstimmenden ganzzahligen Vektortyp",
"das Mangling für 'requires'-Ausdrücke ist noch nicht implementiert"
"aufgerufen von %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"una constante de caracteres UTF-16 no puede ocupar más de una unidad de código; valor truncado",
"ambos argumentos deben tener el mismo tipo",
"el tipo %t no es válido como argumento para este elemento integrado",
"llamado desde %nd:",
"un tipo calificado no es estándar para campos de bits anónimos",
"el tipo de elemento de la condición de vector (%t1) debe tener el mismo tamaño que el tipo de elemento del resultado (%t2)",
"el tipo de operando de vector de punto flotante (%t) no tiene ningún tipo de vector entero coincidente",
"aún no se ha implementado la limpieza de expresiones \"requires\""
"llamado desde %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"une constante de caractères UTF-16 ne peut pas occuper plusieurs unités de code ; valeur tronquée",
"les deux arguments doivent avoir le même type",
"le type %t nest pas valide en tant quargument pour ce builtin",
"appelé à partir de %nd :",
"un type qualifié nest pas standard pour les champs de bits anonymes.",
"le type d’élément de la condition vectorielle (%t1) doit avoir la même taille que le type d’élément du résultat (%t2).",
"le type dopérande vectoriel à virgule flottante (%t) na pas de type de vecteur entier correspondant.",
"La gestion des expressions \"requires\" n'est pas encore implémentée."
"appelé à partir de %nd :"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"una costante di caratteri UTF-16 non può occupare più di un'unità di codice; valore troncato",
"entrambi gli argomenti devono avere lo stesso tipo",
"il tipo %t non è valido come argomento per questa compilazione",
"chiamato da %nd:",
"un tipo qualificato non è conforme allo standard per i campi di bit anonimi",
"il tipo di elemento della condizione vettoriale (%t1) deve avere le stesse dimensioni del tipo di elemento del risultato (%t2)",
"il tipo di operando di vettore a virgola mobile (%t) non ha un tipo di vettore intero corrispondente",
"il mangling per le espressioni 'requires' non è ancora implementato"
"chiamato da %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"UTF-16 文字定数は複数のコード単位を占有できません。値が切り捨てられました",
"両方の引数は同じ型である必要があります",
"型 %t は、このビルトインの引数として無効です",
"%nd からの呼び出し:",
"修飾された型は匿名ビット フィールドでは非標準です",
"ベクトル条件 (%t1) の要素型は、結果の要素型 (%t2) と同じサイズである必要があります",
"浮動小数点ベクトル オペランド型 (%t) に一致する整数ベクトル型がありません",
"'requires' 式のためのマングリングは、まだ実装されていません"
"%nd からの呼び出し:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"UTF-16 문자 상수는 코드 단위를 두 개 이상 사용할 수 없음; 값 잘림",
"두 인수의 형식이 같아야 함",
"%t 형식은 이 기본 제공의 인수로 사용할 수 없음",
"%nd에서 호출",
"정규화된 형식이 익명 비트 필드에 대해 표준이 아닙니다.",
"벡터 조건의 요소 유형(%t1)은 결과의 요소 유형(%t2)과 크기가 같아야 합니다.",
"부동 소수점 벡터 피연산자 유형(%t)에 일치하는 정수 벡터 유형이 없습니다.",
"'requires' 식에 대한 mangling이 아직 구현되지 않았습니다."
"%nd에서 호출"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"stała znaków UTF-16 nie może zajmować więcej niż jednej jednostki kodu; obcięta wartość",
"oba argumenty muszą mieć ten sam typ",
"typ %t jest nieprawidłowy jako argument dla tej wbudowanej",
"wywołano z %nd:",
"kwalifikowany typ jest niestandardowy dla anonimowych pól bitowych",
"typ elementu warunku wektora (%t1) musi mieć taki sam rozmiar jak typ elementu wyniku (%t2)",
"typ operandu wektora zmiennoprzecinkowego (%t) nie ma zgodnego typu wektora liczb całkowitych",
"nie jest jeszcze zaimplementowane dekorowanie wyrażeń typu „requires”."
"wywołano z %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"uma constante de caractere UTF-16 não pode ocupar mais de uma unidade de código; valor truncado",
"ambos os argumentos devem ter o mesmo tipo",
"o tipo %téinválido como argumento para este builtin",
"chamado de %nd:",
"um tipo qualificado não é padrão para campos de bits anônimos",
"o tipo de elemento da condição de vetor (%t1) deve ter o mesmo tamanho que o tipo de elemento do resultado (%t2)",
"o tipo de operando vetorial de ponto flutuante (%t) não tem nenhum tipo de vetor inteiro correspondente",
"a estruturação para expressões 'requires' ainda não foi implementada"
"chamado de %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"символьная константа UTF-16 не может занимать более одной кодовой единицы; значение усечено",
"оба аргумента должны быть одного типа",
"тип %t недопустим в качестве аргумента для этой встроенной функции.",
"вызвано из %nd:",
"нестандартный тип с квалификатором для анонимных битовых полей",
"тип элемента векторного условия (%t1) должен иметь тот же размер, что и тип элемента результата (%t2)",
"тип векторного операнда с плавающей запятой (%t) не имеет соответствующего целочисленного векторного типа",
"искажение для выражений \"requires\" еще не реализовано"
"вызвано из %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"UTF-16 karakter sabit değeri, bir kod biriminden fazla yer kaplayamaz; kesilmiş değer",
"her iki bağımsız değişken de aynı türe sahip olmalıdır",
"%t türü bu yerleşik için bağımsız değişken olarak geçersiz",
"%nd kaynağından çağrı:",
"nitelenmiş bir tür adı anonim bit alanları için standart dışı",
"vektör koşulunun öğe türü (%t1), sonucun öğe türü (%t2) ile aynı boyuta sahip olmalıdır",
"kayan nokta vektörü işlenen türü (%t) eşleşen bir tamsayı vektörü türü içermiyor",
"'requires' ifadeleri için değiştirme henüz uygulanmadı"
"%nd kaynağından çağrı:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"UTF-16 字符常量不能占用多个代码单元;值已截断",
"两个参数的类型必须相同",
"类型 %t 无效,不能用作此内置项的参数",
"调用自 %nd:",
"限定类型对于匿名位字段是非标准的",
"向量条件的元素类型(%t1)的大小必须与结果的元素类型相同(%t2)",
"浮点向量操作数类型(%t)没有匹配的整数向量类型",
"尚未实现 “requires” 表达式的变量名压缩"
"调用自 %nd:"
]
+1 -5
View File
@@ -3457,9 +3457,5 @@
"UTF-16 字元常數不可佔用多個程式碼單位; 已截斷值",
"兩個引數的類型必須相同",
"類型 %t 對此內建的引數無效",
"呼叫自 %nd:",
"限定類型對匿名位欄位而言不是標準類型",
"向量條件 (%t1) 的元素類型大小必須與結果的元素類型相同 (%t2)",
"浮點向量運算元類型 (%t) 沒有相符的整數向量類型",
"尚未實作 'requires' 運算式的重整"
"呼叫自 %nd:"
]
@@ -47,7 +47,7 @@
"windows.sdk.version": "Wersja zestawu Windows SDK",
"windows.sdk.version.description": "Wersja ścieżki dyrektywy include zestawu Windows SDK, która ma być używana w systemie Windows, np. {0}.",
"mac.framework.path": "Ścieżka do platformy Mac",
"mac.framework.path.description": "Lista ścieżek do użycia przez aparat IntelliSense podczas wyszukiwania dołączonych nagłówków z platform Mac. Obsługiwane tylko w przypadku konfiguracji dla systemu macOS.",
"mac.framework.path.description": "Lista ścieżek do użycia przez aparat IntelliSense podczas wyszukiwania dołączonych nagłówków z platform Mac. Obsługiwane tylko w przypadku konfiguracji dla systemu MacOS.",
"one.path.per.line": "Jedna ścieżka na wiersz.",
"forced.include": "Wymuszone dołączanie",
"forced.include.description": "Lista plików, które powinny zostać uwzględnione przed przetworzeniem każdego innego znaku w pliku źródłowym. Pliki są uwzględniane w podanej kolejności.",
+41 -937
View File
File diff suppressed because it is too large Load Diff
-36
View File
@@ -166,13 +166,6 @@
"c_cpp.configuration.inactiveRegionOpacity.markdownDescription": { "message": "Controls the opacity of inactive preprocessor blocks. Scales between `0.1` and `1.0`. This setting only applies when inactive region dimming is enabled.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.inactiveRegionForegroundColor.description": "Controls the font coloring of inactive preprocessor blocks. Input is in the form a hexadecimal color code or a valid Theme Color. If not set, this defaults to the syntax coloring scheme of the editor. This setting only applies when inactive region dimming is enabled.",
"c_cpp.configuration.inactiveRegionBackgroundColor.description": "Controls the background coloring of inactive preprocessor blocks. Input is in the form a hexadecimal color code or a valid Theme Color. If not set, this defaults to transparent. This setting only applies when inactive region dimming is enabled.",
"c_cpp.configuration.inlayHints.autoDeclarationTypes.enabled.markdownDescription": { "message": "Display inlay hints for deduced type when `auto` is used in a declaration:\n```cpp \n\n auto index /* : int */ = 0;\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.autoDeclarationTypes.showOnLeft.markdownDescription": { "message": "Display inlay hints for deduced type when `auto` is used in a declaration on the left of the identifier:\n```cpp \n\n auto /* int */ index = 0;\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.enabled.markdownDescription": { "message": "Display inlay hints for parameter names:\n```cpp \n\n int a = getArea(/* width: */ x, /* height: */ y);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.hideLeadingUnderscores.markdownDescription": { "message": "Hide leading `_` in parameter name hints.", "comment": [ "Markdown text between `` is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.suppressWhenArgumentContainsName.markdownDescription": { "message": "Suppress parameter name hints when the argument text or inline comment contains the parameter name:\n```cpp \n\n int a = getArea(width, /* height: */ y);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.referenceOperator.enabled.markdownDescription": { "message": "Display the inlay hint reference operator `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* &first: */ str1, /* &last: */ str2);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.referenceOperator.showSpace.markdownDescription": { "message": "Controls whether a space is shown after `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* & first: */ str1, /* & last: */ str2);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.loggingLevel.markdownDescription": { "message": "The verbosity of logging in the Output Panel. The order of levels from least verbose to most verbose is: `None` < `Error` < `Warning` < `Information` < `Debug`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.autoAddFileAssociations.markdownDescription": { "message": "Controls whether files are automatically added to `#files.associations#` when they are the target of a navigation operation from a C/C++ file.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.workspaceParsingPriority.markdownDescription": { "message": "Controls whether parsing of the non-active workspace files uses sleeps to avoid using 100% CPU. The values `highest`/`high`/`medium`/`low` correspond to approximately 100/75/50/25% CPU usage.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
@@ -301,35 +294,6 @@
"c_cpp.debuggers.hardwareBreakpoints.description": "Explicit control of hardware breakpoint behavior for remote targets.",
"c_cpp.debuggers.hardwareBreakpoints.require.description": "If true, always use hardware breakpoints. Defaults to false.",
"c_cpp.debuggers.hardwareBreakpoints.limit.description": "Optional limit on the number of available hardware breakpoints to use. Only enforced when \"require\" is true and \"limit\" is greater than 0. Defaults to 0.",
"c_cpp.debuggers.variables.description": "Variables for recursive substitution in this launch configuration. Each variable may refer to others.",
"c_cpp.debuggers.variables.properties.description": "Variable for recursive substitution in this launch configuration. The value may refer to other variables.",
"c_cpp.debuggers.host.description": "Host information.",
"c_cpp.debuggers.host.user.description": "User logging into the host.",
"c_cpp.debuggers.host.hostName.description": "Host name.",
"c_cpp.debuggers.host.port.description": "SSH port on the host. Default is 22.",
"c_cpp.debuggers.host.jumpHost.description": "Connect to the target host by first making a connection to the jump hosts.",
"c_cpp.debuggers.host.localForward.description": "Forward connections to the given TCP port or Unix socket on the local (client) host to the given host and port, or Unix socket, on the remote side",
"c_cpp.debuggers.host.localForward.bindAddress.description": "Local address",
"c_cpp.debuggers.host.localForward.port.description": "Local port",
"c_cpp.debuggers.host.localForward.host.description": "Host name",
"c_cpp.debuggers.host.localForward.hostPort.description": "Host port",
"c_cpp.debuggers.host.localForward.localSocket.description": "Local socket",
"c_cpp.debuggers.host.localForward.remoteSocket.description": "Remote socket",
"c_cpp.debuggers.deploySteps.description": "Steps needed to deploy the application. Order matters.",
"c_cpp.debuggers.deploySteps.scp.description": "Copy files using SCP.",
"c_cpp.debuggers.deploySteps.scp.files.description": "Files to be copied via SCP. Supports path pattern.",
"c_cpp.debuggers.deploySteps.scp.targetDir.description": "Target directory.",
"c_cpp.debuggers.deploySteps.scp.scpPath.description": "Optional full path to SCP. Assumes SCP is on PATH if not specified",
"c_cpp.debuggers.deploySteps.debug": "If true, skip when starting without debugging. If false, skip when starting debugging. If undefined, never skip.",
"c_cpp.debuggers.deploySteps.ssh.description": "SSH command step.",
"c_cpp.debuggers.deploySteps.ssh.command.description": "Command to be executed via SSH. The command after '-c' in SSH command.",
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Optional full path to SSH. Assumes SSH is on PATH if not specified",
"c_cpp.debuggers.deploySteps.continueOn.description": "An optional finish pattern in output. When this pattern is seen in the output, continue the deploy procedures regardless of whether this step returns.",
"c_cpp.debuggers.deploySteps.shell.description": "Shell command step.",
"c_cpp.debuggers.deploySteps.shell.command.description": "Shell command to be executed.",
"c_cpp.debuggers.vsCodeCommand.description": "VS Code command to be invoked. Can be a command in VS Code or an active extension.",
"c_cpp.debuggers.vsCodeCommand.command.description": "VS Code command to be invoked.",
"c_cpp.debuggers.vsCodeCommand.args.description": "Arguments to the VS Code command.",
"c_cpp.taskDefinitions.name.description": "The name of the task.",
"c_cpp.taskDefinitions.command.description": "The path to either a compiler or script that performs compilation.",
"c_cpp.taskDefinitions.args.description": "Additional arguments to pass to the compiler or compilation script.",
+20 -197
View File
@@ -23,24 +23,10 @@ import { PlatformInformation } from '../platform';
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
import { CppSettings, OtherSettings } from '../LanguageServer/settings';
import { configPrefix } from '../LanguageServer/extension';
import { expandAllStrings, ExpansionOptions, ExpansionVars } from '../expand';
import { scp, ssh } from '../SSH/commands';
import * as glob from 'glob';
import { promisify } from 'util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
enum StepType {
scp = 'scp',
ssh = 'ssh',
shell = 'shell',
remoteShell = 'remoteShell',
command = 'command'
}
const globAsync: (pattern: string, options?: glob.IOptions | undefined) => Promise<string[]> = promisify(glob);
/*
* Retrieves configurations from a provider and displays them in a quickpick menu to be selected.
* Ensures that the selected configuration's preLaunchTask (if existent) is populated in the user's task.json.
@@ -52,8 +38,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
private assetProvider: IConfigurationAssetProvider;
// Keep a list of tasks detected by cppBuildTaskProvider.
private static detectedBuildTasks: CppBuildTask[] = [];
private static detectedCppBuildTasks: CppBuildTask[] = [];
private static detectedCBuildTasks: CppBuildTask[] = [];
protected static recentBuildTaskLabel: string;
public constructor(assetProvider: IConfigurationAssetProvider, type: DebuggerType) {
@@ -111,7 +95,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const selection: ConfigMenu | undefined = await vscode.window.showQuickPick(this.localizeConfigDetail(items), {placeHolder: localize("select.configuration", "Select a configuration")});
if (!selection) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": "debug", "configSource": ConfigSource.unknown, "configMode": ConfigMode.unknown, "cancelled": "true", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": "debug", "configSource": ConfigSource.unknown, "configMode": ConfigMode.unknown, "cancelled": "true", "success": "true" });
return []; // User canceled it.
}
@@ -135,7 +119,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// resolveDebugConfiguration will be automatically called after calling provideDebugConfigurations.
const configs: CppDebugConfiguration[]= await this.provideDebugConfigurations(folder);
if (!configs || configs.length === 0) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile, "configMode": ConfigMode.noLaunchConfig, "cancelled": "true", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile, "configMode": ConfigMode.noLaunchConfig, "cancelled": "true", "success": "true" });
return undefined; // aborts debugging silently
} else {
// Currently, we expect only one debug config to be selected.
@@ -169,9 +153,9 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
try {
await cppBuildTaskProvider.runBuildTask(config.preLaunchTask);
config.preLaunchTask = undefined;
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "true" });
} catch (err) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "false" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "false" });
}
return config;
}
@@ -196,7 +180,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
config.debugType = config.debugType ? config.debugType : DebugType.debug;
const configMode: ConfigMode = isExistingConfig ? ConfigMode.launchConfig : ConfigMode.noLaunchConfig;
// if configuration.debuggerEvent === undefined, it means this configuration is already defined in launch.json and is shown in debugPanel.
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "succeeded": "true" });
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "success": "true" });
if (!resolveByVsCode) {
if ((singleFile || (isDebugPanel && !folder && isExistingTask))) {
@@ -219,11 +203,11 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
* This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted.
* This is also ran after the tasks.json has completed.
*
* Try to add all missing attributes to the debug configuration being launched.
* Try to add all missing attributes to the debug configuration being launched.
* If return "undefined", the debugging will be aborted silently.
* If return "null", the debugging will be aborted and launch.json will be opened.
*/
async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): Promise<CppDebugConfiguration | null | undefined> {
*/
resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult<CppDebugConfiguration> {
if (!config || !config.type) {
return undefined; // Abort debugging silently.
}
@@ -246,7 +230,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Disable debug heap by default, enable if 'enableDebugHeap' is set.
if (!config.enableDebugHeap) {
const disableDebugHeapEnvSetting: Environment = { "name": "_NO_DEBUG_HEAP", "value": "1" };
const disableDebugHeapEnvSetting: Environment = {"name" : "_NO_DEBUG_HEAP", "value" : "1"};
if (config.environment && util.isArray(config.environment)) {
config.environment.push(disableDebugHeapEnvSetting);
@@ -259,8 +243,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Add environment variables from .env file
this.resolveEnvFile(config, folder);
await this.expand(config, folder);
this.resolveSourceFileMapVariables(config);
// Modify WSL config for OpenDebugAD7
@@ -323,19 +305,6 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// logger.showOutputChannel();
}
// Run deploy steps
if (config.deploySteps && config.deploySteps.length !== 0) {
const codeVersion: number[] = vscode.version.split('.').map(num => parseInt(num, undefined));
if ((util.isNumber(codeVersion[0]) && codeVersion[0] < 1) || (util.isNumber(codeVersion[0]) && codeVersion[0] === 1 && util.isNumber(codeVersion[1]) && codeVersion[1] < 69)) {
logger.getOutputChannelLogger().showErrorMessage(localize("vs.code.1.69+.required", "'deploySteps' require VS Code 1.69+."));
return undefined;
}
const deploySucceeded: boolean = await this.deploySteps(config, token);
if (!deploySucceeded || token?.isCancellationRequested) {
return undefined;
}
}
return config;
}
@@ -480,44 +449,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
private async loadDetectedTasks(): Promise<void> {
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
const emptyTasks: CppBuildTask[] = [];
if (!editor) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
const fileExt: string = path.extname(editor.document.fileName);
if (!fileExt) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
// Don't offer tasks for header files.
const isHeader: boolean = util.isHeaderFile (editor.document.uri);
if (isHeader) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
// Don't offer tasks if the active file's extension is not a recognized C/C++ extension.
const fileIsCpp: boolean = util.isCppFile(editor.document.uri);
const fileIsC: boolean = util.isCFile(editor.document.uri);
if (!(fileIsCpp || fileIsC)) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
if (fileIsCpp) {
if (!DebugConfigurationProvider.detectedCppBuildTasks || DebugConfigurationProvider.detectedCppBuildTasks.length === 0) {
DebugConfigurationProvider.detectedCppBuildTasks = await cppBuildTaskProvider.getTasks(true);
}
DebugConfigurationProvider.detectedBuildTasks = DebugConfigurationProvider.detectedCppBuildTasks;
} else {
if (!DebugConfigurationProvider.detectedCBuildTasks || DebugConfigurationProvider.detectedCBuildTasks.length === 0) {
DebugConfigurationProvider.detectedCBuildTasks = await cppBuildTaskProvider.getTasks(true);
}
DebugConfigurationProvider.detectedBuildTasks = DebugConfigurationProvider.detectedCBuildTasks;
if (!DebugConfigurationProvider.detectedBuildTasks || DebugConfigurationProvider.detectedBuildTasks.length === 0) {
DebugConfigurationProvider.detectedBuildTasks = await cppBuildTaskProvider.getTasks(true);
}
}
@@ -624,17 +557,17 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, undefined);
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += (message ? ' ' : '\t');
message += localize("replacing.targetpath", "Replacing {0} '{1}' with '{2}'.", "targetPath", sourceFileMapTarget, newSourceFileMapTarget);
target = newSourceFileMapTarget;
}
} else if (util.isObject(sourceFileMapTarget)) {
const newSourceFileMapTarget: { "editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
const newSourceFileMapTarget: {"editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
newSourceFileMapTarget["editorPath"] = util.resolveVariables(sourceFileMapTarget["editorPath"], undefined);
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += (message ? ' ' : '\t');
message += localize("replacing.editorPath", "Replacing {0} '{1}' with '{2}'.", "editorPath", sourceFileMapTarget, newSourceFileMapTarget["editorPath"]);
target = newSourceFileMapTarget;
}
@@ -830,7 +763,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, false, true);
if (!selectedConfig) {
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "true", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "true", "success": "true" });
return; // User canceled it.
}
@@ -847,7 +780,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
selectedConfig.debuggerEvent = undefined;
// Write debug configuration in launch.json file.
await this.writeDebugConfig(selectedConfig, isExistingConfig, folder);
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "true" });
}
public async buildAndRun(textEditor: vscode.TextEditor): Promise<void> {
@@ -859,7 +792,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
let folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
const selectedConfig: CppDebugConfiguration | undefined = await this.selectConfiguration(textEditor);
if (!selectedConfig) {
Telemetry.logDebuggerEvent(DebuggerEvent.playButton, { "debugType": debugModeOn ? DebugType.debug : DebugType.run, "configSource": ConfigSource.unknown, "cancelled": "true", "succeeded": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.playButton, { "debugType": debugModeOn ? DebugType.debug : DebugType.run, "configSource": ConfigSource.unknown, "cancelled": "true", "success": "true" });
return; // User canceled it.
}
@@ -873,7 +806,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
selectedConfig.debugType = debugModeOn ? DebugType.debug : DebugType.run;
// startDebugging will trigger a call to resolveDebugConfiguration.
await vscode.debug.startDebugging(folder, selectedConfig, { noDebug: !debugModeOn });
await vscode.debug.startDebugging(folder, selectedConfig, {noDebug: !debugModeOn});
}
private async selectConfiguration(textEditor: vscode.TextEditor, pickDefault: boolean = true, onlyWorkspaceFolder: boolean = false): Promise<CppDebugConfiguration | undefined> {
@@ -937,120 +870,10 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
if (e && e.message === util.failedToParseJson) {
vscode.window.showErrorMessage(util.failedToParseJson);
}
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "succeeded": "false" });
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "success": "false" });
}
}
}
private async expand(config: vscode.DebugConfiguration, folder: vscode.WorkspaceFolder | undefined): Promise<void> {
const folderPath: string | undefined = folder?.uri.fsPath || vscode.workspace.workspaceFolders?.[0].uri.fsPath;
const vars: ExpansionVars = config.variables ? config.variables : {};
vars.workspaceFolder = folderPath || '{workspaceFolder}';
vars.workspaceFolderBasename = folderPath ? path.basename(folderPath) : '{workspaceFolderBasename}';
const expansionOptions: ExpansionOptions = { vars, recursive: true };
return expandAllStrings(config, expansionOptions);
}
// Returns true when ALL steps succeed; stop all subsequent steps if one fails
private async deploySteps(config: vscode.DebugConfiguration, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
let succeeded: boolean = true;
const deployStart: number = new Date().getTime();
for (const step of config.deploySteps) {
succeeded = await this.singleDeployStep(config, step, cancellationToken);
if (!succeeded) {
break;
}
}
const deployEnd: number = new Date().getTime();
const telemetryProperties: { [key: string]: string } = {
Succeeded: `${succeeded}`,
IsDebugging: `${!config.noDebug || false}`
};
const telemetryMetrics: { [key: string]: number } = {
NumSteps: config.deploySteps.length,
Duration: deployEnd - deployStart
};
Telemetry.logDebuggerEvent('deploy', telemetryProperties, telemetryMetrics);
return succeeded;
}
private async singleDeployStep(config: vscode.DebugConfiguration, step: any, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
if ((config.noDebug && step.debug === true) || (!config.noDebug && step.debug === false)) {
// Skip steps that doesn't match current launch mode. Explicit true/false check, since a step is always run when debug is undefined.
return true;
}
switch (step.type) {
case StepType.command: {
// VS Code commands are the same regardless of which extension invokes them, so just invoke them here.
if (step.args && !Array.isArray(step.args)) {
logger.getOutputChannelLogger().showErrorMessage(localize('command.args.must.be.array', '"args" in command deploy step must be an array.'));
return false;
}
const returnCode: unknown = await vscode.commands.executeCommand(step.command, ...step.args);
return !returnCode;
}
case StepType.scp: {
if (!step.files || !step.targetDir || !step.host) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.scp', '"host", "files", and "targetDir" are required in scp steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
let files: vscode.Uri[] = [];
if (util.isString(step.files)) {
files = files.concat((await globAsync(step.files)).map(file => vscode.Uri.file(file)));
} else if (util.isArrayOfString(step.files)) {
for (const fileGlob of (step.files as string[])) {
files = files.concat((await globAsync(fileGlob)).map(file => vscode.Uri.file(file)));
}
} else {
logger.getOutputChannelLogger().showErrorMessage(localize('incorrect.files.type.scp', '"files" must be a string or an array of strings in scp steps.'));
return false;
}
const scpResult: util.ProcessReturnType = await scp(files, host, step.targetDir, config.scpPath, jumpHosts, cancellationToken);
if (!scpResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.ssh: {
if (!step.host || !step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.ssh', '"host" and "command" are required for ssh steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
const localForwards: util.ISshLocalForwardInfo[] = step.host.localForwards;
const continueOn: string = step.continueOn;
const sshResult: util.ProcessReturnType = await ssh(host, step.command, config.sshPath, jumpHosts, localForwards, continueOn, cancellationToken);
if (!sshResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.shell: {
if (!step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.shell', '"command" is required for shell steps.'));
return false;
}
const taskResult: util.ProcessReturnType = await util.spawnChildProcess(step.command, undefined, step.continueOn);
if (!taskResult.succeeded || cancellationToken?.isCancellationRequested) {
logger.getOutputChannelLogger().showErrorMessage(taskResult.output);
return false;
}
break;
}
default: {
logger.getOutputChannelLogger().appendLine(localize('deploy.step.type.not.supported', 'Deploy step type {0} is not supported.', step.type));
return false;
}
}
return true;
}
}
export interface IConfigurationAssetProvider {
@@ -1203,7 +1026,7 @@ export class ConfigurationSnippetProvider implements vscode.CompletionItemProvid
items = [];
// Make a copy of each snippet since we are adding a comma to the end of the insertText.
this.snippets.forEach((item) => items.push({ ...item }));
this.snippets.forEach((item) => items.push({...item}));
items.map((item) => {
item.insertText = item.insertText + ','; // Add comma
@@ -4,12 +4,13 @@
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient';
import { DefaultClient } from '../client';
import * as util from '../../common';
import { CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisFileToCodeActions, codeAnalysisCodeToFixes,
codeAnalysisAllFixes } from '../codeAnalysis';
codeAnalysisAllFixes, DefaultClient } from '../client';
import { makeVscodeRange } from '../utils';
import { CppSettings } from '../settings';
import { getLocalizedString, LocalizeStringParams } from '../localization';
type LocalizeStringParams = util.LocalizeStringParams;
interface GetCodeActionsRequestParams {
uri: string;
@@ -61,7 +62,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
// Convert to vscode.CodeAction array
commands.forEach((command) => {
const title: string = getLocalizedString(command.localizeStringParams);
const title: string = util.getLocalizedString(command.localizeStringParams);
let wsEdit: vscode.WorkspaceEdit | undefined;
let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix;
if (command.edit) {
@@ -4,9 +4,9 @@
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { DefaultClient, LocalizeDocumentSymbol, GetDocumentSymbolRequestParams, GetDocumentSymbolRequest, SymbolScope } from '../client';
import * as util from '../../common';
import { processDelayedDidOpen } from '../extension';
import { makeVscodeRange } from '../utils';
import { getLocalizedString, getLocalizedSymbolScope } from '../localization';
export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
private client: DefaultClient;
@@ -17,18 +17,18 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
const documentSymbols: vscode.DocumentSymbol[] = [];
if (symbols) {
symbols.forEach((symbol) => {
let detail: string = getLocalizedString(symbol.detail);
let detail: string = util.getLocalizedString(symbol.detail);
if (symbol.scope === SymbolScope.Private) {
if (detail.length === 0) {
detail = "private";
} else {
detail = getLocalizedSymbolScope("private", detail);
detail = util.getLocalizedSymbolScope("private", detail);
}
} else if (symbol.scope === SymbolScope.Protected) {
if (detail.length === 0) {
detail = "protected";
} else {
detail = getLocalizedSymbolScope("protected", detail);
detail = util.getLocalizedSymbolScope("protected", detail);
}
}
@@ -1,163 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { DefaultClient, openFileVersions } from '../client';
import { Position, RequestType } from 'vscode-languageclient';
import { CppSettings } from '../settings';
interface GetInlayHintsParams {
uri: string;
}
enum InlayHintKind {
Type = 0,
Parameter = 1,
}
interface CppInlayHint {
position: Position;
label: string;
inlayHintKind: InlayHintKind;
isValueRef: boolean;
hasParamName: boolean;
leftPadding: boolean;
rightPadding: boolean;
identifierLength: number;
}
interface GetInlayHintsResult {
fileVersion: number;
canceled: boolean;
inlayHints: CppInlayHint[];
}
type InlayHintsCacheEntry = {
FileVersion: number;
TypeHints: vscode.InlayHint[];
ParameterHints: CppInlayHint[];
};
const GetInlayHintsRequest: RequestType<GetInlayHintsParams, GetInlayHintsResult, void, void> =
new RequestType<GetInlayHintsParams, GetInlayHintsResult, void, void>('cpptools/getInlayHints');
export class InlayHintsProvider implements vscode.InlayHintsProvider {
private client: DefaultClient;
public onDidChangeInlayHintsEvent = new vscode.EventEmitter<void>();
public onDidChangeInlayHints?: vscode.Event<void>;
private cache: Map<string, InlayHintsCacheEntry> = new Map<string, InlayHintsCacheEntry>();
constructor(client: DefaultClient) {
this.client = client;
this.onDidChangeInlayHints = this.onDidChangeInlayHintsEvent.event;
}
public async provideInlayHints(document: vscode.TextDocument, range: vscode.Range,
token: vscode.CancellationToken): Promise<vscode.InlayHint[] | undefined> {
await this.client.awaitUntilLanguageClientReady();
const uriString: string = document.uri.toString();
// Get results from cache if available.
const cacheEntry: InlayHintsCacheEntry | undefined = this.cache.get(uriString);
if (cacheEntry?.FileVersion === document.version) {
return this.buildVSCodeHints(cacheEntry);
}
// Get new results from the language server
const params: GetInlayHintsParams = { uri: uriString };
const inlayHintsResult: GetInlayHintsResult = await this.client.languageClient.sendRequest(GetInlayHintsRequest, params, token);
if (!inlayHintsResult.canceled) {
if (inlayHintsResult.fileVersion === openFileVersions.get(uriString)) {
const cacheEntry: InlayHintsCacheEntry = this.createCacheEntry(inlayHintsResult);
this.cache.set(uriString, cacheEntry);
return this.buildVSCodeHints(cacheEntry);
} else {
// Force another request because file versions do not match.
this.onDidChangeInlayHintsEvent.fire();
}
}
return undefined;
}
public invalidateFile(uri: string): void {
this.cache.delete(uri);
this.onDidChangeInlayHintsEvent.fire();
}
private buildVSCodeHints(cacheEntry: InlayHintsCacheEntry): vscode.InlayHint[] {
let result: vscode.InlayHint[] = [];
const settings: CppSettings = new CppSettings();
if (settings.inlayHintsAutoDeclarationTypes) {
result = result.concat(cacheEntry?.TypeHints);
}
const resolvedParameterHints: vscode.InlayHint[] = this.resolveParameterHints(cacheEntry.ParameterHints);
result = result.concat(resolvedParameterHints);
return result;
}
private resolveParameterHints(hints: CppInlayHint[]): vscode.InlayHint[] {
const resolvedHints: vscode.InlayHint[] = [];
const settings: CppSettings = new CppSettings();
for (const hint of hints) {
// Build parameter label based on settings.
let paramHintLabel: string = "";
if (settings.inlayHintsParameterNames) {
paramHintLabel = (settings.inlayHintsParameterNamesSuppressName && hint.hasParamName) ? "" : hint.label;
if (paramHintLabel !== "" && settings.inlayHintsParameterNamesHideLeadingUnderscores) {
let nonUnderscoreIndex: number = 0;
for (let i: number = 0; i < paramHintLabel.length; ++i) {
if (paramHintLabel[i] !== '_') {
nonUnderscoreIndex = i;
break;
}
}
if (nonUnderscoreIndex > 0) {
paramHintLabel = paramHintLabel.substring(nonUnderscoreIndex);
}
}
}
let refOperatorString: string = "";
if (settings.inlayHintsReferenceOperator && hint.isValueRef) {
refOperatorString = (paramHintLabel.length > 0 && settings.inlayHintsReferenceOperatorShowSpace) ? "& " : "&";
}
let label: string = "";
if (paramHintLabel.length > 0 || refOperatorString.length > 0) {
label = refOperatorString + paramHintLabel + ":";
}
const inlayHint: vscode.InlayHint = new vscode.InlayHint(
new vscode.Position(hint.position.line, hint.position.character),
label,
vscode.InlayHintKind.Parameter);
inlayHint.paddingRight = true;
resolvedHints.push(inlayHint);
};
return resolvedHints;
}
private createCacheEntry(inlayHintsResults: GetInlayHintsResult): InlayHintsCacheEntry {
const typeHints: vscode.InlayHint[] = [];
const settings: CppSettings = new CppSettings();
for (const h of inlayHintsResults.inlayHints) {
if (h.inlayHintKind === InlayHintKind.Type) {
const showOnLeft: boolean = settings.inlayHintsAutoDeclarationTypesShowOnLeft && h.identifierLength > 0;
const inlayHint: vscode.InlayHint = new vscode.InlayHint(
new vscode.Position(h.position.line, h.position.character +
(showOnLeft ? 0 : h.identifierLength)),
(showOnLeft ? h.label : ": " + h.label),
vscode.InlayHintKind.Type);
inlayHint.paddingRight = showOnLeft || h.rightPadding;
inlayHint.paddingLeft = showOnLeft && h.leftPadding;
typeHints.push(inlayHint);
}
}
const paramHints: CppInlayHint[] = inlayHintsResults.inlayHints.filter(h => h.inlayHintKind === InlayHintKind.Parameter);
const cacheEntry: InlayHintsCacheEntry = {
FileVersion: inlayHintsResults.fileVersion,
TypeHints: typeHints,
ParameterHints: paramHints
};
return cacheEntry;
}
}
@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { DefaultClient, GetSymbolInfoRequest, WorkspaceSymbolParams, LocalizeSymbolInformation, SymbolScope } from '../client';
import { makeVscodeLocation } from '../utils';
import { getLocalizedString, getLocalizedSymbolScope } from '../localization';
import * as util from '../../common';
export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
private client: DefaultClient;
@@ -23,13 +23,13 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
// Convert to vscode.Command array
symbols.forEach((symbol) => {
let suffix: string = getLocalizedString(symbol.suffix);
let suffix: string = util.getLocalizedString(symbol.suffix);
let name: string = symbol.name;
if (suffix.length) {
if (symbol.scope === SymbolScope.Private) {
suffix = getLocalizedSymbolScope("private", suffix);
suffix = util.getLocalizedSymbolScope("private", suffix);
} else if (symbol.scope === SymbolScope.Protected) {
suffix = getLocalizedSymbolScope("protected", suffix);
suffix = util.getLocalizedSymbolScope("protected", suffix);
}
name = name + ' (' + suffix + ')';
} else {
+551 -41
View File
@@ -7,7 +7,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
// Start provider imports
// Importing providers here
import { OnTypeFormattingEditProvider } from './Providers/onTypeFormattingEditProvider';
import { FoldingRangeProvider } from './Providers/foldingRangeProvider';
import { SemanticTokensProvider } from './Providers/semanticTokensProvider';
@@ -18,16 +18,13 @@ import { WorkspaceSymbolProvider } from './Providers/workspaceSymbolProvider';
import { RenameProvider } from './Providers/renameProvider';
import { FindAllReferencesProvider } from './Providers/findAllReferencesProvider';
import { CodeActionProvider } from './Providers/codeActionProvider';
import { InlayHintsProvider } from './Providers/inlayHintProvider';
// End provider imports
import { LanguageClient, LanguageClientOptions, ServerOptions, NotificationType, TextDocumentIdentifier, RequestType, ErrorAction, CloseAction, DidOpenTextDocumentParams, Range, Position, DocumentFilter } from 'vscode-languageclient';
import { SourceFileConfigurationItem, WorkspaceBrowseConfiguration, SourceFileConfiguration, Version } from 'vscode-cpptools';
import { Status, IntelliSenseStatus } from 'vscode-cpptools/out/testApi';
import { getLocaleId, getLocalizedString, LocalizeStringParams } from './localization';
import { Location, TextEdit } from './commonTypes';
import { makeVscodeRange, makeVscodeLocation } from './utils';
import * as util from '../common';
import { Location, makeVscodeRange, makeVscodeLocation, makeVscodeTextEdits, rangeEquals, TextEdit } from './utils';
import * as configs from './configurations';
import { CppSettings, getEditorConfigSettings, OtherSettings } from './settings';
import * as telemetry from '../telemetry';
@@ -37,6 +34,7 @@ import { ClientCollection } from './clientCollection';
import { createProtocolFilter } from './protocolFilter';
import { DataBinding } from './dataBinding';
import minimatch = require("minimatch");
import * as logger from '../logger';
import { updateLanguageConfigurations, CppSourceStr } from './extension';
import { SettingsTracker, getTracker } from './settingsTracker';
import { getTestHook, TestHook } from '../testHook';
@@ -46,12 +44,10 @@ import * as os from 'os';
import * as refs from './references';
import * as nls from 'vscode-nls';
import { lookupString, localizedStringCount } from '../nativeStrings';
import { CodeAnalysisDiagnosticIdentifiersAndUri, RegisterCodeAnalysisNotifications, removeAllCodeAnalysisProblems,
removeCodeAnalysisProblems, RemoveCodeAnalysisProblemsParams } from './codeAnalysis';
import { DebugProtocolParams, getDiagnosticsChannel, getOutputChannelLogger, logDebugProtocol, Logger, logLocalized, showWarning, ShowWarningParams } from '../logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
type LocalizeStringParams = util.LocalizeStringParams;
let ui: UI;
let timeStamp: number = 0;
@@ -64,7 +60,78 @@ const languageClientCrashTimes: number[] = [];
let clientCollection: ClientCollection;
let pendingTask: util.BlockingTask<any> | undefined;
let compilerDefaults: configs.CompilerDefaults;
let diagnosticsChannel: vscode.OutputChannel;
let outputChannel: vscode.OutputChannel;
let debugChannel: vscode.OutputChannel;
let warningChannel: vscode.OutputChannel;
let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection;
let diagnosticsCollectionCodeAnalysis: vscode.DiagnosticCollection;
export interface CodeActionDiagnosticInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
// Used to work around https://github.com/microsoft/vscode/issues/126393.
// If that bug were fixed, then we could use the vscode.CodeAction.diagnostic directly.
range: vscode.Range;
code: string;
fixCodeAction?: vscode.CodeAction;
// suppressCodeAction?: vscode.CodeAction; // TODO?
removeCodeAction?: vscode.CodeAction;
}
// Used to handle fix invalidation after an edit,
// i.e. it's set to undefined if it becomes invalid.
interface CodeActionWorkspaceEdit {
workspaceEdit?: vscode.WorkspaceEdit;
}
interface CodeActionPerUriInfo {
// These two arrays have the same length, i.e. index i of identifiers
// is used to index into workspaceEdits to get the corresponding edit.
identifiers: CodeAnalysisDiagnosticIdentifier[];
workspaceEdits?: CodeActionWorkspaceEdit[];
// Used to quickly determine how many non-undefined entries are in "workspaceEdits"
// (so the array doesn't have to be iterated through).
numValidWorkspaceEdits: number;
}
// Tracks the "type" code actions (i.e. "code" is a synonym for "type" in this context).
export interface CodeActionCodeInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
// Needed to quickly update the "type" action for a file.
uriToInfo: Map<string, CodeActionPerUriInfo>;
fixAllTypeCodeAction?: vscode.CodeAction;
disableAllTypeCodeAction?: vscode.CodeAction;
removeAllTypeCodeAction?: vscode.CodeAction;
docCodeAction?: vscode.CodeAction;
}
interface CodeActionAllInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
fixAllCodeAction: vscode.CodeAction;
removeAllCodeAction: vscode.CodeAction;
}
export const codeAnalysisFileToCodeActions: Map<string, CodeActionDiagnosticInfo[]> = new Map<string, CodeActionDiagnosticInfo[]>();
export const codeAnalysisCodeToFixes: Map<string, CodeActionCodeInfo> = new Map<string, CodeActionCodeInfo>();
export const codeAnalysisAllFixes: CodeActionAllInfo = {
version: 0,
fixAllCodeAction: {
title: localize("fix_all_code_analysis_problems", "Fix all code analysis problems"),
command: { title: 'FixAllCodeAnalysisProblems', command: 'C_Cpp.FixAllCodeAnalysisProblems',
arguments: [ 0, undefined, true, [] ] },
kind: vscode.CodeActionKind.QuickFix
},
removeAllCodeAction: {
title: localize("clear_all_code_analysis_problems", "Clear all code analysis problems"),
command: { title: "RemoveAllCodeAnalysisProblems", command: "C_Cpp.RemoveAllCodeAnalysisProblems" },
kind: vscode.CodeActionKind.QuickFix
}
};
let workspaceDisposables: vscode.Disposable[] = [];
export let workspaceReferences: refs.ReferencesManager;
@@ -87,16 +154,38 @@ function logTelemetry(notificationBody: TelemetryPayload): void {
function setupOutputHandlers(): void {
console.assert(languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
languageClient.onNotification(DebugProtocolNotification, logDebugProtocol);
languageClient.onNotification(DebugProtocolNotification, (output) => {
if (!debugChannel) {
debugChannel = vscode.window.createOutputChannel(`${localize("c.cpp.debug.protocol", "C/C++ Debug Protocol")}`);
workspaceDisposables.push(debugChannel);
}
debugChannel.appendLine("");
debugChannel.appendLine("************************************************************************************************************************");
debugChannel.append(`${output}`);
});
languageClient.onNotification(DebugLogNotification, logLocalized);
}
function log(output: string): void {
if (!outputChannel) {
outputChannel = logger.getOutputChannel();
workspaceDisposables.push(outputChannel);
}
outputChannel.appendLine(`${output}`);
}
function logLocalized(params: LocalizeStringParams): void {
const output: string = util.getLocalizedString(params);
log(output);
}
/** Note: We should not await on the following functions,
* or any funstion that returns a promise acquired from them,
* vscode.window.showInformationMessage, vscode.window.showWarningMessage, vscode.window.showErrorMessage
*/
function showMessageWindow(params: ShowMessageWindowParams): void {
const message: string = getLocalizedString(params.localizeStringParams);
const message: string = util.getLocalizedString(params.localizeStringParams);
switch (params.type) {
case 1: // Error
vscode.window.showErrorMessage(message);
@@ -113,6 +202,21 @@ function showMessageWindow(params: ShowMessageWindowParams): void {
}
}
function showWarning(params: ShowWarningParams): void {
const message: string = util.getLocalizedString(params.localizeStringParams);
let showChannel: boolean = false;
if (!warningChannel) {
warningChannel = vscode.window.createOutputChannel(`${localize("c.cpp.warnings", "C/C++ Configuration Warnings")}`);
workspaceDisposables.push(warningChannel);
showChannel = true;
}
// Append before showing the channel, to avoid a delay.
warningChannel.appendLine(`[${new Date().toLocaleString()}] ${message}`);
if (showChannel) {
warningChannel.show(true);
}
}
function publishIntelliSenseDiagnostics(params: PublishIntelliSenseDiagnosticsParams): void {
if (!diagnosticsCollectionIntelliSense) {
diagnosticsCollectionIntelliSense = vscode.languages.createDiagnosticCollection(CppSourceStr);
@@ -121,7 +225,7 @@ function publishIntelliSenseDiagnostics(params: PublishIntelliSenseDiagnosticsPa
// Convert from our Diagnostic objects to vscode Diagnostic objects
const diagnosticsIntelliSense: vscode.Diagnostic[] = [];
params.diagnostics.forEach((d) => {
const message: string = getLocalizedString(d.localizeStringParams);
const message: string = util.getLocalizedString(d.localizeStringParams);
const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(makeVscodeRange(d.range), message, d.severity);
diagnostic.code = d.code;
diagnostic.source = CppSourceStr;
@@ -141,6 +245,328 @@ function publishIntelliSenseDiagnostics(params: PublishIntelliSenseDiagnosticsPa
clientCollection.timeTelemetryCollector.setUpdateRangeTime(realUri);
}
// Rebuild codeAnalysisCodeToFixes and codeAnalysisAllFixes.fixAllCodeActions.
function rebuildCodeAnalysisCodeAndAllFixes(): void {
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[0] = ++codeAnalysisAllFixes.version;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = [];
}
const identifiersAndUrisForAllFixes: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
const uriToEditsForAll: Map<vscode.Uri, vscode.TextEdit[]> = new Map<vscode.Uri, vscode.TextEdit[]>();
let numFixTypes: number = 0;
for (const codeToFixes of codeAnalysisCodeToFixes) {
const identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
const uriToEdits: Map<vscode.Uri, vscode.TextEdit[]> = new Map<vscode.Uri, vscode.TextEdit[]>();
codeToFixes[1].uriToInfo.forEach((perUriInfo: CodeActionPerUriInfo, uri: string) => {
const newIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: uri, identifiers: perUriInfo.identifiers };
identifiersAndUris.push(newIdentifiersAndUri);
if (perUriInfo.workspaceEdits === undefined || perUriInfo.numValidWorkspaceEdits === 0) {
return;
}
identifiersAndUrisForAllFixes.push(newIdentifiersAndUri);
for (const edit of perUriInfo.workspaceEdits) {
if (edit.workspaceEdit === undefined) {
continue;
}
for (const [uri, edits] of edit.workspaceEdit.entries()) {
const textEdits: vscode.TextEdit[] = uriToEdits.get(uri) ?? [];
textEdits.push(...edits);
uriToEdits.set(uri, textEdits);
const textEditsForAll: vscode.TextEdit[] = uriToEditsForAll.get(uri) ?? [];
textEditsForAll.push(...edits);
uriToEditsForAll.set(uri, textEdits);
}
}
});
if (uriToEdits.size > 0) {
const allTypeWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uri, edits] of uriToEdits.entries()) {
allTypeWorkspaceEdit.set(uri, edits);
}
++numFixTypes;
codeToFixes[1].fixAllTypeCodeAction = {
title: localize("fix_all_type_problems", "Fix all {0} problems", codeToFixes[0]),
command: { title: 'FixAllTypeCodeAnalysisProblems', command: 'C_Cpp.FixAllTypeCodeAnalysisProblems',
arguments: [ codeToFixes[0], ++codeToFixes[1].version, allTypeWorkspaceEdit, true, identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
}
if (new CppSettings().clangTidyCodeActionShowDisable) {
codeToFixes[1].disableAllTypeCodeAction = {
title: localize("disable_all_type_problems", "Disable all {0} problems", codeToFixes[0]),
command: { title: 'DisableAllTypeCodeAnalysisProblems', command: 'C_Cpp.DisableAllTypeCodeAnalysisProblems',
arguments: [ codeToFixes[0], identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
} else {
codeToFixes[1].disableAllTypeCodeAction = undefined;
}
if (new CppSettings().clangTidyCodeActionShowClear !== "None") {
codeToFixes[1].removeAllTypeCodeAction = {
title: localize("clear_all_type_problems", "Clear all {0} problems", codeToFixes[0]),
command: { title: 'RemoveAllTypeCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems',
arguments: [ false, identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
}
}
if (numFixTypes > 1) {
const allWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uri, edits] of uriToEditsForAll.entries()) {
allWorkspaceEdit.set(uri, edits);
}
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = allWorkspaceEdit;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = identifiersAndUrisForAllFixes;
}
} else {
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined;
}
}
}
function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagnosticsParams): void {
if (!diagnosticsCollectionCodeAnalysis) {
diagnosticsCollectionCodeAnalysis = vscode.languages.createDiagnosticCollection("clang-tidy");
}
// Convert from our Diagnostic objects to vscode Diagnostic objects
const diagnosticsCodeAnalysis: vscode.Diagnostic[] = [];
const realUri: vscode.Uri = vscode.Uri.parse(params.uri);
// Reset codeAnalysisCodeToFixes for the file.
for (const codeToFixes of codeAnalysisCodeToFixes) {
++codeToFixes[1].version;
if (codeToFixes[1].uriToInfo.has(params.uri)) {
codeToFixes[1].uriToInfo.delete(params.uri);
}
}
const previousDiagnostics: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(params.uri);
let nextVersion: number = 0;
if (previousDiagnostics !== undefined) {
for (const diagnostic of previousDiagnostics) {
if (diagnostic.version > nextVersion) {
nextVersion = diagnostic.version;
}
}
}
++nextVersion;
const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] = [];
for (const d of params.diagnostics) {
const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(makeVscodeRange(d.range),
util.getLocalizedString(d.localizeStringParams), d.severity);
const identifier: CodeAnalysisDiagnosticIdentifier = { range: d.range, code: d.code };
const identifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: params.uri, identifiers: [ identifier ] };
const codeAction: CodeActionDiagnosticInfo = {
version: nextVersion,
range: makeVscodeRange(identifier.range),
code: identifier.code,
removeCodeAction: {
title: localize("clear_this_problem", "Clear this {0} problem", d.code),
command: { title: 'RemoveCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems',
arguments: [ false, [ identifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
}
};
const workspaceEdit: CodeActionWorkspaceEdit = {};
if (d.workspaceEdit) {
workspaceEdit.workspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(d.workspaceEdit.changes)) {
workspaceEdit.workspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
}
const fixThisCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem',
arguments: [ nextVersion, workspaceEdit.workspaceEdit, true, [ identifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
};
codeAction.fixCodeAction = fixThisCodeAction;
}
// Edits from clang-tidy can be associated with the related information instead of the root diagnostic.
const relatedCodeActions: CodeActionDiagnosticInfo[] = [];
const rootAndRelatedWorkspaceEdits: CodeActionWorkspaceEdit[] = [];
const rootAndRelatedIdentifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
if (workspaceEdit.workspaceEdit !== undefined) {
rootAndRelatedWorkspaceEdits.push(workspaceEdit);
rootAndRelatedIdentifiersAndUris.push(identifiersAndUri);
}
if (d.relatedInformation) {
diagnostic.relatedInformation = [];
for (const info of d.relatedInformation) {
diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation(makeVscodeLocation(info.location), info.message));
if (info.workspaceEdit === undefined) {
continue;
}
const relatedWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(info.workspaceEdit.changes)) {
relatedWorkspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
}
const relatedIdentifier: CodeAnalysisDiagnosticIdentifier = { range: info.location.range, code: d.code };
const relatedIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = {
uri: info.location.uri, identifiers: [ relatedIdentifier ] };
const relatedCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem',
arguments: [ nextVersion, relatedWorkspaceEdit, true, [ relatedIdentifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
};
if (codeAction.fixCodeAction === undefined) {
codeAction.fixCodeAction = relatedCodeAction;
} else {
const relatedCodeActionInfo: CodeActionDiagnosticInfo = {
version: nextVersion,
range: makeVscodeRange(relatedIdentifier.range),
code: relatedIdentifier.code,
fixCodeAction: relatedCodeAction
};
relatedCodeActions.push(relatedCodeActionInfo);
}
rootAndRelatedWorkspaceEdits.push({ workspaceEdit: relatedWorkspaceEdit});
rootAndRelatedIdentifiersAndUris.push(relatedIdentifiersAndUri);
}
}
if (identifier.code.length !== 0) {
const codeActionCodeInfo: CodeActionCodeInfo = codeAnalysisCodeToFixes.get(identifier.code) ??
{ version: 0, uriToInfo: new Map<string, CodeActionPerUriInfo>() };
let rootAndRelatedWorkspaceEditsIndex: number = 0;
for (const rootAndRelatedIdentifiersAndUri of rootAndRelatedIdentifiersAndUris) {
const existingInfo: CodeActionPerUriInfo = codeActionCodeInfo.uriToInfo.get(rootAndRelatedIdentifiersAndUri.uri) ??
{ identifiers: [], numValidWorkspaceEdits: 0 };
existingInfo.identifiers.push(...rootAndRelatedIdentifiersAndUri.identifiers);
const rootAndRelatedWorkspaceEdit: CodeActionWorkspaceEdit = rootAndRelatedWorkspaceEdits[rootAndRelatedWorkspaceEditsIndex];
if (rootAndRelatedWorkspaceEdit !== undefined) {
if (existingInfo.workspaceEdits === undefined) {
existingInfo.workspaceEdits = [ rootAndRelatedWorkspaceEdit ];
} else {
existingInfo.workspaceEdits.push(rootAndRelatedWorkspaceEdit);
}
++existingInfo.numValidWorkspaceEdits;
}
codeActionCodeInfo.uriToInfo.set(rootAndRelatedIdentifiersAndUri.uri, existingInfo);
++rootAndRelatedWorkspaceEditsIndex;
}
if (!identifier.code.startsWith("clang-diagnostic-")) {
const codes: string[] = identifier.code.split(',');
let codeIndex: number = codes.length - 1;
if (codes[codeIndex] === "cert-dcl51-cpp") { // Handle aliasing
codeIndex = 0;
}
// TODO: Is the ideal code always selected as the primary one?
const primaryCode: string = codes[codeIndex];
const docPage: string = primaryCode === "clang-tidy-nolint" ? "#suppressing-undesired-diagnostics" :
`checks/${primaryCode}.html`;
const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/14.0.0/tools/clang/tools/extra/docs/clang-tidy/${docPage}`);
diagnostic.code = { value: identifier.code, target: primaryDocUri };
if (new CppSettings().clangTidyCodeActionShowDocumentation) {
if (codeActionCodeInfo.docCodeAction === undefined) {
codeActionCodeInfo.docCodeAction = {
title: localize("show_documentation_for", "Show documentation for {0}", primaryCode),
command: { title: 'ShowDocumentation', command: 'C_Cpp.ShowCodeAnalysisDocumentation',
arguments: [ primaryDocUri ] },
kind: vscode.CodeActionKind.QuickFix
};
}
} else {
codeActionCodeInfo.docCodeAction = undefined;
}
} else {
diagnostic.code = d.code;
}
codeAnalysisCodeToFixes.set(identifier.code, codeActionCodeInfo);
} else {
diagnostic.code = d.code;
}
diagnostic.source = CppSourceStr;
codeActionDiagnosticInfo.push(codeAction);
if (relatedCodeActions.length > 0) {
codeActionDiagnosticInfo.push(...relatedCodeActions);
}
diagnosticsCodeAnalysis.push(diagnostic);
}
codeAnalysisFileToCodeActions.set(params.uri, codeActionDiagnosticInfo);
rebuildCodeAnalysisCodeAndAllFixes();
diagnosticsCollectionCodeAnalysis.set(realUri, diagnosticsCodeAnalysis);
}
function removeCodeAnalysisCodeActions(identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[],
removeFixesOnly: boolean): void {
for (const identifiersAndUri of identifiersAndUris) {
const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(identifiersAndUri.uri);
if (codeActionDiagnosticInfo === undefined) {
return;
}
for (const identifier of identifiersAndUri.identifiers) {
const updatedCodeActions: CodeActionDiagnosticInfo[] = [];
for (const codeAction of codeActionDiagnosticInfo) {
if (rangeEquals(codeAction.range, identifier.range) && codeAction.code === identifier.code) {
if (removeFixesOnly) {
++codeAction.version;
codeAction.fixCodeAction = undefined;
} else {
continue;
}
}
updatedCodeActions.push(codeAction);
}
codeAnalysisFileToCodeActions.set(identifiersAndUri.uri, updatedCodeActions);
let codeActionInfoChanged: boolean = false;
for (const codeFixes of codeAnalysisCodeToFixes) {
const codeActionInfo: CodeActionPerUriInfo | undefined = codeFixes[1].uriToInfo.get(identifiersAndUri.uri);
if (codeActionInfo === undefined) {
continue;
}
let removedCodeActionInfoIndex: number = -1;
for (let codeActionInfoIndex: number = 0; codeActionInfoIndex < codeActionInfo.identifiers.length; ++codeActionInfoIndex) {
if (identifier.code === codeActionInfo.identifiers[codeActionInfoIndex].code &&
rangeEquals(identifier.range, codeActionInfo.identifiers[codeActionInfoIndex].range)) {
removedCodeActionInfoIndex = codeActionInfoIndex;
codeActionInfoChanged = true;
break;
}
}
if (removedCodeActionInfoIndex !== -1) {
if (removeFixesOnly) {
if (codeActionInfo.workspaceEdits !== undefined) {
codeActionInfo.workspaceEdits[removedCodeActionInfoIndex].workspaceEdit = undefined;
--codeActionInfo.numValidWorkspaceEdits;
}
} else {
codeActionInfo.identifiers.splice(removedCodeActionInfoIndex, 1);
if (codeActionInfo.workspaceEdits !== undefined) {
codeActionInfo.workspaceEdits.splice(removedCodeActionInfoIndex, 1);
--codeActionInfo.numValidWorkspaceEdits;
}
}
if (codeActionInfo.identifiers.length === 0) {
codeFixes[1].uriToInfo.delete(identifiersAndUri.uri);
} else {
codeFixes[1].uriToInfo.set(identifiersAndUri.uri, codeActionInfo);
}
}
}
if (codeActionInfoChanged) {
rebuildCodeAnalysisCodeAndAllFixes();
}
}
}
}
function publishRemoveCodeAnalysisCodeActionFixes(params: RemoveCodeAnalysisCodeActionFixesParams): void {
removeCodeAnalysisCodeActions(params.identifiersAndUris, true);
}
interface WorkspaceFolderParams {
workspaceFolderUri?: string;
}
@@ -151,6 +577,12 @@ interface TelemetryPayload {
metrics?: { [key: string]: number };
}
interface DebugProtocolParams {
jsonrpc: string;
method: string;
params?: any;
}
interface ReportStatusNotificationBody extends WorkspaceFolderParams {
status: string;
}
@@ -236,6 +668,12 @@ interface IntelliSenseDiagnosticRelatedInformation {
message: string;
}
interface CodeAnalysisDiagnosticRelatedInformation {
location: Location;
message: string;
workspaceEdit?: WorkspaceEdit;
}
interface IntelliSenseDiagnostic {
range: Range;
code?: number;
@@ -244,16 +682,53 @@ interface IntelliSenseDiagnostic {
relatedInformation?: IntelliSenseDiagnosticRelatedInformation[];
}
interface CodeAnalysisDiagnostic {
range: Range;
code: string;
severity: vscode.DiagnosticSeverity;
localizeStringParams: LocalizeStringParams;
relatedInformation?: CodeAnalysisDiagnosticRelatedInformation[];
workspaceEdit?: WorkspaceEdit;
}
interface CodeAnalysisDiagnosticIdentifier {
range: Range;
code: string;
}
export interface CodeAnalysisDiagnosticIdentifiersAndUri {
uri: string;
identifiers: CodeAnalysisDiagnosticIdentifier[];
}
interface RemoveCodeAnalysisProblemsParams {
identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[];
refreshSquigglesOnSave: boolean;
};
interface RemoveCodeAnalysisCodeActionFixesParams {
identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[];
};
interface PublishIntelliSenseDiagnosticsParams {
uri: string;
diagnostics: IntelliSenseDiagnostic[];
}
interface PublishCodeAnalysisDiagnosticsParams {
uri: string;
diagnostics: CodeAnalysisDiagnostic[];
}
interface ShowMessageWindowParams {
type: number;
localizeStringParams: LocalizeStringParams;
}
interface ShowWarningParams {
localizeStringParams: LocalizeStringParams;
}
export interface GetDocumentSymbolRequestParams {
uri: string;
}
@@ -312,6 +787,10 @@ export interface FormatParams {
useVcFormat: boolean;
}
interface WorkspaceEdit {
changes: { [uri: string]: TextEdit[] };
}
export interface GetFoldingRangesParams {
uri: string;
}
@@ -480,15 +959,17 @@ const ReferencesNotification: NotificationType<refs.ReferencesResultMessage, voi
const ReportReferencesProgressNotification: NotificationType<refs.ReportReferencesProgressNotification, void> = new NotificationType<refs.ReportReferencesProgressNotification, void>('cpptools/reportReferencesProgress');
const RequestCustomConfig: NotificationType<string, void> = new NotificationType<string, void>('cpptools/requestCustomConfig');
const PublishIntelliSenseDiagnosticsNotification: NotificationType<PublishIntelliSenseDiagnosticsParams, void> = new NotificationType<PublishIntelliSenseDiagnosticsParams, void>('cpptools/publishIntelliSenseDiagnostics');
const PublishCodeAnalysisDiagnosticsNotification: NotificationType<PublishCodeAnalysisDiagnosticsParams, void> = new NotificationType<PublishCodeAnalysisDiagnosticsParams, void>('cpptools/publishCodeAnalysisDiagnostics');
const ShowMessageWindowNotification: NotificationType<ShowMessageWindowParams, void> = new NotificationType<ShowMessageWindowParams, void>('cpptools/showMessageWindow');
const ShowWarningNotification: NotificationType<ShowWarningParams, void> = new NotificationType<ShowWarningParams, void>('cpptools/showWarning');
const ReportTextDocumentLanguage: NotificationType<string, void> = new NotificationType<string, void>('cpptools/reportTextDocumentLanguage');
const SemanticTokensChanged: NotificationType<string, void> = new NotificationType<string, void>('cpptools/semanticTokensChanged');
const InlayHintsChanged: NotificationType<string, void> = new NotificationType<string, void>('cpptools/inlayHintsChanged');
const IntelliSenseSetupNotification: NotificationType<IntelliSenseSetup, void> = new NotificationType<IntelliSenseSetup, void>('cpptools/IntelliSenseSetup');
const SetTemporaryTextDocumentLanguageNotification: NotificationType<SetTemporaryTextDocumentLanguageParams, void> = new NotificationType<SetTemporaryTextDocumentLanguageParams, void>('cpptools/setTemporaryTextDocumentLanguage');
const ReportCodeAnalysisProcessedNotification: NotificationType<number, void> = new NotificationType<number, void>('cpptools/reportCodeAnalysisProcessed');
const ReportCodeAnalysisTotalNotification: NotificationType<number, void> = new NotificationType<number, void>('cpptools/reportCodeAnalysisTotal');
const PublishRemoveCodeAnalysisCodeActionFixesNotification: NotificationType<RemoveCodeAnalysisCodeActionFixesParams, void> = new NotificationType<RemoveCodeAnalysisCodeActionFixesParams, void>('cpptools/publishRemoveCodeAnalysisCodeActionFixes');
let failureMessageShown: boolean = false;
export interface ReferencesCancellationState {
@@ -667,7 +1148,6 @@ export class DefaultClient implements Client {
private onTypeFormattingProviderDisposable: vscode.Disposable | undefined;
private codeFoldingProvider: FoldingRangeProvider | undefined;
private codeFoldingProviderDisposable: vscode.Disposable | undefined;
private inlayHintsProvider: InlayHintsProvider | undefined;
private semanticTokensProvider: SemanticTokensProvider | undefined;
private semanticTokensProviderDisposable: vscode.Disposable | undefined;
private innerConfiguration?: configs.CppProperties;
@@ -856,9 +1336,6 @@ export class DefaultClient implements Client {
// e.g. prevents empty c_cpp_properties.json from generation.
this.registerFileWatcher();
this.inlayHintsProvider = new InlayHintsProvider(this);
this.disposables.push(vscode.languages.registerInlayHintsProvider(this.documentSelector, this.inlayHintsProvider));
this.disposables.push(vscode.languages.registerRenameProvider(this.documentSelector, new RenameProvider(this)));
this.disposables.push(vscode.languages.registerReferenceProvider(this.documentSelector, new FindAllReferencesProvider(this)));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this)));
@@ -1294,8 +1771,7 @@ export class DefaultClient implements Client {
autoSaveAfterDelay: settings_filesAutoSaveAfterDelay
},
editor: {
autoClosingBrackets: settings_editorAutoClosingBrackets,
inlayHintsEnabled: workspaceOtherSettings.InlayHintsEnabled
autoClosingBrackets: settings_editorAutoClosingBrackets
},
workspace_fallback_encoding: workspaceOtherSettings.filesEncoding,
cpp_exclude_files: settings_cppFilesExclude,
@@ -1327,7 +1803,7 @@ export class DefaultClient implements Client {
},
vcpkg_root: util.getVcpkgRoot(),
experimentalFeatures: workspaceSettings.experimentalFeatures,
edgeMessagesDirectory: path.join(util.getExtensionFilePath("bin"), "messages", getLocaleId()),
edgeMessagesDirectory: path.join(util.getExtensionFilePath("bin"), "messages", util.getLocaleId()),
localizedStrings: localizedStrings,
packageVersion: util.packageJson.version,
legacyCompilerArgsBehavior: settings_legacyCompilerArgsBehavior
@@ -1427,8 +1903,7 @@ export class DefaultClient implements Client {
}
},
editor: {
autoClosingBrackets: otherSettingsFolder.editorAutoClosingBrackets,
inlayHintsEnabled: otherSettingsWorkspace.InlayHintsEnabled
autoClosingBrackets: otherSettingsFolder.editorAutoClosingBrackets
},
files: {
encoding: otherSettingsFolder.filesEncoding,
@@ -1467,7 +1942,7 @@ export class DefaultClient implements Client {
this.loggingLevel = newLoggingLevel;
const newLoggingLevelLogged: boolean = !!newLoggingLevel && newLoggingLevel !== "None" && newLoggingLevel !== "Error";
if (oldLoggingLevelLogged || newLoggingLevelLogged) {
const out: Logger = getOutputChannelLogger();
const out: logger.Logger = logger.getOutputChannelLogger();
out.appendLine(localize({ key: "loggingLevel.changed", comment: ["{0} is the setting name 'loggingLevel', {1} is a string value such as 'Debug'"] }, "{0} has changed to: {1}", "loggingLevel", changedSettings["loggingLevel"]));
}
}
@@ -1583,9 +2058,7 @@ export class DefaultClient implements Client {
if (this.semanticTokensProvider) {
this.semanticTokensProvider.invalidateFile(uri);
}
if (this.inlayHintsProvider) {
this.inlayHintsProvider.invalidateFile(uri);
}
openFileVersions.delete(uri);
}
@@ -1759,8 +2232,12 @@ export class DefaultClient implements Client {
public async logDiagnostics(): Promise<void> {
const response: GetDiagnosticsResult = await this.requestWhenReady(() => this.languageClient.sendRequest(GetDiagnosticsRequest, null));
const diagnosticsChannel: vscode.OutputChannel = getDiagnosticsChannel();
diagnosticsChannel.clear();
if (!diagnosticsChannel) {
diagnosticsChannel = vscode.window.createOutputChannel(localize("c.cpp.diagnostics", "C/C++ Diagnostics"));
workspaceDisposables.push(diagnosticsChannel);
} else {
diagnosticsChannel.clear();
}
const header: string = `-------- Diagnostics - ${new Date().toLocaleString()}\n`;
const version: string = `Version: ${util.packageJson.version}\n`;
@@ -2110,12 +2587,12 @@ export class DefaultClient implements Client {
client.handleRequestCustomConfig(requestFile);
});
this.languageClient.onNotification(PublishIntelliSenseDiagnosticsNotification, publishIntelliSenseDiagnostics);
RegisterCodeAnalysisNotifications(this.languageClient);
this.languageClient.onNotification(PublishCodeAnalysisDiagnosticsNotification, publishCodeAnalysisDiagnostics);
this.languageClient.onNotification(PublishRemoveCodeAnalysisCodeActionFixesNotification, publishRemoveCodeAnalysisCodeActionFixes);
this.languageClient.onNotification(ShowMessageWindowNotification, showMessageWindow);
this.languageClient.onNotification(ShowWarningNotification, showWarning);
this.languageClient.onNotification(ReportTextDocumentLanguage, (e) => this.setTextDocumentLanguage(e));
this.languageClient.onNotification(SemanticTokensChanged, (e) => this.semanticTokensProvider?.invalidateFile(e));
this.languageClient.onNotification(InlayHintsChanged, (e) => this.inlayHintsProvider?.invalidateFile(e));
this.languageClient.onNotification(IntelliSenseSetupNotification, (e) => this.logIntellisenseSetupTime(e));
this.languageClient.onNotification(SetTemporaryTextDocumentLanguageNotification, (e) => this.setTemporaryTextDocumentLanguage(e));
this.languageClient.onNotification(ReportCodeAnalysisProcessedNotification, (e) => this.updateCodeAnalysisProcessed(e));
@@ -2297,7 +2774,7 @@ export class DefaultClient implements Client {
} else if (message.endsWith("IntelliSense done")) {
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Debug") {
const out: Logger = getOutputChannelLogger();
const out: logger.Logger = logger.getOutputChannelLogger();
const duration: number = Date.now() - timeStamp;
out.appendLine(localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", duration / 1000));
}
@@ -2370,7 +2847,7 @@ export class DefaultClient implements Client {
}
private updateTagParseStatus(notificationBody: LocalizeStringParams): void {
this.model.parsingWorkspaceStatus.Value = getLocalizedString(notificationBody);
this.model.parsingWorkspaceStatus.Value = util.getLocalizedString(notificationBody);
if (notificationBody.text.startsWith("Workspace parsing paused")) {
this.model.isParsingWorkspacePausable.Value = true;
this.model.isParsingWorkspacePaused.Value = true;
@@ -2713,7 +3190,7 @@ export class DefaultClient implements Client {
}
const settings: CppSettings = new CppSettings();
const out: Logger = getOutputChannelLogger();
const out: logger.Logger = logger.getOutputChannelLogger();
if (settings.loggingLevel === "Debug") {
out.appendLine(localize("configurations.received", "Custom configurations received:"));
}
@@ -2738,7 +3215,6 @@ export class DefaultClient implements Client {
itemConfig.compilerPath = compilerPathAndArgs.compilerPath;
if (providerVersion < Version.v6) {
itemConfig.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs;
itemConfig.compilerArgs = undefined;
} else {
itemConfig.compilerArgs = compilerPathAndArgs.allCompilerArgs;
}
@@ -2817,7 +3293,7 @@ export class DefaultClient implements Client {
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Debug") {
const out: Logger = getOutputChannelLogger();
const out: logger.Logger = logger.getOutputChannelLogger();
out.appendLine(localize("browse.configuration.received", "Custom browse configuration received: {0}", JSON.stringify(sanitized, null, 2)));
}
@@ -2830,7 +3306,6 @@ export class DefaultClient implements Client {
sanitized.compilerPath = compilerPathAndArgs.compilerPath;
if (providerVersion < Version.v6) {
sanitized.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs;
sanitized.compilerArgs = undefined;
} else {
sanitized.compilerArgs = compilerPathAndArgs.allCompilerArgs;
}
@@ -3011,9 +3486,14 @@ export class DefaultClient implements Client {
public async handleRemoveAllCodeAnalysisProblems(): Promise<void> {
await this.awaitUntilLanguageClientReady();
if (removeAllCodeAnalysisProblems()) {
this.languageClient.sendNotification(CodeAnalysisNotification, CodeAnalysisScope.ClearSquiggles);
if (!diagnosticsCollectionCodeAnalysis) {
return;
}
diagnosticsCollectionCodeAnalysis.clear();
codeAnalysisFileToCodeActions.clear();
codeAnalysisCodeToFixes.clear();
rebuildCodeAnalysisCodeAndAllFixes();
this.languageClient.sendNotification(CodeAnalysisNotification, CodeAnalysisScope.ClearSquiggles);
}
public async handleFixCodeAnalysisProblems(workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise<void> {
@@ -3024,6 +3504,9 @@ export class DefaultClient implements Client {
public async handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise<void> {
await this.awaitUntilLanguageClientReady();
if (!diagnosticsCollectionCodeAnalysis) {
return;
}
// A deep copy is needed because the call to identifiers.splice below can
// remove elements in identifiersAndUris[...].identifiers.
@@ -3032,11 +3515,38 @@ export class DefaultClient implements Client {
identifiersAndUrisCopy.push({ uri: identifiersAndUri.uri, identifiers: [...identifiersAndUri.identifiers] });
}
if (removeCodeAnalysisProblems(identifiersAndUris)) {
// Need to notify the language client of the removed diagnostics so it doesn't re-send them.
this.languageClient.sendNotification(RemoveCodeAnalysisProblemsNotification, {
identifiersAndUris: identifiersAndUrisCopy, refreshSquigglesOnSave: refreshSquigglesOnSave });
// Remove the diagnostics.
for (const identifiersAndUri of identifiersAndUris) {
const uri: vscode.Uri = vscode.Uri.parse(identifiersAndUri.uri);
const diagnostics: readonly vscode.Diagnostic[] | undefined = diagnosticsCollectionCodeAnalysis.get(uri);
if (diagnostics === undefined) {
continue;
}
const newDiagnostics: vscode.Diagnostic[] = [];
for (const diagnostic of diagnostics) {
const code: string = typeof diagnostic.code === "string" ? diagnostic.code :
(typeof diagnostic.code === "object" && typeof diagnostic.code.value === "string" ?
diagnostic.code.value : "");
let removed: boolean = false;
for (const identifier of identifiersAndUri.identifiers) {
if (code !== identifier.code || !rangeEquals(diagnostic.range, identifier.range)) {
continue;
}
removed = true;
break;
}
if (!removed) {
newDiagnostics.push(diagnostic);
}
}
diagnosticsCollectionCodeAnalysis.set(uri, newDiagnostics);
}
removeCodeAnalysisCodeActions(identifiersAndUris, false);
// Need to notify the language client of the removed diagnostics so it doesn't re-send them.
this.languageClient.sendNotification(RemoveCodeAnalysisProblemsNotification, {
identifiersAndUris: identifiersAndUrisCopy, refreshSquigglesOnSave: refreshSquigglesOnSave });
}
public async handleDisableAllTypeCodeAnalysisProblems(code: string,
@@ -295,6 +295,7 @@ export class ClientCollection {
// this.defaultClient is already in this.languageClients, so do not call dispose() on it.
this.languageClients.forEach(client => client.dispose());
this.languageClients.clear();
cpptools.disposeWorkspaceData();
return cpptools.DefaultClient.stopLanguageClient();
}
}
@@ -1,501 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as vscode from 'vscode';
import { LanguageClient, NotificationType, Range } from 'vscode-languageclient';
import { Location, WorkspaceEdit } from './commonTypes';
import { makeVscodeRange, makeVscodeLocation, makeVscodeTextEdits, rangeEquals } from './utils';
import {LocalizeStringParams, getLocalizedString } from './localization';
import { CppSourceStr } from './extension';
import { CppSettings } from './settings';
import * as nls from 'vscode-nls';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
let diagnosticsCollectionCodeAnalysis: vscode.DiagnosticCollection;
export function RegisterCodeAnalysisNotifications(languageClient: LanguageClient): void {
languageClient.onNotification(PublishCodeAnalysisDiagnosticsNotification, publishCodeAnalysisDiagnostics);
languageClient.onNotification(PublishRemoveCodeAnalysisCodeActionFixesNotification, publishRemoveCodeAnalysisCodeActionFixes);
}
export interface CodeActionDiagnosticInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
// Used to work around https://github.com/microsoft/vscode/issues/126393.
// If that bug were fixed, then we could use the vscode.CodeAction.diagnostic directly.
range: vscode.Range;
code: string;
fixCodeAction?: vscode.CodeAction;
// suppressCodeAction?: vscode.CodeAction; // TODO?
removeCodeAction?: vscode.CodeAction;
}
// Used to handle fix invalidation after an edit,
// i.e. it's set to undefined if it becomes invalid.
interface CodeActionWorkspaceEdit {
workspaceEdit?: vscode.WorkspaceEdit;
}
interface CodeActionPerUriInfo {
// These two arrays have the same length, i.e. index i of identifiers
// is used to index into workspaceEdits to get the corresponding edit.
identifiers: CodeAnalysisDiagnosticIdentifier[];
workspaceEdits?: CodeActionWorkspaceEdit[];
// Used to quickly determine how many non-undefined entries are in "workspaceEdits"
// (so the array doesn't have to be iterated through).
numValidWorkspaceEdits: number;
}
// Tracks the "type" code actions (i.e. "code" is a synonym for "type" in this context).
export interface CodeActionCodeInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
// Needed to quickly update the "type" action for a file.
uriToInfo: Map<string, CodeActionPerUriInfo>;
fixAllTypeCodeAction?: vscode.CodeAction;
disableAllTypeCodeAction?: vscode.CodeAction;
removeAllTypeCodeAction?: vscode.CodeAction;
docCodeAction?: vscode.CodeAction;
}
interface CodeActionAllInfo {
version: number; // Needed due to https://github.com/microsoft/vscode/issues/148723 .
fixAllCodeAction: vscode.CodeAction;
removeAllCodeAction: vscode.CodeAction;
}
interface CodeAnalysisDiagnosticRelatedInformation {
location: Location;
message: string;
workspaceEdit?: WorkspaceEdit;
}
interface CodeAnalysisDiagnostic {
range: Range;
code: string;
severity: vscode.DiagnosticSeverity;
localizeStringParams: LocalizeStringParams;
relatedInformation?: CodeAnalysisDiagnosticRelatedInformation[];
workspaceEdit?: WorkspaceEdit;
}
interface CodeAnalysisDiagnosticIdentifier {
range: Range;
code: string;
}
export interface CodeAnalysisDiagnosticIdentifiersAndUri {
uri: string;
identifiers: CodeAnalysisDiagnosticIdentifier[];
}
export interface RemoveCodeAnalysisProblemsParams {
identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[];
refreshSquigglesOnSave: boolean;
};
interface RemoveCodeAnalysisCodeActionFixesParams {
identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[];
};
interface PublishCodeAnalysisDiagnosticsParams {
uri: string;
diagnostics: CodeAnalysisDiagnostic[];
}
const PublishCodeAnalysisDiagnosticsNotification: NotificationType<PublishCodeAnalysisDiagnosticsParams, void> = new NotificationType<PublishCodeAnalysisDiagnosticsParams, void>('cpptools/publishCodeAnalysisDiagnostics');
const PublishRemoveCodeAnalysisCodeActionFixesNotification: NotificationType<RemoveCodeAnalysisCodeActionFixesParams, void> = new NotificationType<RemoveCodeAnalysisCodeActionFixesParams, void>('cpptools/publishRemoveCodeAnalysisCodeActionFixes');
export const codeAnalysisFileToCodeActions: Map<string, CodeActionDiagnosticInfo[]> = new Map<string, CodeActionDiagnosticInfo[]>();
export const codeAnalysisCodeToFixes: Map<string, CodeActionCodeInfo> = new Map<string, CodeActionCodeInfo>();
export const codeAnalysisAllFixes: CodeActionAllInfo = {
version: 0,
fixAllCodeAction: {
title: localize("fix_all_code_analysis_problems", "Fix all code analysis problems"),
command: { title: 'FixAllCodeAnalysisProblems', command: 'C_Cpp.FixAllCodeAnalysisProblems',
arguments: [ 0, undefined, true, [] ] },
kind: vscode.CodeActionKind.QuickFix
},
removeAllCodeAction: {
title: localize("clear_all_code_analysis_problems", "Clear all code analysis problems"),
command: { title: "RemoveAllCodeAnalysisProblems", command: "C_Cpp.RemoveAllCodeAnalysisProblems" },
kind: vscode.CodeActionKind.QuickFix
}
};
// Rebuild codeAnalysisCodeToFixes and codeAnalysisAllFixes.fixAllCodeActions.
function rebuildCodeAnalysisCodeAndAllFixes(): void {
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[0] = ++codeAnalysisAllFixes.version;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = [];
}
const identifiersAndUrisForAllFixes: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
const uriToEditsForAll: Map<vscode.Uri, vscode.TextEdit[]> = new Map<vscode.Uri, vscode.TextEdit[]>();
let numFixTypes: number = 0;
for (const codeToFixes of codeAnalysisCodeToFixes) {
const identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
const uriToEdits: Map<vscode.Uri, vscode.TextEdit[]> = new Map<vscode.Uri, vscode.TextEdit[]>();
codeToFixes[1].uriToInfo.forEach((perUriInfo: CodeActionPerUriInfo, uri: string) => {
const newIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: uri, identifiers: perUriInfo.identifiers };
identifiersAndUris.push(newIdentifiersAndUri);
if (perUriInfo.workspaceEdits === undefined || perUriInfo.numValidWorkspaceEdits === 0) {
return;
}
identifiersAndUrisForAllFixes.push(newIdentifiersAndUri);
for (const edit of perUriInfo.workspaceEdits) {
if (edit.workspaceEdit === undefined) {
continue;
}
for (const [uri, edits] of edit.workspaceEdit.entries()) {
const textEdits: vscode.TextEdit[] = uriToEdits.get(uri) ?? [];
textEdits.push(...edits);
uriToEdits.set(uri, textEdits);
const textEditsForAll: vscode.TextEdit[] = uriToEditsForAll.get(uri) ?? [];
textEditsForAll.push(...edits);
uriToEditsForAll.set(uri, textEdits);
}
}
});
if (uriToEdits.size > 0) {
const allTypeWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uri, edits] of uriToEdits.entries()) {
allTypeWorkspaceEdit.set(uri, edits);
}
++numFixTypes;
codeToFixes[1].fixAllTypeCodeAction = {
title: localize("fix_all_type_problems", "Fix all {0} problems", codeToFixes[0]),
command: { title: 'FixAllTypeCodeAnalysisProblems', command: 'C_Cpp.FixAllTypeCodeAnalysisProblems',
arguments: [ codeToFixes[0], ++codeToFixes[1].version, allTypeWorkspaceEdit, true, identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
}
if (new CppSettings().clangTidyCodeActionShowDisable) {
codeToFixes[1].disableAllTypeCodeAction = {
title: localize("disable_all_type_problems", "Disable all {0} problems", codeToFixes[0]),
command: { title: 'DisableAllTypeCodeAnalysisProblems', command: 'C_Cpp.DisableAllTypeCodeAnalysisProblems',
arguments: [ codeToFixes[0], identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
} else {
codeToFixes[1].disableAllTypeCodeAction = undefined;
}
if (new CppSettings().clangTidyCodeActionShowClear !== "None") {
codeToFixes[1].removeAllTypeCodeAction = {
title: localize("clear_all_type_problems", "Clear all {0} problems", codeToFixes[0]),
command: { title: 'RemoveAllTypeCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems',
arguments: [ false, identifiersAndUris ] },
kind: vscode.CodeActionKind.QuickFix
};
}
}
if (numFixTypes > 1) {
const allWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uri, edits] of uriToEditsForAll.entries()) {
allWorkspaceEdit.set(uri, edits);
}
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = allWorkspaceEdit;
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[3] = identifiersAndUrisForAllFixes;
}
} else {
if (codeAnalysisAllFixes.fixAllCodeAction.command?.arguments !== undefined) {
codeAnalysisAllFixes.fixAllCodeAction.command.arguments[1] = undefined;
}
}
}
export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagnosticsParams): void {
if (!diagnosticsCollectionCodeAnalysis) {
diagnosticsCollectionCodeAnalysis = vscode.languages.createDiagnosticCollection("clang-tidy");
}
// Convert from our Diagnostic objects to vscode Diagnostic objects
const diagnosticsCodeAnalysis: vscode.Diagnostic[] = [];
const realUri: vscode.Uri = vscode.Uri.parse(params.uri);
// Reset codeAnalysisCodeToFixes for the file.
for (const codeToFixes of codeAnalysisCodeToFixes) {
++codeToFixes[1].version;
if (codeToFixes[1].uriToInfo.has(params.uri)) {
codeToFixes[1].uriToInfo.delete(params.uri);
}
}
const previousDiagnostics: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(params.uri);
let nextVersion: number = 0;
if (previousDiagnostics !== undefined) {
for (const diagnostic of previousDiagnostics) {
if (diagnostic.version > nextVersion) {
nextVersion = diagnostic.version;
}
}
}
++nextVersion;
const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] = [];
for (const d of params.diagnostics) {
const diagnostic: vscode.Diagnostic = new vscode.Diagnostic(makeVscodeRange(d.range),
getLocalizedString(d.localizeStringParams), d.severity);
const identifier: CodeAnalysisDiagnosticIdentifier = { range: d.range, code: d.code };
const identifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = { uri: params.uri, identifiers: [ identifier ] };
const codeAction: CodeActionDiagnosticInfo = {
version: nextVersion,
range: makeVscodeRange(identifier.range),
code: identifier.code,
removeCodeAction: {
title: localize("clear_this_problem", "Clear this {0} problem", d.code),
command: { title: 'RemoveCodeAnalysisProblems', command: 'C_Cpp.RemoveCodeAnalysisProblems',
arguments: [ false, [ identifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
}
};
const workspaceEdit: CodeActionWorkspaceEdit = {};
if (d.workspaceEdit) {
workspaceEdit.workspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(d.workspaceEdit.changes)) {
workspaceEdit.workspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
}
const fixThisCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem',
arguments: [ nextVersion, workspaceEdit.workspaceEdit, true, [ identifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
};
codeAction.fixCodeAction = fixThisCodeAction;
}
// Edits from clang-tidy can be associated with the related information instead of the root diagnostic.
const relatedCodeActions: CodeActionDiagnosticInfo[] = [];
const rootAndRelatedWorkspaceEdits: CodeActionWorkspaceEdit[] = [];
const rootAndRelatedIdentifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
rootAndRelatedIdentifiersAndUris.push(identifiersAndUri);
if (workspaceEdit.workspaceEdit !== undefined) {
rootAndRelatedWorkspaceEdits.push(workspaceEdit);
}
if (d.relatedInformation) {
diagnostic.relatedInformation = [];
for (const info of d.relatedInformation) {
diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation(makeVscodeLocation(info.location), info.message));
if (info.workspaceEdit === undefined) {
continue;
}
const relatedWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(info.workspaceEdit.changes)) {
relatedWorkspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
}
const relatedIdentifier: CodeAnalysisDiagnosticIdentifier = { range: info.location.range, code: d.code };
const relatedIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = {
uri: info.location.uri, identifiers: [ relatedIdentifier ] };
const relatedCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
command: { title: 'FixThisCodeAnalysisProblem', command: 'C_Cpp.FixThisCodeAnalysisProblem',
arguments: [ nextVersion, relatedWorkspaceEdit, true, [ relatedIdentifiersAndUri ] ] },
kind: vscode.CodeActionKind.QuickFix
};
if (codeAction.fixCodeAction === undefined) {
codeAction.fixCodeAction = relatedCodeAction;
} else {
const relatedCodeActionInfo: CodeActionDiagnosticInfo = {
version: nextVersion,
range: makeVscodeRange(relatedIdentifier.range),
code: relatedIdentifier.code,
fixCodeAction: relatedCodeAction
};
relatedCodeActions.push(relatedCodeActionInfo);
}
rootAndRelatedWorkspaceEdits.push({ workspaceEdit: relatedWorkspaceEdit});
rootAndRelatedIdentifiersAndUris.push(relatedIdentifiersAndUri);
}
}
if (identifier.code.length !== 0) {
const codeActionCodeInfo: CodeActionCodeInfo = codeAnalysisCodeToFixes.get(identifier.code) ??
{ version: 0, uriToInfo: new Map<string, CodeActionPerUriInfo>() };
let rootAndRelatedWorkspaceEditsIndex: number = 0;
for (const rootAndRelatedIdentifiersAndUri of rootAndRelatedIdentifiersAndUris) {
const existingInfo: CodeActionPerUriInfo = codeActionCodeInfo.uriToInfo.get(rootAndRelatedIdentifiersAndUri.uri) ??
{ identifiers: [], numValidWorkspaceEdits: 0 };
existingInfo.identifiers.push(...rootAndRelatedIdentifiersAndUri.identifiers);
const rootAndRelatedWorkspaceEdit: CodeActionWorkspaceEdit = rootAndRelatedWorkspaceEdits[rootAndRelatedWorkspaceEditsIndex];
if (rootAndRelatedWorkspaceEdit !== undefined) {
if (existingInfo.workspaceEdits === undefined) {
existingInfo.workspaceEdits = [ rootAndRelatedWorkspaceEdit ];
} else {
existingInfo.workspaceEdits.push(rootAndRelatedWorkspaceEdit);
}
++existingInfo.numValidWorkspaceEdits;
}
codeActionCodeInfo.uriToInfo.set(rootAndRelatedIdentifiersAndUri.uri, existingInfo);
++rootAndRelatedWorkspaceEditsIndex;
}
if (!identifier.code.startsWith("clang-diagnostic-")) {
const codes: string[] = identifier.code.split(',');
let codeIndex: number = codes.length - 1;
if (codes[codeIndex] === "cert-dcl51-cpp") { // Handle aliasing
codeIndex = 0;
}
// TODO: Is the ideal code always selected as the primary one?
const primaryCode: string = codes[codeIndex];
const docPage: string = primaryCode === "clang-tidy-nolint" ? "#suppressing-undesired-diagnostics" :
`checks/${primaryCode}.html`;
const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/14.0.0/tools/clang/tools/extra/docs/clang-tidy/${docPage}`);
diagnostic.code = { value: identifier.code, target: primaryDocUri };
if (new CppSettings().clangTidyCodeActionShowDocumentation) {
if (codeActionCodeInfo.docCodeAction === undefined) {
codeActionCodeInfo.docCodeAction = {
title: localize("show_documentation_for", "Show documentation for {0}", primaryCode),
command: { title: 'ShowDocumentation', command: 'C_Cpp.ShowCodeAnalysisDocumentation',
arguments: [ primaryDocUri ] },
kind: vscode.CodeActionKind.QuickFix
};
}
} else {
codeActionCodeInfo.docCodeAction = undefined;
}
} else {
diagnostic.code = d.code;
}
codeAnalysisCodeToFixes.set(identifier.code, codeActionCodeInfo);
} else {
diagnostic.code = d.code;
}
diagnostic.source = CppSourceStr;
codeActionDiagnosticInfo.push(codeAction);
if (relatedCodeActions.length > 0) {
codeActionDiagnosticInfo.push(...relatedCodeActions);
}
diagnosticsCodeAnalysis.push(diagnostic);
}
codeAnalysisFileToCodeActions.set(params.uri, codeActionDiagnosticInfo);
rebuildCodeAnalysisCodeAndAllFixes();
diagnosticsCollectionCodeAnalysis.set(realUri, diagnosticsCodeAnalysis);
}
function removeCodeAnalysisCodeActions(identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[],
removeFixesOnly: boolean): void {
for (const identifiersAndUri of identifiersAndUris) {
const codeActionDiagnosticInfo: CodeActionDiagnosticInfo[] | undefined = codeAnalysisFileToCodeActions.get(identifiersAndUri.uri);
if (codeActionDiagnosticInfo === undefined) {
return;
}
for (const identifier of identifiersAndUri.identifiers) {
const updatedCodeActions: CodeActionDiagnosticInfo[] = [];
for (const codeAction of codeActionDiagnosticInfo) {
if (rangeEquals(codeAction.range, identifier.range) && codeAction.code === identifier.code) {
if (removeFixesOnly) {
++codeAction.version;
codeAction.fixCodeAction = undefined;
} else {
continue;
}
}
updatedCodeActions.push(codeAction);
}
codeAnalysisFileToCodeActions.set(identifiersAndUri.uri, updatedCodeActions);
let codeActionInfoChanged: boolean = false;
for (const codeFixes of codeAnalysisCodeToFixes) {
const codeActionInfo: CodeActionPerUriInfo | undefined = codeFixes[1].uriToInfo.get(identifiersAndUri.uri);
if (codeActionInfo === undefined) {
continue;
}
let removedCodeActionInfoIndex: number = -1;
for (let codeActionInfoIndex: number = 0; codeActionInfoIndex < codeActionInfo.identifiers.length; ++codeActionInfoIndex) {
if (identifier.code === codeActionInfo.identifiers[codeActionInfoIndex].code &&
rangeEquals(identifier.range, codeActionInfo.identifiers[codeActionInfoIndex].range)) {
removedCodeActionInfoIndex = codeActionInfoIndex;
codeActionInfoChanged = true;
break;
}
}
if (removedCodeActionInfoIndex !== -1) {
if (removeFixesOnly) {
if (codeActionInfo.workspaceEdits !== undefined) {
codeActionInfo.workspaceEdits[removedCodeActionInfoIndex].workspaceEdit = undefined;
--codeActionInfo.numValidWorkspaceEdits;
}
} else {
codeActionInfo.identifiers.splice(removedCodeActionInfoIndex, 1);
if (codeActionInfo.workspaceEdits !== undefined) {
codeActionInfo.workspaceEdits.splice(removedCodeActionInfoIndex, 1);
--codeActionInfo.numValidWorkspaceEdits;
}
}
if (codeActionInfo.identifiers.length === 0) {
codeFixes[1].uriToInfo.delete(identifiersAndUri.uri);
} else {
codeFixes[1].uriToInfo.set(identifiersAndUri.uri, codeActionInfo);
}
}
}
if (codeActionInfoChanged) {
rebuildCodeAnalysisCodeAndAllFixes();
}
}
}
}
export function publishRemoveCodeAnalysisCodeActionFixes(params: RemoveCodeAnalysisCodeActionFixesParams): void {
removeCodeAnalysisCodeActions(params.identifiersAndUris, true);
}
export function removeAllCodeAnalysisProblems(): boolean {
if (!diagnosticsCollectionCodeAnalysis) {
return false;
}
diagnosticsCollectionCodeAnalysis.clear();
codeAnalysisFileToCodeActions.clear();
codeAnalysisCodeToFixes.clear();
rebuildCodeAnalysisCodeAndAllFixes();
return true;
}
export function removeCodeAnalysisProblems(identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): boolean {
if (!diagnosticsCollectionCodeAnalysis) {
return false;
}
// Remove the diagnostics.
for (const identifiersAndUri of identifiersAndUris) {
const uri: vscode.Uri = vscode.Uri.parse(identifiersAndUri.uri);
const diagnostics: readonly vscode.Diagnostic[] | undefined = diagnosticsCollectionCodeAnalysis.get(uri);
if (diagnostics === undefined) {
continue;
}
const newDiagnostics: vscode.Diagnostic[] = [];
for (const diagnostic of diagnostics) {
const code: string = typeof diagnostic.code === "string" ? diagnostic.code :
(typeof diagnostic.code === "object" && typeof diagnostic.code.value === "string" ?
diagnostic.code.value : "");
let removed: boolean = false;
for (const identifier of identifiersAndUri.identifiers) {
if (code !== identifier.code || !rangeEquals(diagnostic.range, identifier.range)) {
continue;
}
removed = true;
break;
}
if (!removed) {
newDiagnostics.push(diagnostic);
}
}
diagnosticsCollectionCodeAnalysis.set(uri, newDiagnostics);
}
removeCodeAnalysisCodeActions(identifiersAndUris, false);
return true;
}
@@ -1,21 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import { Range } from 'vscode-languageclient';
/** Differs from vscode.Location, which has a uri of type vscode.Uri. */
export interface Location {
uri: string;
range: Range;
}
export interface TextEdit {
range: Range;
newText: string;
}
export interface WorkspaceEdit {
changes: { [uri: string]: TextEdit[] };
}
@@ -122,19 +122,10 @@ export class CppBuildTaskProvider implements TaskProvider {
const knownCompilerPathsSet: Set<string> = new Set();
let knownCompilers: configs.KnownCompiler[] | undefined = await activeClient.getKnownCompilers();
if (knownCompilers) {
const compiler_condition: (info: configs.KnownCompiler) => boolean = info =>
(
// Filter out c compilers for cpp files and vice versa, except for cl.exe, which handles both.
path.basename(info.path) === "cl.exe" ||
(fileIsCpp && !info.isC) || (fileIsC && info.isC)
) &&
(
!isCompilerValid || (!!userCompilerPathAndArgs &&
(path.basename(info.path) !== userCompilerPathAndArgs.compilerName))
) &&
(
!isWindows || !info.path.startsWith("/")
); // TODO: Add WSL compiler support.
const compiler_condition: (info: configs.KnownCompiler) => boolean = info => ((fileIsCpp && !info.isC) || (fileIsC && info.isC)) &&
(!isCompilerValid || (!!userCompilerPathAndArgs &&
(path.basename(info.path) !== userCompilerPathAndArgs.compilerName))) &&
(!isWindows || !info.path.startsWith("/")); // TODO: Add WSL compiler support.
const cl_to_add: configs.KnownCompiler | undefined = userCompilerIsCl ? undefined : knownCompilers.find(info =>
((path.basename(info.path) === "cl.exe") && compiler_condition(info)));
knownCompilers = knownCompilers.filter(info =>
+3 -4
View File
@@ -12,9 +12,8 @@ import * as util from '../common';
import * as telemetry from '../telemetry';
import { TreeNode, NodeType } from './referencesModel';
import { UI, getUI } from './ui';
import { Client, openFileVersions } from './client';
import { CodeAnalysisDiagnosticIdentifiersAndUri, CodeActionDiagnosticInfo, codeAnalysisCodeToFixes,
codeAnalysisFileToCodeActions, codeAnalysisAllFixes } from './codeAnalysis';
import { Client, openFileVersions, CodeAnalysisDiagnosticIdentifiersAndUri, CodeActionDiagnosticInfo, codeAnalysisCodeToFixes,
codeAnalysisFileToCodeActions, codeAnalysisAllFixes } from './client';
import { makeCpptoolsRange, rangeEquals } from './utils';
import { ClientCollection } from './clientCollection';
import { CppSettings, OtherSettings } from './settings';
@@ -363,7 +362,7 @@ export function processDelayedDidOpen(document: vscode.TextDocument): boolean {
return false;
}
function onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]): void {
function onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]): void {
// Process delayed didOpen for any visible editors we haven't seen before
editors.forEach(editor => {
if ((editor.document.uri.scheme === "file") && (editor.document.languageId === "c" || editor.document.languageId === "cpp" || editor.document.languageId === "cuda-cpp")) {
@@ -1,75 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import { getExtensionFilePath } from '../common';
import { lookupString } from '../nativeStrings';
import * as nls from 'vscode-nls';
import path = require('path');
import * as fs from 'fs';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export interface LocalizeStringParams {
text: string;
stringId: number;
stringArgs: string[];
indentSpaces: number;
}
export function getLocalizedString(params: LocalizeStringParams): string {
let indent: string = "";
if (params.indentSpaces) {
indent = " ".repeat(params.indentSpaces);
}
let text: string = params.text;
if (params.stringId !== 0) {
text = lookupString(params.stringId, params.stringArgs);
}
return indent + text;
}
interface VSCodeNlsConfig {
locale: string;
availableLanguages: {
[pack: string]: string;
};
}
export function getLocaleId(): string {
// This replicates the language detection used by initializeSettings() in vscode-nls
if (typeof process.env.VSCODE_NLS_CONFIG === 'string') {
const vscodeOptions: VSCodeNlsConfig = JSON.parse(process.env.VSCODE_NLS_CONFIG) as VSCodeNlsConfig;
if (vscodeOptions.availableLanguages) {
const value: any = vscodeOptions.availableLanguages['*'];
if (typeof value === 'string') {
return value;
}
}
if (typeof vscodeOptions.locale === 'string') {
return vscodeOptions.locale.toLowerCase();
}
}
return "en";
}
export function getLocalizedHtmlPath(originalPath: string): string {
const locale: string = getLocaleId();
if (!locale.startsWith("en")) {
const localizedFilePath: string = getExtensionFilePath(path.join("dist/html/", locale, originalPath));
if (fs.existsSync(localizedFilePath)) {
return localizedFilePath;
}
}
return getExtensionFilePath(originalPath);
}
export function getLocalizedSymbolScope(scope: string, detail: string): string {
return localize({
key: "c.cpp.symbolscope.separator", comment:
["{0} is an untranslated C++ keyword (e.g. \"private\") and {1} is either another keyword (e.g. \"typedef\") or a localized property (e.g. a localized version of \"declaration\""]
}, "{0}, {1}", scope, detail);
}
-29
View File
@@ -252,34 +252,6 @@ export class CppSettings extends Settings {
public get codeFolding(): boolean { return super.Section.get<string>("codeFolding") === "Enabled"; }
public get legacyCompilerArgsBehavior(): boolean | undefined { return super.Section.get<boolean>("legacyCompilerArgsBehavior"); }
public get inlayHintsAutoDeclarationTypes(): boolean {
return super.Section.get<boolean>("inlayHints.autoDeclarationTypes.enabled") === true;
}
public get inlayHintsAutoDeclarationTypesShowOnLeft(): boolean {
return super.Section.get<boolean>("inlayHints.autoDeclarationTypes.showOnLeft") === true;
}
public get inlayHintsParameterNames(): boolean {
return super.Section.get<boolean>("inlayHints.parameterNames.enabled") === true;
}
public get inlayHintsParameterNamesSuppressName(): boolean {
return super.Section.get<boolean>("inlayHints.parameterNames.suppressWhenArgumentContainsName") === true;
}
public get inlayHintsParameterNamesHideLeadingUnderscores(): boolean {
return super.Section.get<boolean>("inlayHints.parameterNames.hideLeadingUnderscores") === true;
}
public get inlayHintsReferenceOperator(): boolean {
return super.Section.get<boolean>("inlayHints.referenceOperator.enabled") === true;
}
public get inlayHintsReferenceOperatorShowSpace(): boolean {
return super.Section.get<boolean>("inlayHints.referenceOperator.showSpace") === true;
}
public get enhancedColorization(): boolean {
return super.Section.get<string>("enhancedColorization") === "Enabled"
&& super.Section.get<string>("intelliSenseEngine") === "Default"
@@ -816,7 +788,6 @@ export class OtherSettings {
}
public get filesExclude(): vscode.WorkspaceConfiguration | undefined { return vscode.workspace.getConfiguration("files", this.resource).get("exclude"); }
public get filesAutoSaveAfterDelay(): boolean { return vscode.workspace.getConfiguration("files").get("autoSave") === "afterDelay"; }
public get InlayHintsEnabled(): boolean { return vscode.workspace.getConfiguration("editor.inlayHints").get<string>("enabled") !== "off"; }
public get searchExclude(): vscode.WorkspaceConfiguration | undefined { return vscode.workspace.getConfiguration("search", this.resource).get("exclude"); }
public get settingsEditor(): string | undefined { return vscode.workspace.getConfiguration("workbench.settings").get<string>("editor"); }
@@ -10,7 +10,6 @@ import * as vscode from 'vscode';
import * as util from '../common';
import * as config from './configurations';
import * as telemetry from '../telemetry';
import { getLocalizedHtmlPath } from './localization';
// TODO: share ElementId between SettingsPanel and SettingsApp. Investigate why SettingsApp cannot import/export
const elementId: { [key: string]: string } = {
@@ -374,7 +373,7 @@ export class SettingsPanel {
private getHtml(): string {
let content: string | undefined;
content = fs.readFileSync(getLocalizedHtmlPath("ui/settings.html")).toString();
content = fs.readFileSync(util.getLocalizedHtmlPath("ui/settings.html")).toString();
if (this.panel && this.panel.webview) {
const cppImageUri: vscode.Uri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(util.extensionPath, 'LanguageCCPP_color_128x.png')));
+11 -1
View File
@@ -5,7 +5,17 @@
'use strict';
import * as vscode from 'vscode';
import { Range } from 'vscode-languageclient';
import { Location, TextEdit } from './commonTypes';
/** Differs from vscode.Location, which has a uri of type vscode.Uri. */
export interface Location {
uri: string;
range: Range;
}
export interface TextEdit {
range: Range;
newText: string;
}
export function makeCpptoolsRange(vscRange: vscode.Range): Range {
return { start: { line: vscRange.start.line, character: vscRange.start.character },
-340
View File
@@ -1,340 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { stripEscapeSequences, isWindows, escapeStringForRegex } from '../common';
export type IDifferingHostConfirmationProvider =
(message: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export type IFingerprintConfirmationProvider =
(host: string, fingerprint: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export interface IInteraction {
canceled?: boolean;
postAction?: 'consume' | 'keep';
response?: string;
isPassword?: boolean;
continue?: boolean; // Continue without waiting for the program to finish or pause
}
export interface IInteractorDataDetails {
detectedServerKey?: string;
detail?: string;
}
export interface IInteractor {
id: string;
onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction>;
}
export class MitmInteractor implements IInteractor {
static ID = 'mitm';
constructor() { }
get id(): string {
return MitmInteractor.ID;
}
async onData(data: string): Promise<IInteraction> {
if (!!data.match('Port forwarding is disabled to avoid man-in-the-middle attacks.')) {
throw Error('Port forwarding is disabled to avoid man-in-the-middle attacks.');
}
return {};
}
}
export class FingerprintInteractor implements IInteractor {
static ID = 'fingerprint';
constructor(private readonly hostName: string, private readonly confirmationProvider: IFingerprintConfirmationProvider) { }
get id(): string {
return FingerprintInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const fingerprintMatcher: RegExp = /fingerprint\sis\s(.+)\./;
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
let fingerprintMatch: RegExpMatchArray | null;
if (
data.includes('Are you sure you want to continue connecting') &&
(fingerprintMatch = data.match(fingerprintMatcher))
) {
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(
this.hostName,
fingerprintMatch[1],
cancelToken
);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
} else if (
isWindows() &&
(data.includes('The authenticity of host ') || (data === '' && extraDetails?.detectedServerKey))
) {
// hack for #1195
// First line local server case (git ssh only gives the first line over ssh_askpass)
const key: string = extraDetails?.detectedServerKey || '(unknown)';
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(this.hostName, key, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export class DifferingHostKeyInteractor implements IInteractor {
static ID = 'differing host key';
constructor(private readonly confirmationProvider: IDifferingHostConfirmationProvider) { }
get id(): string {
return DifferingHostKeyInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, _extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
if (
data.includes('Are you sure you want to continue connecting') &&
data.includes('Offending key for IP in') &&
data.includes('Matching host key in')
) {
result.postAction = 'consume';
const message: string = data.substring(data.indexOf('Warning'), data.indexOf('Are')).trim();
const confirmation: string | undefined = await this.confirmationProvider(message, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IStringProvider =
(key?: string, detail?: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class PassphraseInteractor implements IInteractor {
static ID = 'passphrase';
constructor(private readonly passphraseProvider: IStringProvider) { }
get id(): string {
return PassphraseInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const lines: string[] = data.trim().split('\n');
if (lines.some(l => l.indexOf('Enter passphrase for') >= 0)) {
result.postAction = 'consume';
const passphrase: string | undefined = await this.passphraseProvider(undefined, undefined, cancelToken); // TODO keep track of the key name
if (typeof passphrase === 'string') {
result.response = passphrase;
result.isPassword = true;
} else {
result.canceled = true;
}
} else if (lines.some(l => l.indexOf('Identity added:') >= 0)) {
result.postAction = 'consume';
}
return result;
}
}
export function getExitCode(output: string, marker: string): number | undefined {
const regex: RegExp = new RegExp(`${marker}##([0-9]*)##`);
const match: RegExpExecArray | null = regex.exec(output);
if (match) {
try {
const num: number = parseInt(match[1]);
return Number.isNaN(num) ? undefined : num;
} catch (err) {
return undefined;
}
}
return 0;
}
/**
* Matches SSH password prompt of format:
* 's password:
* or
* Password:
* not
* 's old password:
* 's new password:
*/
function getPasswordPrompt(data: string, details?: IInteractorDataDetails): { user?: string; message?: string } | undefined {
if (data.includes('Password:')) {
// Password prompt for unspecified user
return { user: '' };
}
// Got \r\r\n as a line ending here
const match: RegExpMatchArray | null = stripEscapeSequences(data).match(/([a-zA-Z0-9\-_@\.]*)'s password:/);
if (match) {
return {
user: match[1],
message: details ? details.detail : undefined
};
}
return undefined;
}
export class PasswordInteractor implements IInteractor {
static ID = 'password';
constructor(private readonly passwordProvider: IStringProvider) { }
get id(): string {
return PasswordInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pwPrompt: { user?: string; message?: string } | undefined = getPasswordPrompt(data, extraDetails);
if (pwPrompt && typeof pwPrompt.user === 'string') {
result.postAction = 'consume';
const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken);
if (typeof password === 'string') {
result.response = password;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IVerificationCodeProvider =
(msg: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class TwoFacInteractor implements IInteractor {
static ID = '2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return TwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Verification code:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter verification code', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
// https://github.com/microsoft/vscode-remote-release/issues/2170
export class DuoTwoFacInteractor implements IInteractor {
static ID = 'duo-2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return DuoTwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Passcode:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter passcode', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export class ContinueOnInteractor implements IInteractor {
static ID = 'continueOn';
constructor(private readonly continueOn: string) { }
get id(): string {
return ContinueOnInteractor.ID;
}
async onData(data: string, _cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pattern: string = escapeStringForRegex(this.continueOn);
const re: RegExp = new RegExp(pattern, 'g');
if (data.match(re)) {
result.continue = true;
}
return result;
}
}
export class ComposedInteractor implements IInteractor {
constructor(private readonly interactors: IInteractor[]) { }
get id(): string {
return 'composed';
}
async onData(data: string): Promise<IInteraction> {
for (const interactor of this.interactors) {
const result: IInteraction = await interactor.onData(data);
if (result.postAction === 'consume') {
return result;
}
}
return { postAction: 'keep' };
}
}
export interface ISystemInteractor {
createTerminal(options: vscode.TerminalOptions): vscode.Terminal;
onDidCloseTerminal: typeof vscode.window.onDidCloseTerminal;
onDidWriteTerminalData: typeof vscode.window.onDidWriteTerminalData;
}
export const defaultSystemInteractor: ISystemInteractor = {
createTerminal: vscode.window.createTerminal,
onDidCloseTerminal: vscode.window.onDidCloseTerminal,
onDidWriteTerminalData: vscode.window.onDidWriteTerminalData
};
-98
View File
@@ -1,98 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
import { defaultSystemInteractor } from './commandInteractors';
import { runSshTerminalCommandWithLogin } from './sshCommandRunner';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export async function scp(files: vscode.Uri[], host: ISshHostInfo, targetDir: string, scpPath?: string, jumpHosts?: ISshHostInfo[], cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// upper case P
args.push('-P', `${host.port}`);
}
args.push(files.map(uri => `"${uri.fsPath}"`).join(' '), `${getFullHostAddressNoPort(host)}:${targetDir}`);
return runSshTerminalCommandWithLogin(host, { systemInteractor: defaultSystemInteractor, nickname: 'scp', command: `"${scpPath || 'scp'}" ${args.join(' ')}`, token: cancellationToken });
}
export function ssh(host: ISshHostInfo, command: string, sshPath?: string, jumpHosts?: ISshHostInfo[], localForwards?: ISshLocalForwardInfo[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// lower case p
args.push('-p', `${host.port}`);
}
if (localForwards) {
localForwards.forEach(info => args.push(...localForwardToArgs(info)));
}
args.push(getFullHostAddressNoPort(host), `"${command}"`);
return runSshTerminalCommandWithLogin(host, {
systemInteractor: defaultSystemInteractor,
command: `"${sshPath || 'ssh'}" ${args.join(' ')}`,
nickname: 'ssh',
continueOn,
token: cancellationToken
});
}
/**
* Takes one local forward info and convert it to '-L' args in ssh.
*/
function localForwardToArgs(localForward: ISshLocalForwardInfo): string[] {
// Do not combine error checking and arg conversion for clarity.
if (localForward.localSocket && (localForward.bindAddress || localForward.port)) {
throw Error(localize('local.forward.local.conflict', '"localSocket" cannot be specifed at the same time with "bindAddress" or "port" in localForwards'));
}
if (!localForward.localSocket && !localForward.port) {
throw Error(localize('local.forward.local.missing', '"port" or "localSocket" required in localForwards'));
}
if (localForward.remoteSocket && (localForward.host || localForward.hostPort)) {
throw Error(localize('local.forward.remote.conflict', '"remoteSocket" cannot be specifed at the same time with "host" or "hostPort" in localForwards'));
}
if (!localForward.remoteSocket && (!localForward.host || !localForward.hostPort)) {
throw Error(localize('local.forward.remote.missing', '"host" and "hostPort", or "remoteSocket" required in localForwards'));
}
let arg: string = '';
if (localForward.localSocket) {
arg += `${localForward.localSocket}:`;
}
if (localForward.bindAddress) {
arg += `${localForward.bindAddress}:`;
}
if (localForward.port) {
arg += `${localForward.port}:`;
}
if (localForward.remoteSocket) {
arg += `${localForward.remoteSocket}`;
}
if (localForward.host && localForward.hostPort) {
arg += `${localForward.host}:${localForward.hostPort}`;
}
return ['-L', arg];
}
/** user@host */
function getFullHostAddressNoPort(host: ISshHostInfo): string {
return host.user ? `${host.user}@${host.hostName}` : `${host.hostName}`;
}
function getFullHostAddress(host: ISshHostInfo): string {
const fullHostName: string = getFullHostAddressNoPort(host);
return host.port ? `${fullHostName}:${host.port}` : fullHostName;
}
-518
View File
@@ -1,518 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import {
DifferingHostKeyInteractor,
DuoTwoFacInteractor,
FingerprintInteractor,
IInteractor,
MitmInteractor,
PassphraseInteractor,
PasswordInteractor,
TwoFacInteractor,
ContinueOnInteractor,
ISystemInteractor,
IInteraction
} from './commandInteractors';
import { isWindows, ISshHostInfo, splitLines, stripEscapeSequences, ProcessReturnType } from '../common';
import { getOutputChannelLogger } from '../logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export class CanceledError extends Error {
constructor() {
super(localize('ssh.canceled', 'SSH command canceled'));
}
}
export interface ICommandResult {
stdout: string;
stderr: string;
}
export function showPassphraseInputBox(
keyName?: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const keyStr: string = keyName ? `"${keyName}"` : '';
const msg: string = localize('ssh.passphrase.input.box', 'Enter passphrase for ssh key {0}', keyStr);
return showInputBox(msg, prompt, cancelToken);
}
export function showPasswordInputBox(
user: string | undefined,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const msg: string = user ? localize('ssh.enter.password.for.user', 'Enter password for user "{0}"', user) : localize('ssh_message_enterPassword', 'Enter password');
return showInputBox(msg, prompt, cancelToken);
}
export function showVerificationCodeInputBox(
msg: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showInputBox(msg, undefined, cancelToken);
}
export async function showInputBox(
msg: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.InputBox = vscode.window.createInputBox();
quickPick.title = msg;
quickPick.prompt = prompt;
quickPick.password = true;
quickPick.ignoreFocusOut = true;
let isAccepted: boolean = false;
quickPick.onDidAccept(() => {
isAccepted = true;
const passphrase: string = quickPick.value;
quickPick.dispose();
resolve(passphrase);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
reject(new CanceledError());
quickPick.dispose();
});
}
});
}
class ConfirmationItem implements vscode.QuickPickItem, vscode.MessageItem {
title: string;
isCloseAffordance: boolean = true;
constructor(public label: string, public value: string) {
this.title = label;
}
}
const continueConfirmationPlaceholder: string = localize('ssh.continue.confirmation.placeholder', 'Are you sure you want to continue?');
export async function showHostKeyConfirmation(
host: string,
fingerprint: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(
localize('ssh.host.key.confirmation.title', '"{0}" has fingerprint "{1}".', host, fingerprint),
continueConfirmationPlaceholder,
cancelToken
);
}
export async function showDifferingHostConfirmation(
message: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(message, continueConfirmationPlaceholder, cancelToken);
}
async function showConfirmationPicker(
title: string,
placeholder: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.QuickPick<ConfirmationItem> = vscode.window.createQuickPick<ConfirmationItem>();
quickPick.canSelectMany = false;
quickPick.items = [new ConfirmationItem(localize('continue', 'Continue'), 'yes'), new ConfirmationItem(localize('cancel', 'Cancel'), 'no')];
quickPick.title = title;
quickPick.placeholder = placeholder;
let isAccepted: boolean = false;
quickPick.onDidAccept(async () => {
isAccepted = true;
const value: string = quickPick.selectedItems[0].value;
quickPick.dispose();
resolve(value);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
quickPick.hide();
reject(new CanceledError());
});
}
});
}
export interface ITerminalCommandWithLoginArgs {
systemInteractor: ISystemInteractor;
command: string;
nickname: string;
marker?: string;
usedInteractors?: Set<string>;
interactor?: IInteractor;
cwd?: string;
token?: vscode.CancellationToken;
continueOn?: string;
revealTerminal?: vscode.Event<void>;
}
export async function runSshTerminalCommandWithLogin(
host: ISshHostInfo,
terminalArgs: ITerminalCommandWithLoginArgs,
showLoginTerminal = false
): Promise<ProcessReturnType> {
const interactors: IInteractor[] = [];
if (terminalArgs.interactor) {
interactors.push(terminalArgs.interactor);
}
if (!showLoginTerminal) {
interactors.push(
new MitmInteractor(),
new FingerprintInteractor(host.hostName, showHostKeyConfirmation),
new PassphraseInteractor(showPassphraseInputBox),
new DifferingHostKeyInteractor(showDifferingHostConfirmation),
new PasswordInteractor(showPasswordInputBox),
new TwoFacInteractor(showVerificationCodeInputBox),
new DuoTwoFacInteractor(showVerificationCodeInputBox)
);
}
if (terminalArgs.continueOn) {
interactors.push(new ContinueOnInteractor(terminalArgs.continueOn));
}
// This terminal is always local
const result: ProcessReturnType = await runInteractiveSshTerminalCommand({
systemInteractor: terminalArgs.systemInteractor,
command: terminalArgs.command,
interactors,
usedInteractors: terminalArgs.usedInteractors,
nickname: terminalArgs.nickname,
token: terminalArgs.token,
marker: terminalArgs.marker,
revealTerminal: terminalArgs.revealTerminal,
showLoginTerminal,
cwd: terminalArgs.cwd ? vscode.Uri.file(terminalArgs.cwd) : undefined
});
return result;
}
export interface ITerminalCommandArgs {
systemInteractor: ISystemInteractor;
command: string;
interactors?: IInteractor[];
nickname: string;
usedInteractors?: Set<string>;
sendText?: string;
cwd?: vscode.Uri;
terminalIsWindows?: boolean;
token?: vscode.CancellationToken;
marker?: string;
revealTerminal?: vscode.Event<void>;
showLoginTerminal?: boolean; // If true, respect the showLoginTerminal setting
}
export function getPauseLogMarker(uuid: string): string {
return `${uuid}: pauseLog`;
}
export function getResumeLogMarker(uuid: string): string {
return `${uuid}: resumeLog`;
}
export function runInteractiveSshTerminalCommand(args: ITerminalCommandArgs): Promise<ProcessReturnType> {
const disposables: vscode.Disposable[] = [];
const { systemInteractor, command, interactors, nickname, token } = args;
let logIsPaused: boolean = false;
return new Promise(async (resolve, reject) => {
let stdout: string = '';
let windowListener: vscode.Disposable | undefined;
let terminalListener: vscode.Disposable | undefined;
let terminal: vscode.Terminal | undefined;
let tokenListener: vscode.Disposable;
let continueWithoutExiting: boolean = false;
const clean = () => {
if (terminalListener) {
terminalListener.dispose();
terminalListener = undefined;
}
if (terminal) {
terminal.dispose();
terminal = undefined;
}
if (windowListener) {
windowListener.dispose();
windowListener = undefined;
}
if (tokenListener) {
tokenListener.dispose();
}
disposables.forEach(disposable => disposable.dispose());
};
const done = (cancel: boolean = false, noClean: boolean = false, exitCode?: number) => {
if (!noClean) {
clean();
}
getOutputChannelLogger().appendLine(cancel ? localize('ssh.terminal.command.canceled', '"{0}" terminal command canceled.', nickname) : localize('ssh.terminal.command.done', '"{0}" terminal command done.', nickname));
if (cancel) {
if (continueWithoutExiting) {
getOutputChannelLogger().showWarningMessage(localize('ssh.continuing.command.canceled', 'Task \'{0}\' is canceled, but the underlying command may not be terminated. Please check manually.', command));
}
return reject(new CanceledError());
}
// When using showLoginTerminal, stdout include the passphrase prompt, etc. Try to get just the command output on the last line.
const actualOutput: string | undefined = cancel ? '' : lastNonemptyLine(stdout);
resolve({ succeeded: !exitCode, exitCode, output: actualOutput || '' });
};
const failed = (error?: any) => {
clean();
getOutputChannelLogger().showErrorMessage(localize('ssh.process.failed', '"{0}" process failed: {1}', nickname, error));
reject(error);
};
const handleOutputLogging = (data: string): void => {
let nextPauseState: boolean | undefined;
if (args.marker) {
const pauseMarker: string = getPauseLogMarker(args.marker);
const pauseIdx: number = data.lastIndexOf(pauseMarker);
if (pauseIdx >= 0) {
data = data.substring(0, pauseIdx + pauseMarker.length);
nextPauseState = true;
}
const resumeIdx: number = data.lastIndexOf(getResumeLogMarker(args.marker));
if (resumeIdx >= 0) {
data = data.substring(resumeIdx);
nextPauseState = false;
}
}
// Log the chunk of data that includes the pause/resume markers,
// so unpause first and pause after logging
if (!logIsPaused) {
logReceivedData(data, nickname);
}
if (typeof nextPauseState === 'boolean') {
logIsPaused = nextPauseState;
}
};
const handleTerminalOutput = async (dataWrite: vscode.TerminalDataWriteEvent): Promise<void> => {
handleOutputLogging(dataWrite.data);
stdout += dataWrite.data;
if (interactors) {
for (const interactor of interactors) {
try {
const interaction: IInteraction = await interactor.onData(stdout);
if (interaction.postAction === 'consume') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
stdout = '';
}
if (interaction.canceled) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
done(true);
return;
}
if (interaction.continue) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
continueWithoutExiting = true;
done(false, true);
return;
}
if (typeof interaction.response === 'string') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
if (terminal) {
terminal.sendText(`${interaction.response}\n`);
const logOutput: string = interaction.isPassword
? interaction.response.replace(/./g, '*')
: interaction.response;
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, logOutput));
}
}
} catch (e) {
failed(e);
}
}
}
};
if (token) {
tokenListener = token.onCancellationRequested(() => {
done(true);
});
}
const terminalIsWindows: boolean = typeof args.terminalIsWindows === 'boolean' ? args.terminalIsWindows : isWindows();
try {
// the terminal process should not fail, but exit cleanly
let shellArgs: string | string[];
if (args.sendText) {
shellArgs = '';
} else {
shellArgs = terminalIsWindows ? `/c (${command})\nexit /b %ErrorLevel%` : ['-c', `${command}\nexit $?`];
}
const options: vscode.TerminalOptions = {
cwd:
args.cwd ||
(terminalIsWindows
? vscode.Uri.file(os.homedir() || 'c:\\')
: vscode.Uri.file(os.homedir() || '/')),
name: nickname,
shellPath: getShellPath(terminalIsWindows),
shellArgs,
hideFromUser: true
};
let terminalDataHandlingQueue: Promise<void> = Promise.resolve();
terminalListener = systemInteractor.onDidWriteTerminalData(async e => {
if (e.terminal !== terminal) {
return;
}
terminalDataHandlingQueue = terminalDataHandlingQueue.finally(() => handleTerminalOutput(e));
});
terminal = systemInteractor.createTerminal(options);
if (args.revealTerminal) {
disposables.push(
args.revealTerminal(() => {
if (terminal) {
terminal.show();
}
})
);
}
if (args.sendText) {
const sendText: string = terminalIsWindows ? `(${args.sendText})\nexit /b %ErrorLevel%` : `${args.sendText}\nexit $?`;
terminal.sendText(sendText);
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, args.sendText));
}
if (args.showLoginTerminal) {
terminal.show();
}
windowListener = systemInteractor.onDidCloseTerminal(t => {
if (t === terminal) {
terminal = undefined; // Is already disposed
done(false, false, t.exitStatus?.code);
}
});
} catch (error) {
failed(error);
}
});
}
function getShellPath(_isWindows: boolean): string {
if (_isWindows) {
// Some users don't have cmd.exe on the path...
if (process.env.SystemRoot) {
// This var should always exist but be paranoid
const cmdPath: string = path.join(process.env.SystemRoot, 'System32', 'cmd.exe');
return cmdPath;
} else {
return 'cmd.exe';
}
} else {
// Note - can't rely on having sh in path (#590), and can't check the disk (bc remote terminals)
return '/bin/sh';
}
}
function logReceivedData(data: string, nickname: string): void {
const logData: string = data.replace(/\r?\n$/, ''); // Trim single trailing newline for nicer log
if (logData === ' ') {
// From the sleep command that must periodically echo ' '
return;
}
const markedLines: string = logData
.split(/\n/)
.map(line => `${nickname}> ${line}`)
.join('\n');
getOutputChannelLogger().appendLine(markedLines);
}
function lastNonemptyLine(str: string): string | undefined {
const lines: string[] = splitLines(str);
if (isWindows()) {
let outputContainingPipeError: string = '';
for (let i: number = lines.length - 1; i >= 0; i--) {
const strippedLine: string = stripEscapeSequences(lines[i]);
if (strippedLine.match(/The process tried to write to a nonexistent pipe/)) {
outputContainingPipeError = strippedLine;
continue;
}
if (!!strippedLine) {
return strippedLine;
}
}
if (outputContainingPipeError) {
return outputContainingPipeError;
}
}
const nonEmptyLines: string[] = lines.filter(l => !!l);
return nonEmptyLines[nonEmptyLines.length - 1];
}
+90 -116
View File
@@ -17,10 +17,11 @@ import * as assert from 'assert';
import * as https from 'https';
import * as tmp from 'tmp';
import { ClientRequest, OutgoingHttpHeaders } from 'http';
import { lookupString } from './nativeStrings';
import * as nls from 'vscode-nls';
import { Readable } from 'stream';
import * as jsonc from 'comment-json';
import { TargetPopulation } from 'vscode-tas-client';
import { CppSettings } from './LanguageServer/settings';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -320,13 +321,10 @@ export function resolveCachePath(input: string | undefined, additionalEnvironmen
return resolvedPath;
}
export function isWindows(): boolean {
return os.platform() === 'win32';
}
export function defaultExePath(): string {
const isWindows: boolean = os.platform() === 'win32';
const exePath: string = path.join('${fileDirname}', '${fileBasenameNoExtension}');
return isWindows() ? exePath + '.exe' : exePath;
return isWindows ? exePath + '.exe' : exePath;
}
export function findExePathInArgs(args: string[]): string | undefined {
@@ -572,9 +570,9 @@ export function checkDirectoryExistsSync(dirPath: string): boolean {
}
/** Test whether a relative path exists */
export function checkPathExistsSync(path: string, relativePath: string, _isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
export function checkPathExistsSync(path: string, relativePath: string, isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
let pathExists: boolean = true;
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && _isWindows && !isWSL && fs.existsSync(path + ".exe");
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && isWindows && !isWSL && fs.existsSync(path + ".exe");
if (!fs.existsSync(path)) {
if (existsWithExeAdded(path)) {
path += ".exe";
@@ -713,83 +711,32 @@ export function execChildProcess(process: string, workingDirectory?: string, cha
});
}
export interface ProcessReturnType {
succeeded: boolean;
exitCode?: number | NodeJS.Signals;
output: string;
}
export function spawnChildProcess(process: string, args: string[], workingDirectory: string,
dataCallback: (stdout: string) => void, errorCallback: (stderr: string) => void): Promise<void> {
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, cancellationToken);
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Information" || settings.loggingLevel === "Debug") {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}\n${programOutput.stderr || programOutput.stdout}\n`);
}
if (programOutput.exitCode) {
return { succeeded: false, exitCode, output: programOutput.stderr || programOutput.stdout || localize('process.exited', 'Process exited with code {0}', exitCode) };
} else {
let stdout: string;
if (programOutput.stdout.length) {
// Type system doesn't work very well here, so we need call toString
stdout = programOutput.stdout;
} else {
stdout = localize('process.succeeded', 'Process executed successfully.');
}
return { succeeded: true, exitCode, output: stdout };
}
}
return new Promise<void>(function (resolve, reject): void {
const child: child_process.ChildProcess = child_process.spawn(process, args, { cwd: workingDirectory });
interface ProcessOutput {
exitCode?: number | NodeJS.Signals;
stdout: string;
stderr: string;
}
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
return new Promise(async (resolve, reject) => {
let proc: child_process.ChildProcess;
if (await isExecutable(program)) {
proc = child_process.spawn(`.${isWindows() ? '\\' : '/'}${path.basename(program)}`, args, { shell: true, cwd: path.dirname(program) });
} else {
proc = child_process.spawn(program, args, { shell: true });
}
const cancellationTokenListener: vscode.Disposable | undefined = cancellationToken?.onCancellationRequested(() => {
getOutputChannelLogger().appendLine(localize('killing.process', 'Killing process {0}', program));
proc.kill();
});
const clean = () => {
proc.removeAllListeners();
if (cancellationTokenListener) {
cancellationTokenListener.dispose();
}
};
let stdout: string = '';
let stderr: string = '';
if (proc.stdout) {
proc.stdout.on('data', data => {
stdout += data.toString();
if (continueOn) {
const continueOnReg: string = escapeStringForRegex(continueOn);
if (stdout.search(continueOnReg)) {
resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
}
}
const stdout: Readable | null = child.stdout;
if (stdout) {
stdout.on('data', (data) => {
dataCallback(`${data}`);
});
}
if (proc.stderr) {
proc.stderr.on('data', data => stderr += data.toString());
const stderr: Readable | null = child.stderr;
if (stderr) {
stderr.on('data', (data) => {
errorCallback(`${data}`);
});
}
proc.on('close', (code, signal) => {
clean();
resolve({ exitCode: code || signal, stdout: stdout.trim(), stderr: stderr.trim() });
});
proc.on('error', error => {
clean();
reject(error);
child.on('exit', (code: number) => {
if (code !== 0) {
reject(new Error(localize("process.exited.with.code", "{0} exited with error code {1}", process, code)));
} else {
resolve();
}
});
});
}
@@ -980,6 +927,7 @@ function resolveWindowsEnvironmentVariables(str: string): string {
}
function legacyExtractArgs(argsString: string): string[] {
const isWindows: boolean = os.platform() === 'win32';
const result: string[] = [];
let currentArg: string = "";
let isWithinDoubleQuote: boolean = false;
@@ -1003,7 +951,7 @@ function legacyExtractArgs(argsString: string): string[] {
}
} else if (c === '\'') {
// On Windows, a single quote string is not allowed to join multiple args into a single arg
if (!isWindows()) {
if (!isWindows) {
if (!isWithinDoubleQuote) {
isWithinSingleQuote = !isWithinSingleQuote;
}
@@ -1249,6 +1197,67 @@ export class BlockingTask<T> {
}
}
interface VSCodeNlsConfig {
locale: string;
availableLanguages: {
[pack: string]: string;
};
}
export function getLocaleId(): string {
// This replicates the language detection used by initializeSettings() in vscode-nls
if (isString(process.env.VSCODE_NLS_CONFIG)) {
const vscodeOptions: VSCodeNlsConfig = JSON.parse(process.env.VSCODE_NLS_CONFIG) as VSCodeNlsConfig;
if (vscodeOptions.availableLanguages) {
const value: any = vscodeOptions.availableLanguages['*'];
if (isString(value)) {
return value;
}
}
if (isString(vscodeOptions.locale)) {
return vscodeOptions.locale.toLowerCase();
}
}
return "en";
}
export function getLocalizedHtmlPath(originalPath: string): string {
const locale: string = getLocaleId();
if (!locale.startsWith("en")) {
const localizedFilePath: string = getExtensionFilePath(path.join("dist/html/", locale, originalPath));
if (fs.existsSync(localizedFilePath)) {
return localizedFilePath;
}
}
return getExtensionFilePath(originalPath);
}
export interface LocalizeStringParams {
text: string;
stringId: number;
stringArgs: string[];
indentSpaces: number;
}
export function getLocalizedString(params: LocalizeStringParams): string {
let indent: string = "";
if (params.indentSpaces) {
indent = " ".repeat(params.indentSpaces);
}
let text: string = params.text;
if (params.stringId !== 0) {
text = lookupString(params.stringId, params.stringArgs);
}
return indent + text;
}
export function getLocalizedSymbolScope(scope: string, detail: string): string {
return localize({
key: "c.cpp.symbolscope.separator", comment:
["{0} is an untranslated C++ keyword (e.g. \"private\") and {1} is either another keyword (e.g. \"typedef\") or a localized property (e.g. a localized version of \"declaration\""]
}, "{0}, {1}", scope, detail);
}
function decodeUCS16(input: string): number[] {
const output: number[] = [];
let counter: number = 0;
@@ -1462,38 +1471,3 @@ export function isVsCodeInsiders(): boolean {
extensionPath.includes(".vscode-server-exploration");
}
export function stripEscapeSequences(str: string): string {
return str
.replace(/\x1b\[\??[0-9]{0,3}(;[0-9]{1,3})?[a-zA-Z]/g, '')
.replace(/\u0008/g, '')
.replace(/\r/g, '');
}
export function splitLines(data: string): string[] {
return data.split(/\r?\n/g);
}
export function escapeStringForRegex(str: string): string {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}
export function replaceAll(str: string, searchValue: string, replaceValue: string): string {
const pattern: string = escapeStringForRegex(searchValue);
const re: RegExp = new RegExp(pattern, 'g');
return str.replace(re, replaceValue);
}
export interface ISshHostInfo {
hostName: string;
user?: string;
port?: number | string;
}
export interface ISshLocalForwardInfo {
bindAddress?: string;
port?: number | string;
host?: string;
hostPort?: number | string;
localSocket?: string;
remoteSocket?: string;
}
-133
View File
@@ -1,133 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { isString, replaceAll } from './common';
import { getOutputChannelLogger } from './logger';
/**
* Support ExpansionVars (${var}), env (${env:var}), and optionally VS CODE commands (${command:commandID}).
* Supported format follows https://code.visualstudio.com/docs/editor/variables-reference
* Expand options and functions are mofidifed from https://github.com/microsoft/vscode-cmake-tools/blob/main/src/expand.ts
*/
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export interface ExpansionVars {
[key: string]: string;
workspaceFolder: string;
workspaceFolderBasename: string;
}
export interface ExpansionOptions {
vars: ExpansionVars;
doNotSupportCommands?: boolean;
recursive?: boolean;
}
export async function expandAllStrings(obj: any, options: ExpansionOptions): Promise<void> {
if (Array.isArray(obj) || (obj !== null && typeof obj === 'object')) {
for (const key of Object.keys(obj)) {
if (isString(obj[key])) {
obj[key] = await expandString(obj[key], options);
} else {
await expandAllStrings(obj[key], options);
}
}
}
}
export async function expandString(input: string, options: ExpansionOptions): Promise<string> {
const MAX_RECURSION: number = 10;
let result: string = input;
let didReplacement: boolean = false;
let i: number = 0;
do {
// TODO: consider a full circular reference check?
[result, didReplacement] = await expandStringImpl(result, options);
i++;
} while (i < MAX_RECURSION && options.recursive && didReplacement);
if (i === MAX_RECURSION && didReplacement) {
getOutputChannelLogger().showErrorMessage(localize('max.recursion.reached', 'Reached max string expansion recursion. Possible circular reference.'));
}
return replaceAll(result, '${dollar}', '$');
}
/** Returns [expandedString, didReplacement] */
async function expandStringImpl(input: string, options: ExpansionOptions): Promise<[string, boolean]> {
if (!input) {
return [input, false];
}
// We accumulate a list of substitutions that we need to make, preventing
// recursively expanding or looping forever on bad replacements
const subs: Map<string, string> = new Map<string, string>();
const var_re: RegExp = /\$\{(\w+)\}/g;
let match: RegExpMatchArray | null = null;
while ((match = var_re.exec(input))) {
const full: string = match[0];
const key: string = match[1];
if (key !== 'dollar') {
// Replace dollar sign at the very end of the expanding process
const repl: string = options.vars[key];
if (!repl) {
getOutputChannelLogger().showWarningMessage(localize('invalid.var.reference', 'Invalid variable reference {0} in string: {1}.', full, input));
} else {
subs.set(full, repl);
}
}
}
// Regular expression for variable value (between the variable suffix and the next ending curly bracket):
// .+? matches any character (except line terminators) between one and unlimited times,
// as few times as possible, expanding as needed (lazy)
const varValueRegexp: string = ".+?";
const env_re: RegExp = RegExp(`\\$\\{env:(${varValueRegexp})\\}`, "g");
while ((match = env_re.exec(input))) {
const full: string = match[0];
const varname: string = match[1];
if (process.env[varname] === undefined) {
getOutputChannelLogger().showWarningMessage(localize('env.var.not.found', 'Environment variable {0} not found', varname));
}
const repl: string = process.env[varname] || '';
subs.set(full, repl);
}
const command_re: RegExp = RegExp(`\\$\\{command:(${varValueRegexp})\\}`, "g");
while ((match = command_re.exec(input))) {
if (options.doNotSupportCommands) {
getOutputChannelLogger().showWarningMessage(localize('commands.not.supported', 'Commands are not supported for string: {0}.', input));
break;
}
const full: string = match[0];
const command: string = match[1];
if (subs.has(full)) {
continue; // Don't execute commands more than once per string
}
try {
const command_ret: unknown = await vscode.commands.executeCommand(command, options.vars.workspaceFolder);
subs.set(full, `${command_ret}`);
} catch (e: any) {
getOutputChannelLogger().showWarningMessage(localize('exception.executing.command', 'Exception while executing command {0} for string: {1} {2}.', command, input, e));
}
}
let result: string = input;
let didReplacement: boolean = false;
subs.forEach((value, key) => {
if (value !== key) {
result = replaceAll(result, key, value);
didReplacement = true;
}
});
return [result, didReplacement];
}
+1 -76
View File
@@ -8,11 +8,6 @@ import * as vscode from 'vscode';
import * as os from 'os';
import { CppSettings } from './LanguageServer/settings';
import { CppSourceStr } from './LanguageServer/extension';
import * as nls from 'vscode-nls';
import { getLocalizedString, LocalizeStringParams } from './LanguageServer/localization';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
// This is used for testing purposes
let Subscriber: (message: string) => void;
@@ -72,10 +67,7 @@ export class Logger {
}
}
export let outputChannel: vscode.OutputChannel | undefined;
export let diagnosticsChannel: vscode.OutputChannel | undefined;
export let debugChannel: vscode.OutputChannel | undefined;
export let warningChannel: vscode.OutputChannel | undefined;
let outputChannel: vscode.OutputChannel | undefined;
export function getOutputChannel(): vscode.OutputChannel {
if (!outputChannel) {
@@ -89,13 +81,6 @@ export function getOutputChannel(): vscode.OutputChannel {
return outputChannel;
}
export function getDiagnosticsChannel(): vscode.OutputChannel {
if (!diagnosticsChannel) {
diagnosticsChannel = vscode.window.createOutputChannel(localize("c.cpp.diagnostics", "C/C++ Diagnostics"));
}
return diagnosticsChannel;
}
export function showOutputChannel(): void {
getOutputChannel().show();
}
@@ -108,63 +93,3 @@ export function getOutputChannelLogger(): Logger {
}
return outputChannelLogger;
}
export function log(output: string): void {
if (!outputChannel) {
outputChannel = getOutputChannel();
}
outputChannel.appendLine(`${output}`);
}
export interface DebugProtocolParams {
jsonrpc: string;
method: string;
params?: any;
}
export function logDebugProtocol(output: DebugProtocolParams): void {
if (!debugChannel) {
debugChannel = vscode.window.createOutputChannel(`${localize("c.cpp.debug.protocol", "C/C++ Debug Protocol")}`);
}
debugChannel.appendLine("");
debugChannel.appendLine("************************************************************************************************************************");
debugChannel.append(`${output}`);
}
export interface ShowWarningParams {
localizeStringParams: LocalizeStringParams;
}
export function showWarning(params: ShowWarningParams): void {
const message: string = getLocalizedString(params.localizeStringParams);
let showChannel: boolean = false;
if (!warningChannel) {
warningChannel = vscode.window.createOutputChannel(`${localize("c.cpp.warnings", "C/C++ Configuration Warnings")}`);
showChannel = true;
}
// Append before showing the channel, to avoid a delay.
warningChannel.appendLine(`[${new Date().toLocaleString()}] ${message}`);
if (showChannel) {
warningChannel.show(true);
}
}
export function logLocalized(params: LocalizeStringParams): void {
const output: string = getLocalizedString(params);
log(output);
}
export function disposeOutputChannels(): void {
if (outputChannel) {
outputChannel.dispose();
}
if (diagnosticsChannel) {
diagnosticsChannel.dispose();
}
if (debugChannel) {
debugChannel.dispose();
}
if (warningChannel) {
warningChannel.dispose();
}
}
+5 -13
View File
@@ -21,8 +21,6 @@ import { TargetPopulation } from 'vscode-tas-client';
import * as semver from 'semver';
import * as nls from 'vscode-nls';
import { cppBuildTaskProvider, CppBuildTaskProvider } from './LanguageServer/cppBuildTaskProvider';
import { getLocaleId, getLocalizedHtmlPath } from './LanguageServer/localization';
import { disposeOutputChannels, log } from './logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -42,7 +40,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
public async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
console.assert(uri.path[0] === '/', "A preceeding slash is expected on schema uri path");
const fileName: string = uri.path.substring(1);
const locale: string = getLocaleId();
const locale: string = util.getLocaleId();
let localizedFilePath: string = util.getExtensionFilePath(path.join("dist/schema/", locale, fileName));
const fileExists: boolean = await util.checkFileExists(localizedFilePath);
if (!fileExists) {
@@ -81,8 +79,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
// Read the setting and determine whether we should activate the language server prior to installing callbacks,
// to ensure there is no potential race condition. LanguageServer.activate() is called near the end of this
// function, to allow any further setup to occur here, prior to activation.
const isIntelliSenseEngineDisabled: boolean = settings.intelliSenseEngine === "Disabled";
const shouldActivateLanguageServer: boolean = (!isIntelliSenseEngineDisabled && !isOldMacOs);
const shouldActivateLanguageServer: boolean = (settings.intelliSenseEngine !== "Disabled" && !isOldMacOs);
if (isOldMacOs) {
languageServiceDisabled = true;
@@ -137,24 +134,19 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
if (shouldActivateLanguageServer) {
await LanguageServer.activate();
} else if (isIntelliSenseEngineDisabled) {
// The check here for isIntelliSenseEngineDisabled avoids logging
// the message on old Macs that we've already displayed a warning for.
log(localize("intellisense.disabled", "intelliSenseEngine is Disabled"));
}
return cppTools;
}
export async function deactivate(): Promise<void> {
export function deactivate(): Thenable<void> {
DebuggerExtension.dispose();
Telemetry.deactivate();
disposables.forEach(d => d.dispose());
if (languageServiceDisabled) {
return Promise.resolve();
}
await LanguageServer.deactivate();
disposeOutputChannels();
return LanguageServer.deactivate();
}
async function makeBinariesExecutable(): Promise<void> {
@@ -330,7 +322,7 @@ async function checkVsixCompatibility(): Promise<void> {
if (promise) {
promise.then(async (value) => {
if (value === moreInfoButton) {
await vscode.commands.executeCommand("markdown.showPreview", vscode.Uri.file(getLocalizedHtmlPath("Reinstalling the Extension.md")));
await vscode.commands.executeCommand("markdown.showPreview", vscode.Uri.file(util.getLocalizedHtmlPath("Reinstalling the Extension.md")));
} else if (value === ignoreButton) {
ignoreMismatchedCompatibleVsix.Value = true;
}
+3 -3
View File
@@ -4,7 +4,7 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import TelemetryReporter from '@vscode/extension-telemetry';
import TelemetryReporter from 'vscode-extension-telemetry';
import { getExperimentationServiceAsync, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client';
import * as util from './common';
@@ -89,11 +89,11 @@ export async function deactivate(): Promise<void> {
}
}
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }, metrics?: { [key: string]: number }): void {
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "cppdbg/VS/Diagnostics/Debugger/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties);
}
};
+1 -2
View File
@@ -14,7 +14,6 @@
"include": [
"test/**/*.ts",
"tools/**/*.ts",
"ui/**/*.ts",
"./vscode*.d.ts"
"ui/**/*.ts"
]
}
-46
View File
@@ -1,46 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as assert from "assert";
import { ExpansionOptions, expandAllStrings, expandString } from "../../src/expand";
suite('Var expansion validation', () => {
test('Expand all strings', async () => {
const input: object = {
in1: "${test2}",
in2: "${test4}",
in3: [
"${test3}",
{
in4: "${test3}"
}
]
};
const variables: object = {
test1: "t1",
test2: "${dollar}{${test1}}",
test3: "test${test2}test:${env:envtest}:${dollar}test",
test4: "${test4}"
};
const expansionOptions: ExpansionOptions = {
vars: {
workspaceFolder: '{workspaceFolder}',
workspaceFolderBasename: '{workspaceFolderBasename}',
...variables
},
recursive: true
};
await expandAllStrings(input, expansionOptions);
assert.deepStrictEqual(input, {
in1: "${t1}",
in2: "${test4}",
in3: [
"test${t1}test::$test",
{
in4: "test${t1}test::$test"
}
]
});
});
});
+7 -8
View File
@@ -53,7 +53,7 @@ function updateDefaults(object: any, defaults: any): any {
}
function refReplace(definitions: any, ref: any): any {
// $ref is formatted as "#/definitions/ObjectName"
// $ref is formatted as "#/definitions/ObjectName"
const referenceStringArray: string[] = ref['$ref'].split('/');
// Getting "ObjectName"
@@ -82,7 +82,11 @@ function replaceReferences(definitions: any, objects: any): any {
// Handle 'anyOf' with references
if (objects[key].hasOwnProperty('anyOf')) {
objects[key].anyOf = replaceReferences(definitions, objects[key].anyOf);
for (const index in objects[key].anyOf) {
if (objects[key].anyOf[index].hasOwnProperty('$ref')) {
objects[key].anyOf[index] = refReplace(definitions, objects[key].anyOf[index]);
}
}
}
// Recursively replace references if this object has properties.
@@ -91,15 +95,10 @@ function replaceReferences(definitions: any, objects: any): any {
objects[key].properties = updateDefaults(objects[key].properties, objects[key].default);
}
// Items in array contains ref
// Recursively replace references if the array has objects in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null && objects[key].items.hasOwnProperty('$ref')) {
objects[key].items = refReplace(definitions, objects[key].items);
}
// Recursively replace references if the array has objects that contains ref in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null) {
objects[key].items = replaceReferences(definitions, objects[key].items);
}
}
return objects;
+2 -321
View File
@@ -193,313 +193,6 @@
}
}
},
"Variables": {
"type": "object",
"description": "%c_cpp.debuggers.variables.description%",
"default": {
"<variable-name>": "<variable-value>"
},
"properties": {},
"additionalProperties": {
"type": "string",
"description": "%c_cpp.debuggers.variables.properties.description%",
"default": ""
}
},
"VsCodeCommand": {
"type": "object",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": "",
"enum": [
"command"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.command.description%",
"default": ""
},
"args": {
"type": "array",
"description": "%c_cpp.debuggers.vsCodeCommand.args.description%",
"items": {
"type": "string"
}
}
}
},
"Host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"DeploySteps": {
"type": "array",
"description": "%c_cpp.debuggers.deploySteps.description%",
"items": {
"anyOf": [
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": {},
"required": [
"type",
"files",
"host",
"targetDir"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": "",
"enum": [
"scp"
]
},
"files": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "%c_cpp.debuggers.deploySteps.scp.files.description%",
"default": ""
},
"host": {
"$ref": "#/definitions/Host"
},
"targetDir": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.targetDir.description%",
"default": ""
},
"scpPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.scpPath.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": {},
"required": [
"type",
"host",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": "",
"enum": [
"ssh"
]
},
"host": {
"$ref": "#/definitions/Host"
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.command.description%",
"default": ""
},
"sshPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.sshPath.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": "",
"enum": [
"shell"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.command.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"$ref": "#/definitions/VsCodeCommand"
}
]
},
"default": []
},
"CppdbgLaunchOptions": {
"type": "object",
"required": [
@@ -560,8 +253,8 @@
},
"launchCompleteCommand": {
"enum": [
"exec-run",
"exec-continue",
"exec-run",
"exec-continue",
"None"
],
"description": "%c_cpp.debuggers.launchCompleteCommand.description%",
@@ -706,12 +399,6 @@
"$ref": "#/definitions/HardwareBreakpoints",
"description": "%c_cpp.debuggers.hardwareBreakpoints.description%",
"default": {}
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},
@@ -826,12 +513,6 @@
"symbolLoadInfo": {
"$ref": "#/definitions/SymbolLoadInfo",
"description": "%c_cpp.debuggers.symbolLoadInfo.description%"
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},
+1 -1
View File
@@ -15,7 +15,7 @@
},
"include": [
"src/**/*.ts",
"./vscode*.d.ts",
"./node_modules/vscode/vscode.d.ts",
"./node_modules/vscode/lib/*"
]
}
+41 -122
View File
@@ -44,14 +44,14 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
"@es-joy/jsdoccomment@~0.31.0":
version "0.31.0"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz#dbc342cc38eb6878c12727985e693eaef34302bc"
integrity sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==
"@es-joy/jsdoccomment@0.10.8":
version "0.10.8"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz#b3152887e25246410ed4ea569a55926ec13b2b05"
integrity sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==
dependencies:
comment-parser "1.3.1"
comment-parser "1.2.4"
esquery "^1.4.0"
jsdoc-type-pratt-parser "~3.1.0"
jsdoc-type-pratt-parser "1.1.1"
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
@@ -101,42 +101,6 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@microsoft/[email protected]", "@microsoft/1ds-core-js@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7"
integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g==
dependencies:
"@microsoft/applicationinsights-core-js" "2.8.4"
"@microsoft/applicationinsights-shims" "^2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/1ds-post-js@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216"
integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ==
dependencies:
"@microsoft/1ds-core-js" "3.2.3"
"@microsoft/applicationinsights-shims" "^2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/[email protected]":
version "2.8.4"
resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596"
integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ==
dependencies:
"@microsoft/applicationinsights-shims" "2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/[email protected]", "@microsoft/applicationinsights-shims@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd"
integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ==
"@microsoft/dynamicproto-js@^1.1.6":
version "1.1.6"
resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc"
integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg==
"@nodelib/[email protected]":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
@@ -290,14 +254,6 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe"
integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==
"@types/glob@^7.1.3":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/json-schema@*", "@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
@@ -313,11 +269,6 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@@ -365,6 +316,11 @@
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd"
integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==
"@types/[email protected]":
version "1.60.0"
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.60.0.tgz#9330c317691b4f53441a18b598768faeeb71618a"
integrity sha512-wZt3VTmzYrgZ0l/3QmEbCq4KAJ71K3/hmMQ/nfpv84oH8e81KKwPEoQ5v8dNCxfHFVJ1JabHKmCvqdYOoVm1Ow==
"@types/which@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
@@ -459,14 +415,6 @@
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
"@vscode/extension-telemetry@^0.6.2":
version "0.6.2"
resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e"
integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w==
dependencies:
"@microsoft/1ds-core-js" "^3.2.3"
"@microsoft/1ds-post-js" "^3.2.3"
"@vscode/test-electron@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-1.6.1.tgz#2b282154097e250ee9b94b6a284eb5804e53a3d7"
@@ -1384,10 +1332,10 @@ comment-json@^4.1.1:
has-own-prop "^2.0.0"
repeat-string "^1.6.1"
comment-parser@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b"
integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==
comment-parser@1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.2.4.tgz#489f3ee55dfd184a6e4bffb31baba284453cb760"
integrity sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==
component-emitter@^1.2.1:
version "1.3.0"
@@ -1505,7 +1453,7 @@ [email protected]:
dependencies:
ms "^2.1.1"
debug@4:
debug@4, debug@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
@@ -1540,13 +1488,6 @@ debug@^4.0.1, debug@^4.1.1:
dependencies:
ms "^2.1.1"
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
decamelize@^1.1.1, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -1929,17 +1870,19 @@ eslint-plugin-import@^2.24.2:
resolve "^1.20.0"
tsconfig-paths "^3.11.0"
eslint-plugin-jsdoc@^39.3.3:
version "39.3.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.3.tgz#75dd67ce581e7527a69f27800138cc0f9c388236"
integrity sha512-K/DAjKRUNaUTf0KQhI9PvsF+Y3mGDx/j0pofXsJCQe/tmRsRweBIXR353c8nAro0lytZYEf7l0PluBpzKDiHxw==
eslint-plugin-jsdoc@^36.1.0:
version "36.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.1.0.tgz#8dfe5f27edfb6aa3812e6d86ccaea849ddc86b03"
integrity sha512-Qpied2AJCQcScxfzTObLKRiP5QgLXjMU/ITjBagEV5p2Q/HpumD1EQtazdRYdjDSwPmXhwOl2yquwOGQ4HOJNw==
dependencies:
"@es-joy/jsdoccomment" "~0.31.0"
comment-parser "1.3.1"
debug "^4.3.4"
escape-string-regexp "^4.0.0"
"@es-joy/jsdoccomment" "0.10.8"
comment-parser "1.2.4"
debug "^4.3.2"
esquery "^1.4.0"
semver "^7.3.7"
jsdoc-type-pratt-parser "^1.1.1"
lodash "^4.17.21"
regextras "^0.8.0"
semver "^7.3.5"
spdx-expression-parse "^3.0.1"
eslint-scope@^5.0.0:
@@ -3464,10 +3407,10 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
jsdoc-type-pratt-parser@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e"
integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==
jsdoc-type-pratt-parser@1.1.1, jsdoc-type-pratt-parser@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz#10fe5e409ba38de22a48b555598955a26ff0160f"
integrity sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
@@ -3534,11 +3477,6 @@ kind-of@^6.0.0, kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
last-run@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
@@ -4494,14 +4432,6 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prompts@^2.1.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
dependencies:
kleur "^3.0.3"
sisteransi "^1.0.5"
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -4655,6 +4585,11 @@ regexpp@^3.1.0:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
regextras@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.8.0.tgz#ec0f99853d4912839321172f608b544814b02217"
integrity sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==
remove-bom-buffer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
@@ -4883,13 +4818,6 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
[email protected], serialize-javascript@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
@@ -4970,11 +4898,6 @@ signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -5867,14 +5790,10 @@ [email protected], vscode-debugprotocol@^1.35.0:
resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.38.0.tgz#7a9bcd457e6642f48fabef114c0fa1c25a2fb1e7"
integrity sha512-oam9iSjNfXSn71a8bmNsXv8k/rIKSOcllIPrFnNgxd1EMBpfnum+gb7lmRpcH0zSjGb+OH8Ncn8B5tv8srWbNQ==
vscode-dts@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/vscode-dts/-/vscode-dts-0.3.3.tgz#e5ef3afe76182875b252cca7f449938e4a0bf28a"
integrity sha512-JfOsWL0NvfVw0UF9bcTjlv1Onz3Ted7cgpPWKWMnHGB+72t/tn8WFDeKLZO42l2k9KJq/NGS9rFC5gZbyI4FTg==
dependencies:
minimist "^1.2.0"
prompts "^2.1.0"
rimraf "^3.0.0"
vscode-extension-telemetry@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.4.4.tgz#e5d5ac90ea7d07ec054f5310893d95d43d5984b0"
integrity sha512-LzirNf2GnykXCAqqWrvj+snYqgkPVyjwM72tYOHgcZiG/ZRuNjmqlgvs+SomEJdmD8cutduitPmhoyIuzOrVfA==
vscode-jsonrpc@^4.0.0:
version "4.0.0"
@@ -6216,4 +6135,4 @@ yauzl@^2.10.0:
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+1
View File
@@ -7,3 +7,4 @@ This extension pack includes a set of popular extensions for C++ development in
* [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools)
* [Doxygen Documentation Generator](https://marketplace.visualstudio.com/items?itemName=cschlosser.doxdocgen)
* [Better C++ Syntax](https://marketplace.visualstudio.com/items?itemName=jeff-hykin.better-cpp-syntax)
* [Remote Development Extension Pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)