Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8309a022d9 | ||
|
|
acaa8d116f | ||
|
|
18a108a7d2 | ||
|
|
998b2570b8 | ||
|
|
23f4d67ed8 | ||
|
|
e7c7ccd362 | ||
|
|
01cfad93a2 | ||
|
|
6532902f76 | ||
|
|
d225eeb592 | ||
|
|
10563fad14 | ||
|
|
803e8a9c22 | ||
|
|
c5899fa663 | ||
|
|
9f99738cb5 | ||
|
|
9a3da2b74f | ||
|
|
0e2ddc6954 | ||
|
|
58f5ae3e57 | ||
|
|
f487c9be4e | ||
|
|
c48a4fb0e0 | ||
|
|
54bfc004a5 | ||
|
|
b603db62f9 | ||
|
|
0aa3fc8804 | ||
|
|
94f05866a4 | ||
|
|
5e17eeeeae | ||
|
|
c983a011bd | ||
|
|
30b5be6540 | ||
|
|
a433293530 | ||
|
|
9313999c8e | ||
|
|
ba4d4131cd | ||
|
|
e2d7deb912 | ||
|
|
22439cccde | ||
|
|
e9b2659e1e |
@@ -134,6 +134,10 @@ export async function main() {
|
||||
packageJSON.contributes.debuggers[1].configurationAttributes.launch = schemaJSON.definitions.CppvsdbgLaunchOptions;
|
||||
packageJSON.contributes.debuggers[1].configurationAttributes.attach = schemaJSON.definitions.CppvsdbgAttachOptions;
|
||||
|
||||
// cpplldb
|
||||
packageJSON.contributes.debuggers[2].configurationAttributes.launch = schemaJSON.definitions.CpplldbLaunchOptions;
|
||||
packageJSON.contributes.debuggers[2].configurationAttributes.attach = schemaJSON.definitions.CpplldbAttachOptions;
|
||||
|
||||
let content: string = JSON.stringify(packageJSON, null, 4);
|
||||
|
||||
// We use '\u200b' (unicode zero-length space character) to break VS Code's URL detection regex for URLs that are examples. This process will
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -180,9 +180,12 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mergeConfigurations": {
|
||||
"markdownDescription": "Set to `true` to merge `includePath`, `defines`, `forcedInclude`, and `browse.path` with those received from the configuration provider.",
|
||||
"descriptionHint": "{Locked=\"`true`\"} {Locked=\"`includePath`\"} {Locked=\"`defines`\"} {Locked=\"`forcedInclude`\"} {Locked=\"`browse.path`\"}",
|
||||
"type": "boolean"
|
||||
"markdownDescription": "Set to `true` to merge include paths, defines, and forced includes with those from a configuration provider.",
|
||||
"descriptionHint": "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.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"browse": {
|
||||
"type": "object",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "如果为 true,应忽略此命令的失败。默认值为 false。",
|
||||
"c_cpp.debuggers.program.description": "程序可执行文件的完整路径。",
|
||||
"c_cpp.debuggers.args.description": "传递给程序的命令行参数。",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "引擎的类型。必须为 \"cppdbg\"。",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "引擎的类型。必须为 \"cppvsdbg\"。",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "调试对象的体系结构。如果未设置此参数,将进行自动检测。允许的值有 x86、arm、arm64、mips、x64、amd64、x86_64。",
|
||||
"c_cpp.debuggers.cwd.description": "目标的工作目录。",
|
||||
"c_cpp.debuggers.setupCommands.description": "为了安装基础调试程序而执行的一个或多个 GDB/LLDB 命令。示例: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }]。",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "MI 调试程序(如 gdb)的其他参数。",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "要连接到的 MI 调试程序服务器的网络地址(示例: localhost:1234)。",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "使用目标扩展远程模式连接到 MI 调试器服务器。",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "可选参数。如果为 `true`,则调试程序应在目标的入口点处停止。如果传递了 `processId`,则不起任何作用。",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "可选参数。如果为 true,则调试程序应在目标的入口点处停止。如果传递了 processId,则不起任何作用。",
|
||||
"c_cpp.debuggers.debugServerPath.description": "到要启动的调试服务器的可选完整路径。默认值为 null。该路径与 “miDebugServerAddress” 或带有运行 “-target-select remote <server:port>” 的 “customSetupCommand” 的自有服务器配合使用。",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "可选调试服务器参数。默认为 null。",
|
||||
"c_cpp.debuggers.serverStarted.description": "要在调试服务器输出中查找的可选服务器启动模式。默认为 null。",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "控制台应用程序将在外部终端窗口中启动。该窗口将在重新启动方案中重复使用,并且在应用程序退出时不会自动消失。",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "控制台应用程序将在自身的外部控制台窗口中启动,该窗口将在应用程序停止时结束。非控制台应用程序将在没有终端的情况下运行,并且 stdout/stderr 将被忽略。",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "如果为 true,则禁用集成终端支持所需的调试对象控制台重定向。",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "传递到调试引擎的可选源文件映射。示例: `{ \"<original source path>\": \"<current source path>\" }`。",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "要将调试程序附加到的可选进程 ID。使用 `${command:pickProcess}` 获取要附加到的本地运行进程的列表。请注意,一些平台需要管理员权限才能附加到进程。",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "传递给调试引擎的可选源文件映射。示例: '{ \"/original/source/path\":\"/current/source/path\" }'。",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "要将调试程序附加到的可选进程 ID。使用 \"${command:pickProcess}\" 获取要附加到的本地运行进程的列表。请注意,一些平台需要管理员权限才能附加到进程。",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "用于搜索符号(即 pdb)文件的目录列表(以分号分隔)。示例: \"c:\\dir1;c:\\dir2\"。",
|
||||
"c_cpp.debuggers.dumpPath.description": "指定程序的转储文件的可选完整路径。例如: \"c:\\temp\\app.dmp\"。默认为 null。",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "如果为 false,将在禁用调试堆的情况下启动该进程。这会将环境变量 \"_NO_DEBUG_HEAP\" 设置为 \"1\"。",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "要复制的文件。支持路径模式。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "目标目录。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "如果为 true,则以递归方式复制文件夹。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP 的可选完整路径。假定 SCP 位于 PATH 上(如果未指定)。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync 的可选完整路径。假定 rsync 在 PATH 上(如果未指定)。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP 的可选完整路径。假定 SCP 位于 PATH 上(如果未指定)",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync 的可选完整路径。假定 rsync 在 PATH 上(如果未指定)",
|
||||
"c_cpp.debuggers.deploySteps.debug": "如果为 true,则在不调试的情况下启动时跳过。如果为 false,则在开始调试时跳过。如果未定义,则从不跳过。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "SSH 命令步骤。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "要通过 SSH 执行的命令。SSH 命令中 \"-c\" 后面的命令。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH 的可选完整路径。假定 SSH 位于 PATH 上(如果未指定)。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH 的可选完整路径。假定 SSH 位于 PATH 上(如果未指定)",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "输出中的可选完成模式。在输出中看到此模式时,无论此步骤是否返回,都继续执行部署过程。",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "shell 命令步骤。",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "要执行的 shell 命令。",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "若為 true,則應略過來自命令的失敗。預設值為 false。",
|
||||
"c_cpp.debuggers.program.description": "程式可執行檔的完整路徑。",
|
||||
"c_cpp.debuggers.args.description": "傳遞至程式的命令列引數。",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "引擎的類型。必須是 \"cppdbg\"。",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "引擎的類型。必須是 \"cppvsdbg\"。",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "偵錯項目的架構。除非設定此參數,否則將會受到自動偵測。允許的值為 x86、arm、arm64、mips、x64、amd64 及 x86_64。",
|
||||
"c_cpp.debuggers.cwd.description": "目標的工作目錄。",
|
||||
"c_cpp.debuggers.setupCommands.description": "為了安裝基礎偵錯工具而要執行的一或多個 GDB/LLDB 命令。範例: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }]。",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "MI 偵錯工具 (例如 gdb) 的其他引數。",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "MI 偵錯工具伺服器要連線至的網路位址 (範例: localhost:1234)。",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "使用目標延伸的遠端模式連線到 MI 偵錯工具伺服器。",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "選擇性參數。若為 `true`,則偵錯工具應該在目標的進入點停止。如果已傳遞 `processId`,則這就無效。",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "選擇性參數。若為 true,則偵錯工具應該在目標的進入點停止。如果已傳遞 processId。就沒有效果。",
|
||||
"c_cpp.debuggers.debugServerPath.description": "要啟動的偵錯伺服器選用完整路徑。預設為 Null。使用時,會將 \"miDebugServerAddress\" 或您自己的伺服器與 \"customSetupCommand\" 連接,以執行 \"-target-select remote <伺服器:連接埠>\"。",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "選擇性偵錯伺服器引數。預設為 null。",
|
||||
"c_cpp.debuggers.serverStarted.description": "要在偵錯伺服器輸出中尋找的選擇性伺服器啟動模式。預設為 null。",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "主控台應用程式將會在外部終端視窗中啟動。此視窗將在重新啟動情節中重複使用,且在應用程式結束時不會自動消失。",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "主控台應用程式將會在其本身的外部主控台視窗中啟動,該視窗會在應用程式停止時結束。非主控台應用程式將在沒有終端的情況下執行,而且將忽略 stdout/stderr。",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "若為 true,則停用整合式終端機支援需要的偵錯項目主控台重新導向。",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "傳遞至偵錯引擎的選擇性來源檔案對應。範例: `{ \"<original source path>\": \"<current source path>\" }`。",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "要附加偵錯工具的選擇性處理序識別碼。使用 `${command:pickProcess}` 可取得要附加的本機執行中處理序清單。請注意,某些平台需要系統管理員權限才能附加至處理序。",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "傳遞給偵錯引擎的選擇性來源檔案對應。範例: '{ \"/original/source/path\":\"/current/source/path\" }'。",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "要附加偵錯工具的選擇性處理序識別碼。使用 \"${command:pickProcess}\" 可取得要附加的本機執行中處理序清單。請注意,某些平台需要系統管理員權限才能附加至處理序。",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "要用於搜尋符號 (即 pdb) 檔案的目錄清單 (以分號分隔)。範例: \"c:\\dir1;c:\\dir2\"。",
|
||||
"c_cpp.debuggers.dumpPath.description": "指定程式之傾印檔案的選擇性完整路徑。範例: \"c:\\temp\\app.dmp\"。預設為 null。",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "若為 false,將會啟動已停用偵錯堆積的處理序。這會將環境變數 '_NO_DEBUG_HEAP' 設為 '1'。",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "要複製的檔案。支援路徑模式。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "目標目錄。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "若為 True,會以遞迴方式複製資料夾。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP 的選用完整路徑。如果未指定,則會假設 SCP 在 PATH 上。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync 的選用完整路徑。如果未指定,則會假設 rsync 在 PATH 上。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP 的選用完整路徑。如果未指定,則會假設 SCP 在 PATH 上",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync 的選用完整路徑。如果未指定,則會假設 rsync 在 PATH 上",
|
||||
"c_cpp.debuggers.deploySteps.debug": "如果為 True,則在啟動而不偵錯的情況下略過。如果為 False,則在啟動而偵錯的情況下略過。如果未定義,則永不略過。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "SSH 命令步驟。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "要透過 SSH 執行的命令。SSH 命令中 '-c' 之後的命令。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH 的選用完整路徑。如果未指定,則會假設 SSH 在 PATH 上。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH 的選用完整路徑。如果未指定,則會假設 SSH 在 PATH 上",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "輸出中選用的完成模式。當輸出中出現此模式,則會繼續執行部署程序 (而無論此步驟是否傳回)。",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "殼層命令步驟。",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "要執行的殼層命令。",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Pokud má hodnotu true, měla by se ignorovat selhání z daného příkazu. Výchozí hodnota je false.",
|
||||
"c_cpp.debuggers.program.description": "Úplná cesta ke spustitelnému souboru programu",
|
||||
"c_cpp.debuggers.args.description": "Argumenty příkazového řádku, které se předávají do programu",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Typ modulu. Musí to být cppdbg.",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Typ modulu. Musí to být cppvsdbg.",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Architektura laděného procesu. Pokud tento parametr není nastavený, automaticky se rozpozná. Povolené hodnoty jsou x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Pracovní adresář cíle",
|
||||
"c_cpp.debuggers.setupCommands.description": "Jeden nebo více příkazů GDB/LLDB, které se mají provést, aby se nastavil odpovídající ladicí program. Příklad: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }]",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Další argumenty pro ladicí program MI (třeba gdb)",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Síťová adresa MI Debugger Serveru, ke kterému se má připojit (příklad: localhost:1234)",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Připojení k serveru ladicího programu MI přes cílový rozšířený vzdálený režim.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Nepovinný parametr. Pokud je `true`, ladicí program by se měl zastavit na vstupním bodu cíle. Pokud je předán parametr `processId`, nemá to žádný vliv.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Nepovinný parametr. Když se nastaví na true, ladicí program by se měl zastavit u vstupního bodu cíle. Pokud se předá processId, nemá parametr žádný vliv.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Volitelná úplná cesta k ladicímu serveru, který se má spustit. Výchozí hodnota je null. Používá se ve spojení buď s miDebugServerAddress, nebo s vlastním serverem s customSetupCommand, na kterém běží \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Volitelné argumenty ladicího serveru. Výchozí hodnota je null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Volitelný vzorek spuštěný na serveru, který se má vyhledat ve výstupu ladicího serveru. Výchozí hodnota je null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Konzolové aplikace se spustí v externím okně terminálu. Okno se znovu použije ve scénářích opětovného spuštění a po ukončení aplikace se automaticky nezavře.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Konzolové aplikace se spustí ve vlastním externím okně konzoly, které se ukončí, až se aplikace zastaví. Aplikace, které konzolové nejsou, se spustí bez terminálu a stdout a stderr se budou ignorovat.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Pokud se nastaví na true, zakáže přesměrování konzoly laděného procesu, které se vyžaduje pro podporu integrovaného terminálu.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Ladicímu modulu se předala volitelná mapování zdrojových souborů. Příklad: `{ \"<původní cesta ke zdroji>\": \"<aktuální cesta ke zdroji>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Nepovinné ID procesu, ke kterému se má ladicí program připojit. Pokud chcete získat seznam místních spuštěných procesů, ke kterým se dá připojit, použijte `${command:pickProcess}`. Poznámka: Některé platformy vyžadují pro připojení k procesu oprávnění správce.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Nepovinná mapování zdrojových souborů předaná ladicímu stroji. Příklad: { \"/original/source/path\":\"/current/source/path\" }.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Nepovinné ID procesu, ke kterému se má ladicí program připojit. Pokud chcete získat seznam místních spuštěných procesů, ke kterým se dá připojit, použijte ${command:pickProcess}. Poznámka: Některé platformy vyžadují pro připojení k procesu oprávnění správce.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Seznam středníkem oddělených adresářů, ve kterých se budou hledat soubory symbolů (tj. soubory pdb). Příklad: c:\\dir1;c:\\dir2",
|
||||
"c_cpp.debuggers.dumpPath.description": "Volitelná úplná cesta k souboru výpisu pro zadaný program. Příklad: c:\\temp\\app.dmp. Výchozí hodnota je null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Když se nastaví na false, proces se spustí se zakázanou haldou ladění. Tato možnost nastaví proměnnou prostředí _NO_DEBUG_HEAP na 1.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Soubory, které se mají zkopírovat Podporuje vzor cesty.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Cílový adresář.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Při hodnotě true kopíruje složky rekurzivně.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Volitelná úplná cesta k SCP. Předpokládá, že SCP je na cestě PATH, pokud není zadané.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Volitelná úplná cesta k rsync. Předpokládá, že rsync je na cestě PATH, pokud není zadané.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Volitelná úplná cesta k SCP. Předpokládá, že SCP je na cestě PATH, pokud není zadané",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Volitelná úplná cesta k rsync Předpokládá, že rsync je v CESTĚ, pokud není zadané.",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Při hodnotě true přeskočte při spuštění bez ladění. Pokud je hodnota false, přeskočte při spuštění ladění. Pokud není definováno, nikdy nepřeskakujte.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Krok příkazu SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Příkaz, který se má provést přes SSH. Příkaz za znakem -c v příkazu SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Volitelná úplná cesta k SSH. Předpokládá, že SSH je na cestě PATH, pokud není zadané.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Volitelná úplná cesta k SSH. Předpokládá, že SSH je na cestě PATH, pokud není zadané",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Nepovinný vzor dokončení při výstupu. Pokud je tento vzor zaznamenán při výstupu, pokračujte v nasazování procedur bez ohledu na to, zda se tento krok vrátí.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Krok příkazu prostředí.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Příkaz prostředí, který se má provést.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Wenn dieser Wert auf TRUE festgelegt ist, werden durch den Befehl verursachte Fehler ignoriert. Der Standardwert ist FALSE.",
|
||||
"c_cpp.debuggers.program.description": "Vollständiger Pfad zur ausführbaren Programmdatei.",
|
||||
"c_cpp.debuggers.args.description": "Befehlszeilenargumente, die an das Programm übergeben werden.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Der Typ der Engine. Muss \"cppdbg\" sein.",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Der Typ der Engine. Muss \"cppvsdbg\" sein.",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Die Architektur der zu debuggenden Komponente. Falls dieser Parameter nicht festgelegt ist, wird die Architektur automatisch erkannt. Zulässige Werte sind \"x86\", \"arm\", \"arm64\", \"mips\", \"x64\", \"amd64\" und \"x86_64\".",
|
||||
"c_cpp.debuggers.cwd.description": "Das Arbeitsverzeichnis des Ziels.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Ein oder mehrere GDB/LLDB-Befehle, die zum Einrichten des zugrunde liegenden Debuggers ausgeführt werden. Beispiel: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Zusätzliche Argumente für den MI-Debugger (z. B. gdb).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Netzwerkadresse des MI-Debugger-Servers, mit dem eine Verbindung hergestellt werden soll (Beispiel: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Stellen Sie eine Verbindung mit dem MI-Debuggerserver mit dem erweiterten Remotemodus des Ziels her.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Optionaler Parameter. Wenn dieser Wert auf `true` festgelegt ist, sollte der Debugger am Einstiegspunkt des Ziels anhalten. Wenn die `processId` übergeben wird, hat dies keine Auswirkungen.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Optionaler Parameter. Wenn dieser Wert auf TRUE festgelegt ist, sollte der Debugger am Einstiegspunkt des Ziels anhalten. Wenn die processId übergeben wird, hat dies keine Auswirkungen.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Optionaler vollständiger Pfad zum Debugserver, der gestartet werden soll. Der Standardwert ist NULL. Dies wird in Verbindung mit \"miDebugServerAddress\" oder Ihrem eigenen Server mit \"customSetupCommand\" verwendet, auf dem \"-target-select remote <server:port>\" ausgeführt wird.",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Optionale Debugserverargumente. Der Standardwert ist \"null\".",
|
||||
"c_cpp.debuggers.serverStarted.description": "Optionales vom Server gestartetes Muster, nach dem in der Ausgabe des Debugservers gesucht wird. Der Standardwert ist \"null\".",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Konsolenanwendungen werden in einem externen Terminalfenster gestartet. Das Fenster wird in Neustartszenarien erneut verwendet und beim Beenden der Anwendung nicht automatisch ausgeblendet.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Konsolenanwendungen werden in ihrem eigenen externen Konsolenfenster gestartet, das beim Beenden der Anwendung ebenfalls beendet wird. Nicht-Konsolenanwendungen werden ohne Terminal ausgeführt, und stdout/stderr wird ignoriert.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Wenn dieser Wert auf TRUE festgelegt ist, wird für die zu debuggende Komponente die Konsolenumleitung deaktiviert, die für die Unterstützung des integrierten Terminals erforderlich ist.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Optionale Quelldateizuordnungen, die an die Debug-Engine übergeben werden. Beispiel: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Optionale Prozess-ID, an die der Debugger angefügt werden soll. Verwenden Sie `${command:pickProcess}`, um eine Liste der lokalen ausgeführten Prozesse abzurufen, an die das Anfügen möglich ist. Beachten Sie, dass für einige Plattformen Administratorrechte erforderlich sind, damit an einen Prozess angefügt werden kann.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Optionale Quelldateizuordnungen, die an die Debug-Engine übergeben werden. Beispiel: `{ \"/original/source/path\":\"/current/source/path\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Optionale Prozess-ID, an die der Debugger angefügt werden soll. Verwenden Sie \"${command:pickProcess}\", um eine Liste der lokalen ausgeführten Prozesse abzurufen, an die angefügt werden kann. Beachten Sie, dass einige Plattformen Administratorrechte erfordern, damit an einen Prozess angefügt werden kann.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Durch Semikolons getrennte Liste von Verzeichnissen, die für die Suche nach Symboldateien (PDB-Dateien) verwendet werden sollen. Beispiel: \"c:\\dir1;c:\\dir2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Optionaler vollständiger Pfad zu einer Dumpdatei für das angegebene Programm. Beispiel: \"c:\\temp\\app.dmp\". Standardwert ist NULL.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Wenn dieser Wert auf FALSE festgelegt ist, wird der Prozess mit deaktiviertem Debug-Heap gestartet. Hiermit wird die Umgebungsvariable \"_NO_DEBUG_HEAP\" auf \"1\" festgelegt.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Dateien, die kopiert werden sollen. Unterstützt Pfadmuster.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Zielverzeichnis.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Bei \"wahr\" werden Ordner rekursiv kopiert.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Optionaler vollständiger Pfad zu SCP. Sofern nicht angegeben, wird davon ausgegangen, dass sich SCP auf PATH befindet.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Optionaler vollständiger Pfad zu rsync. Sofern nicht angegeben, wird davon ausgegangen, dass sich rsync auf PATH befindet.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Optionaler vollständiger Pfad zu SCP. Es wird davon ausgegangen, dass sich SCP auf PATH befindet, wenn keine Angabe erfolgt.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Optionaler vollständiger Pfad zu rsync. Es wird davon ausgegangen, dass sich rsync auf PATH befindet, wenn nicht angegeben",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Wenn WAHR, überspringen Sie beim Starten ohne Debuggen. Wenn FALSCH, überspringen Sie beim Starten von Debuggen. Wenn nicht definiert, überspringen Sie nie.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "SSH-Befehlsschritt.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Befehl, der über SSH ausgeführt werden soll. Der Befehl nach „-c“ im SSH-Befehl.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Optionaler vollständiger Pfad zu SSH. Sofern nicht angegeben, wird davon ausgegangen, dass sich SSH auf PATH befindet.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Optionaler vollständiger Pfad zu SSH. Es wird davon ausgegangen, dass sich SSH auf PATH befindet, sofern nicht angegeben.",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Ein optionales Endmuster in der Ausgabe. Wenn dieses Muster in der Ausgabe angezeigt wird, setzen Sie die Bereitstellungsprozeduren unabhängig davon fort, ob dieser Schritt zurückgegeben wird.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Shellbefehlsschritt.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Shellbefehl, der ausgeführt werden soll.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Si se establece en true, los errores del comando deben omitirse. El valor predeterminado es false.",
|
||||
"c_cpp.debuggers.program.description": "Ruta de acceso completa al ejecutable del programa.",
|
||||
"c_cpp.debuggers.args.description": "Argumentos de la línea de comandos que se pasan al programa.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Tipo de motor. Debe ser \"cppdbg\".",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Tipo de motor. Debe ser \"cppvsdbg\".",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Arquitectura del depurado. Se detectará automáticamente, a menos que se haya establecido este parámetro. Los valores permitidos son x86, arm, arm64, mips, x64, amd64 y x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Directorio de trabajo del destino.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Uno o varios comandos GDB/LLDB que deben ejecutarse para configurar el depurador subyacente. Ejemplo: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Argumentos adicionales para el depurador MI (como gdb).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Dirección de red del servidor del depurador MI al que debe conectarse (ejemplo: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Conéctese al servidor del depurador de Instancia administrada con el modo extendido-remoto de destino.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Parámetro opcional. Si se establece en `true`, el depurador debe detenerse en el punto de entrada del destino. Si se pasa `processId`, esto no tiene efecto.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Parámetro opcional. Si se establece en true, el depurador debe detenerse en el punto de entrada del destino. Si se pasa processId, no tiene efecto.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Ruta de acceso completa opcional al servidor de depuración que se va a iniciar. El valor predeterminado es null. Se usa junto con \"miDebugServerAddress\" o su servidor propio con un comando \"customSetupCommand\" que ejecuta \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Argumentos opcionales del servidor de depuración. El valor predeterminado es NULL.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Patrón opcional iniciado por el servidor que debe buscarse en la salida del servidor de depuración. El valor predeterminado es NULL.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Las aplicaciones de consola se iniciarán en una ventana de terminal de tipo externo. La ventana se volverá a usar en los escenarios de reinicio y no desaparecerá automáticamente cuando se cierre la aplicación.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Las aplicaciones de consola se iniciarán en su propia ventana de consola externa, que terminará cuando la aplicación se detenga. Las aplicaciones que no sean de consola se ejecutarán sin un terminal y se omitirá stdout/stderr.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Si se establece en true, se deshabilita la redirección de la consola del depurado necesaria para la compatibilidad con el terminal integrado.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Asignaciones de archivo de origen opcionales pasadas al motor de depuración. Ejemplo: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Id. de proceso opcional al que debe asociarse el depurador. Use `${command:pickProcess}` para obtener una lista de los procesos locales en ejecución a los que se puede asociar. Tenga en cuenta que algunas plataformas requieren privilegios de administrador para poder asociar el depurador a un proceso.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Asignaciones de archivo de código fuente opcionales que se pasan al motor de depuración. Ejemplo: \"{ \"/original/source/path\":\"/current/source/path\" }\".",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Id. de proceso opcional al que debe asociarse el depurador. Use \"${command:pickProcess}\" para obtener una lista de los procesos locales en ejecución a los que se puede asociar. Tenga en cuenta que algunas plataformas requieren privilegios de administrador para poder asociar el depurador a un proceso.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Lista de directorios separados por punto y coma que debe usarse para buscar archivos de símbolos (es decir, pdb). Ejemplo: \"c:\\dir1;c:\\dir2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Ruta de acceso completa opcional a un archivo de volcado de memoria para el programa especificado. Ejemplo: \"c:\\temp\\app.dmp\". El valor predeterminado es null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Si se establece en false, el proceso se iniciará con el montón de depuración deshabilitado. Esta opción establece la variable de entorno \"_NO_DEBUG_HEAP\" en \"1\".",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Archivos que se van a copiar. Admite el patrón de ruta de acceso.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Directorio de destino.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Si es true, copia las carpetas de forma recursiva.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Ruta de acceso completa opcional al SCP. Asume que SCP está en PATH si no se especifica.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Ruta de acceso completa opcional a rsync. Se supone que rsync está en PATH si no se especifica.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Ruta de acceso completa opcional al SCP. Asume que SCP está en PATH si no se especifica",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Ruta de acceso completa opcional a rsync. Se supone que rsync está en PATH si no se especifica",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Si es true, se omite cuando se inicia sin depuración. Si es false, se omite al iniciar la depuración. Si no está definido, no se omitirá nunca.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Paso del comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Comando que se ejecutará a través de SSH. Comando después de '-c' en el comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Ruta de acceso completa opcional a SSH. Asume que SSH está en PATH si no se especifica.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Ruta de acceso completa opcional a SSH. Asume que SSH está en PATH si no se especifica",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Patrón de finalización opcional en la salida. Cuando se ve este patrón en la salida, continúa con los procedimientos de implementación independientemente de si este paso devuelve resultados.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Paso del comando shell.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Comando de shell que se va a ejecutar.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Si la valeur est true, les échecs de la commande doivent être ignorés. La valeur par défaut est false.",
|
||||
"c_cpp.debuggers.program.description": "Chemin complet du programme exécutable.",
|
||||
"c_cpp.debuggers.args.description": "Arguments de ligne de commande passés au programme.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Type du moteur. Doit être \"cppdbg\".",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Type du moteur. Doit être \"cppvsdbg\".",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Architecture de l'élément débogué. Elle est automatiquement détectée, sauf si ce paramètre est défini. Les valeurs autorisées sont x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Répertoire de travail de la cible.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Une ou plusieurs commandes GDB/LLDB à exécuter pour configurer le débogueur sous-jacent. Exemple : \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Arguments supplémentaires pour le débogueur MI (par exemple gdb).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Adresse réseau du serveur du débogueur MI auquel se connecter (par exemple : localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Connectez-vous au serveur débogueur MI avec le mode étendu-distant cible.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Paramètre facultatif. Si la valeur est `true`, le débogueur doit s'arrêter au point d'entrée de la cible. Si `processId` est passé, cela n'a aucun effet.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Paramètre facultatif. Si la valeur est true, le débogueur doit s'arrêter au point d'entrée de la cible. Si processId est passé, le paramètre n'a aucun effet.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Chemin complet facultatif au serveur de débogage à lancer (valeur par défaut : null). Utilisé conjointement avec \"miDebugServerAddress\" ou votre propre serveur avec \"customSetupCommand\" qui exécute \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Arguments facultatifs du serveur de débogage. La valeur par défaut est null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Modèle facultatif de démarrage du serveur à rechercher dans la sortie du serveur de débogage. La valeur par défaut est null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Les applications console sont lancées dans une fenêtre de terminal externe. La fenêtre est réutilisée dans les scénarios de redémarrage et ne disparaît pas automatiquement à la fermeture de l'application.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Les applications console sont lancées dans leur propre fenêtre de console externe, qui se ferme à l'arrêt de l'application. Les applications non-console s'exécutent sans terminal, et stdout/stderr est ignoré.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Si la valeur est true, désactive la redirection de la console de l'élément débogué nécessaire pour prendre en charge le terminal intégré.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Mappages de fichiers sources facultatifs passés au moteur de débogage. Exemple : `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "ID de processus facultatif auquel attacher le débogueur. Utilisez `${command:pickProcess}` pour obtenir la liste des processus locaux en cours d'exécution à attacher. Notez que certaines plateformes nécessitent des privilèges d'administrateur(-trice) pour attacher un processus.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Mappages de fichiers sources facultatifs passés au moteur de débogage. Exemple : { « /original/source/path »:\"/current/source/path » }.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "ID de processus facultatif auquel attacher le débogueur. Utilisez \"${command:pickProcess}\" pour obtenir la liste des processus locaux en cours d'exécution à attacher. Notez que certaines plateformes nécessitent des privilèges d'administrateur pour attacher un processus.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Liste de répertoires séparés par des points-virgules à utiliser pour rechercher les fichiers de symboles (c'est-à-dire, pdb). Exemple : \"c:\\dir1;c:\\dir2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Chemin complet facultatif d'un fichier d'image mémoire pour le programme spécifié. Exemple : \"c:\\temp\\app.dmp\". La valeur par défaut est null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Si la valeur est false, le processus est lancé avec le tas de débogage désactivé. Cette valeur définit la variable d'environnement '_NO_DEBUG_HEAP' sur '1'.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Fichiers à copier. Prend en charge le modèle de chemin d’accès.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Répertoire cible.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Si la valeur est true, copie les dossiers de manière récursive.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Chemin d’accès complet facultatif vers SCP. Suppose que SCP est sur PATH s’il n’est pas spécifié.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Chemin d’accès complet facultatif vers rsync. Suppose que rsync se trouve dans PATH s’il n’est pas spécifié.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Chemin d’accès complet facultatif au protocole SCP. Suppose que SCP est sur PATH s’il n’est pas spécifié",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Chemin complet facultatif vers rsync. Suppose que rsync se trouve dans PATH s’il n’est pas spécifié.",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Si la valeur est true, ignorez le démarrage sans débogage. Si la valeur est false, ignorez le début du débogage. S’il n’est pas défini, ne l’ignorez jamais.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Étape de commande SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Commande à exécuter via SSH. Commande après « -c » dans la commande SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Chemin d’accès complet facultatif vers SSH. Suppose que SSH est sur PATH s’il n’est pas spécifié.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Chemin complet facultatif vers SSH. Suppose que SSH est sur PATH s’il n’est pas spécifié",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Modèle de fin facultatif dans la sortie. Lorsque ce modèle est affiché dans la sortie, continuez les procédures de déploiement, que cette étape soit retournée ou non.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Étape de commande de l’interpréteur de commandes.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Commande Shell à exécuter.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Se è true, gli errori del comando devono essere ignorati. Il valore predefinito è false.",
|
||||
"c_cpp.debuggers.program.description": "Percorso completo dell'eseguibile del programma.",
|
||||
"c_cpp.debuggers.args.description": "Argomenti della riga di comando passati al programma.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Tipo del motore. Deve essere \"cppdbg\".",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Tipo del motore. Deve essere \"cppvsdbg\".",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Architettura dell'oggetto del debug. Verrà rilevata automaticamente a meno che non sia impostato questo parametro. Valori consentiti: x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Directory di lavoro della destinazione.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Uno o più comandi GDB/LLDB da eseguire per configurare il debugger sottostante. Esempio: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Argomenti aggiuntivi per il debugger MI, ad esempio gdb.",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Indirizzo di rete del server del debugger MI a cui connettersi. Esempio: localhost:1234.",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Connettersi al server del debugger MI con la modalità estesa-remota di destinazione.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Parametro facoltativo. Se è `true`, il debugger deve arrestarsi in corrispondenza del punto di ingresso della destinazione. Se viene passato `processId`, non ha alcun effetto.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Parametro facoltativo. Se è true, il debugger deve arrestarsi in corrispondenza del punto di ingresso della destinazione. Se viene passato ProcessId, non ha alcun effetto.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Percorso completo facoltativo del server di debug da avviare. L'impostazione predefinita è Null. Viene usata insieme a \"miDebugServerAddress\" o al proprio server con un comando \"customSetupCommand\" che esegue \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Argomenti facoltativi del server di debug. L'impostazione predefinita è null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Criterio facoltativo avviato dal server per cercare nell'output del server di debug. L'impostazione predefinita è null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Le applicazioni della console verranno avviate in una finestra del terminale esterna. La finestra verrà riutilizzata in scenari di riavvio e non scomparirà automaticamente alla chiusura dell'applicazione.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Le applicazioni della console verranno avviate nella finestra della console esterna, che verrà terminata alla chiusura dell'applicazione. Le applicazioni non della console vengono eseguite senza un terminale e stdout/stderr verrà ignorato.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Se è true, disabilita il reindirizzamento della console dell'oggetto del debug richiesto per il supporto del terminale integrato.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Mapping di file di origine facoltativi passati al motore di debug. Esempio: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "ID processo facoltativo a cui collegare il debugger. Usare `${command:pickProcess}` per ottenere un elenco dei processi locali in esecuzione a cui collegarsi. Tenere presente che alcune piattaforme richiedono privilegi di amministratore per collegarsi a un processo.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Mapping facoltativi dei file di origine passati al motore di debug. Esempio: '{ '/original/source/path':'/current/source/path' }'.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "ID processo facoltativo a cui collegare il debugger. Usare \"${command:pickProcess}\" per ottenere un elenco dei processi locali in esecuzione a cui collegarsi. Tenere presente che alcune piattaforme richiedono privilegi di amministratore per collegarsi a un processo.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Elenco di directory delimitate da punto e virgola da usare per la ricerca di file di simboli, ovvero PDB. Esempio: \"c:\\dir1;c:\\dir2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Percorso completo facoltativo di un file dump per il programma specificato. Esempio: \"c:\\temp\\app.dmp\". L'impostazione predefinita è Null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Se è false, il processo verrà avviato con l'heap di debug disabilitato. Imposta la variabile di ambiente '_NO_DEBUG_HEAP' su '1'.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "File da copiare. Supporta il modello di percorso.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Directory di destinazione.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Se true, copiare le cartelle in modo ricorsivo.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Percorso completo facoltativo di SCP. Presuppone che SCP sia in PATH se non specificato.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Percorso completo facoltativo di rsync. Presuppone che rsync sia in PATH se non specificato.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Percorso completo facoltativo di SCP. Presuppone che SCP sia in PATH se non specificato",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Percorso completo facoltativo di rsync. Presuppone che rsync sia in PATH se non specificato",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Se true, ignorare l'avvio senza eseguire il debug. Se false, ignorare quando si avvia il debug. Se non definito, non ignorare mai.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Passaggio del comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Comando da eseguire tramite SSH. Comando dopo '-c' nel comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Percorso completo facoltativo di SSH. Presuppone che SSH sia in PATH se non è specificato.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Percorso completo facoltativo di SSH. Presuppone che SSH sia in PATH se non è specificato",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Modello di fine facoltativo nell'output. Quando questo modello viene visualizzato nell'output, continuare le procedure di distribuzione indipendentemente dal fatto che il passaggio venga restituito.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Passaggio del comando della shell.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Comando SQL da eseguire.",
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"unknown.properties.version": "È stato trovato un numero di versione sconosciuto in c_cpp_properties.json. Alcune funzionalità potrebbero non funzionare come previsto.",
|
||||
"update.properties.failed": "Il tentativo di aggiornamento di \"{0}\" non è riuscito. L'accesso in scrittura è disponibile?",
|
||||
"failed.to.parse.properties": "Non è stato possibile analizzare \"{0}\"",
|
||||
"path.with.spaces": "Non è possibile trovare il percorso del compilatore contenente spazi. Se l'intenzione era includere argomenti del compilatore, racchiudi il percorso del compilatore tra doppie virgolette ({0}).",
|
||||
"path.with.spaces": "Non è possibile trovare il percorso del compilatore contenente spazi. Se l'intenzione era includere argomenti del compilatore, racchiudi il percorso del compilatore tra doppie virgolette ({0})",
|
||||
"cannot.find": "Non è possibile trovare: {0}",
|
||||
"path.is.not.a.file": "Il percorso non è un file: {0}",
|
||||
"wrapped.with.quotes": "Non aggiungere virgolette aggiuntive intorno ai percorsi.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "true に設定すると、コマンドの失敗は無視されます。既定値は false です。",
|
||||
"c_cpp.debuggers.program.description": "プログラムの実行可能ファイルへの完全なパス。",
|
||||
"c_cpp.debuggers.args.description": "プログラムに渡すコマンド ライン引数。",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "エンジンの種類。\"cppdbg\" でなければなりません。",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "エンジンの種類。\"cppvsdbg\" でなければなりません。",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "デバッグ対象のアーキテクチャ。このパラメーターを設定しない場合は、自動的に検出されます。可能な値は、x86、arm、arm64、mips、x64、amd64、x86_64 です。",
|
||||
"c_cpp.debuggers.cwd.description": "ターゲットの作業ディレクトリです。",
|
||||
"c_cpp.debuggers.setupCommands.description": "基礎となるデバッガーをセットアップするために実行する 1 つ以上の GDB/LLDB コマンド。例: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }]。",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "MI デバッガー (gdb など) の追加の引数。",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "接続先の MI デバッガー サーバーのネットワークアドレスです (例: localhost: 1234)。",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "ターゲットの拡張リモート モードで MI デバッガー サーバーに接続します。",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "オプションのパラメーターです。`true` の場合、デバッガーはターゲットのエントリポイントで停止します。`processId` が渡された場合、この効果はありません。",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "オプションのパラメーターです。true の場合、デバッガーはターゲットのエントリポイントで停止します。processId が渡された場合は効果はありません。",
|
||||
"c_cpp.debuggers.debugServerPath.description": "起動するデバッグ サーバーの完全なパス (省略可能)。既定値は null です。これは、\"miDebugServerAddress\"、または \"-target-select remote <server:port>\" を実行する \"customSetupCommand\" を含む独自のサーバーのいずれかと接合して使用されます。",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "デバッグ サーバー引数 (省略可能)。既定値は null です。",
|
||||
"c_cpp.debuggers.serverStarted.description": "デバッグ サーバー出力から検索する、サーバー開始のパターン (省略可能)。既定値は null です。",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "コンソール アプリケーションは、外部ターミナル ウィンドウで起動されます。このウィンドウは再起動のシナリオで再利用され、アプリケーションが終了しても自動的に消えません。",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "コンソール アプリケーションは、アプリケーションの停止時に終了する独自の外部コンソール ウィンドウで起動されます。コンソール以外のアプリケーションはターミナルなしで実行され、stdout および stderr は無視されます。",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "true の場合、統合ターミナルのサポートに必要なデバッグ対象のコンソール リダイレクトが無効になります。",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "デバッグ エンジンに渡されるオプションのソース ファイル マッピング。例: `{ \"<original source path>\": \"<current source path>\" }`。",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "デバッガーをアタッチするためのオプションのプロセス ID。ローカルで実行される、アタッチ先プロセスのリストを取得するには、`${command:pickProcess}` を使用します。一部のプラットフォームでは、プロセスにアタッチするために管理者特権が必要となることに注意してください。",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "デバッグ エンジンに渡されたソース ファイル マッピングです (オプション)。例: '{ \"/original/source/path\":\"/current/source/path\" }'。",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "デバッガーをアタッチするためのオプションのプロセス ID です。\"${command:pickProcess}\" を使用すれば、アタッチ先のローカルで実行されているプロセスの一覧を取得できます。一部のプラットフォームでは、プロセスにアタッチするには管理者特権が必要です。",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "シンボル (つまり、pdb) ファイルの検索に使用する、セミコロンで区切られたディレクトリの一覧です。例: \"c:\\dir1;c:\\dir2\"。",
|
||||
"c_cpp.debuggers.dumpPath.description": "指定したプログラムのダンプ ファイルへの完全なパスです (オプション)。例: \"c:\\temp\\app.dmp\"。既定値は null です。",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "false の場合、プロセスはデバッグ ヒープを無効にして起動します。これにより、環境変数 '_NO_DEBUG_HEAP' は '1' に設定されます。",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "コピーするファイル。パス パターンがサポートされています。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "ターゲット ディレクトリ。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "true の場合、フォルダーを再帰的にコピーします。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP への完全パス (省略可能)。指定されていない場合、SCP は PATH 上にあると想定されます。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync への完全パス (省略可能)。指定されていない場合、rsync は PATH 上にあると想定されます。",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP への完全パス (省略可能)。指定されていない場合、SCP は PATH 上にあると想定します",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync への完全パス (省略可能)。指定されていない場合、rsync は PATH 上にあると想定します",
|
||||
"c_cpp.debuggers.deploySteps.debug": "true の場合は、デバッグなしで開始するときにスキップします。false の場合は、デバッグを開始するときにスキップします。未定義の場合は、スキップしません。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "SSH コマンド ステップ。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "SSH 経由で実行するコマンド。SSH コマンドの '-c' の後のコマンド。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH への完全パス (省略可能)。指定されていない場合、SSH は PATH 上にあると想定されます。",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH への完全パス (省略可能)。指定されていない場合、SSH は PATH 上にあると想定されます",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "出力の省略可能な終了パターン。このパターンが出力に表示されたら、このステップが戻るかどうかに関係なく、デプロイ プロシージャを続行します。",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "シェル コマンド ステップ。",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "実行するシェル コマンド。",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "True이면 명령 실패가 무시됩니다. 기본값은 false입니다.",
|
||||
"c_cpp.debuggers.program.description": "프로그램 실행 파일의 전체 경로입니다.",
|
||||
"c_cpp.debuggers.args.description": "프로그램에 전달된 명령줄 인수입니다.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "엔진 유형입니다. \"cppdbg\"여야 합니다.",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "엔진 유형입니다. \"cppvsdbg\"여야 합니다.",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "디버기의 아키텍처입니다. 이 매개 변수를 설정하지 않는 경우 자동으로 검색됩니다. 허용되는 값은 x86, arm, arm64, mips, x64, amd64, x86_64입니다.",
|
||||
"c_cpp.debuggers.cwd.description": "대상의 작업 디렉터리입니다.",
|
||||
"c_cpp.debuggers.setupCommands.description": "기본 디버거를 설정하기 위해 실행할 하나 이상의 GDB/LLDB 명령입니다. 예: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "MI 디버거(예: gdb)의 추가 인수입니다.",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "연결할 MI 디버거 서버의 네트워크 주소입니다(예: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "대상 확장 원격 모드를 사용하여 MI 디버거 서버에 연결합니다.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "선택적 매개 변수입니다. `true`이면 디버거가 대상의 진입점에서 중지됩니다. `processId`가 전달되는 경우 영향을 주지 않습니다.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "선택적 매개 변수입니다. True이면 디버거가 대상의 진입점에서 중지됩니다. processId가 전달되는 경우 영향을 주지 않습니다.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "시작할 디버그 서버의 전체 경로입니다(선택 사항). 기본값은 null입니다. 이 옵션은 \"miDebugServerAddress\"와 함께 사용되거나 \"-target-select remote <server:port>\"를 실행하는 \"customSetupCommand\"와 자체 서버와 함께 사용됩니다.",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "선택적 디버그 서버 인수입니다. 기본값은 null입니다.",
|
||||
"c_cpp.debuggers.serverStarted.description": "디버그 서버 출력에서 찾을 서버에서 시작한 패턴(선택 사항)입니다. 기본값은 null입니다.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "콘솔 애플리케이션이 외부 터미널 창에서 시작됩니다. 이 창은 다시 시작 시나리오에서 재사용되며, 애플리케이션이 종료될 때 자동으로 사라지지 않습니다.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "콘솔 애플리케이션은 애플리케이션이 중지될 때 종료되는 해당 외부 콘솔 창에서 시작됩니다. 콘솔이 아닌 애플리케이션은 터미널 없이 실행되며, stdout/stderr이 무시됩니다.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "True이면 통합 터미널 지원에 필요한 디버기 콘솔 리디렉션을 사용하지 않도록 설정합니다.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "디버그 엔진에 전달되는 선택적 소스 파일 매핑입니다. 예: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "디버거를 연결할 선택적 프로세스 ID입니다. `${command:pickProcess}`를 사용하여 연결할 로컬 실행 프로세스 목록을 가져옵니다. 일부 플랫폼에서는 프로세스에 연결하기 위해 관리자 권한이 필요합니다.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "디버그 엔진에 전달되는 선택적 소스 파일 매핑입니다(예: '{\"/original/source/path\": \"/original/source/path\"}').",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "디버거를 연결할 선택적 프로세스 ID입니다. \"${command:pickProcess}\"를 사용하여 연결할 로컬 실행 프로세스 목록을 가져옵니다. 일부 플랫폼에서는 프로세스에 연결하기 위해 관리자 권한이 필요합니다.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "기호(pdb) 파일 검색에 사용할 디렉터리의 세미콜론으로 구분된 목록입니다(예: \"c:\\dir1;c:\\dir2\").",
|
||||
"c_cpp.debuggers.dumpPath.description": "지정된 프로그램에 대한 코어 덤프 파일의 선택적 전체 경로입니다(예: \"c:\\temp\\app.dmp\"). 기본값은 null입니다.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "False이면 디버그 힙이 사용하지 않도록 설정된 상태로 프로세스가 시작됩니다. 이렇게 하면 환경 변수 '_NO_DEBUG_HEAP'이 '1'로 설정됩니다.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Jeśli wartość to true, niepowodzenia polecenia powinny być ignorowane. Wartość domyślna to false.",
|
||||
"c_cpp.debuggers.program.description": "Pełna ścieżka do pliku wykonywalnego programu.",
|
||||
"c_cpp.debuggers.args.description": "Argumenty wiersza polecenia przekazywane do programu.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Typ aparatu. Musi mieć wartość „cppdbg”.",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Typ aparatu. Musi mieć wartość „cppvsdbg”.",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Architektura obiektu debugowanego. Zostanie automatycznie wykryta, chyba że ten parametr jest ustawiony. Dozwolone wartości to x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Katalog roboczy obiektu docelowego.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Co najmniej jedno polecenie GDB/LLDB do wykonania w celu skonfigurowania bazowego debugera. Przykład: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Dodatkowe argumenty dla debugera MI (takiego jak gdb).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Adres sieciowy serwera debugera MI, z którym ma zostać nawiązane połączenie (przykład: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Połącz się z wystąpieniem zarządzanym serwera debugera za pomocą docelowego rozszerzonego trybu zdalnego.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Parametr opcjonalny. Jeśli wartość to `true`, debuger powinien zostać zatrzymany w punkcie wejścia miejsca docelowego. W przypadku przekazania `processId` nie ma to żadnego efektu.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Parametr opcjonalny. Jeśli wartość to true, debuger powinien zostać zatrzymany w punkcie wejścia obiektu docelowego. W przypadku przekazania identyfikatora procesu parametr ten nie ma żadnego efektu.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Opcjonalna pełna ścieżka do serwera debugowania, który ma zostać uruchomiony. Wartość domyślna to null. Jest ona używana w połączeniu z właściwością \"miDebugServerAddress\" lub Twoim własnym serwerem wraz z poleceniem \"customSetupCommand\", które uruchamia polecenie \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Opcjonalne argumenty serwera debugowania. Wartość domyślna to null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Opcjonalny wzorzec uruchomiony przez serwer do wyszukania w danych wyjściowych serwera debugowania. Wartością domyślną jest null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Aplikacje konsolowe będą uruchamiane w zewnętrznym oknie terminalu. To okno będzie ponownie użyte w scenariuszach wznowionego uruchamiania i nie będzie automatycznie znikać po zamknięciu aplikacji.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Aplikacje konsolowe będą uruchamiane we własnym oknie konsoli, które zostanie zamknięte po zatrzymaniu aplikacji. Aplikacje inne niż konsolowe będą uruchamiane bez terminalu, a dane stdout/stderr będą ignorowane.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Jeśli wartość to true, wyłącza przekierowywanie konsoli debugowanego obiektu, które jest wymagane do obsługi zintegrowanego terminalu.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Opcjonalne mapowania plików źródłowych przekazane do silnika debugowania. Przykład: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Opcjonalny identyfikator procesu, do którego ma zostać dołączony debuger. Użyj polecenia `${command:pickProcess}`, aby uzyskać listę uruchomionych lokalnie procesów, do których można dołączyć. Pamiętaj, że niektóre platformy wymagają uprawnień administratora, aby dołączyć je do procesu.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Opcjonalne mapowania plików źródłowych przekazywane do aparatu debugowania. Przykład: '{ \"/original/source/path\":\"/current/source/path\" }'.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Opcjonalny identyfikator procesu, do którego ma zostać dołączony debuger. Użyj polecenia „${command:pickProcess}”, aby uzyskać listę uruchomionych lokalnie procesów, do których można dołączyć. Pamiętaj, że niektóre platformy wymagają uprawnień administratora, aby dołączyć je do procesu.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Rozdzielana średnikami lista katalogów, w których mają być wyszukiwanie pliki symboli (PDB). Przykład: „c:\\dir1;c:\\dir2”.",
|
||||
"c_cpp.debuggers.dumpPath.description": "Opcjonalna pełna ścieżka do pliku zrzutu dla określonego programu. Przykład: „c:\\temp\\app.dmp”. Wartość domyślna to null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "W przypadku wartości false proces zostanie uruchomiony z wyłączoną stertą debugowania. Spowoduje to ustawienie zmiennej środowiskowej „_NO_DEBUG_HEAP” na wartość „1”.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Pliki do skopiowania. Obsługuje wzorzec ścieżki.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Katalog docelowy.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "W przypadku wartości True, kopiuje foldery rekursywnie.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Opcjonalna pełna ścieżka do protokołu SCP. Przyjęto założenie, że protokół SCP znajduje się w PATH, jeśli nie zostanie określony.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Opcjonalna pełna ścieżka do rsync. Przyjęto założenie, że rsync znajduje się w PATH, jeśli nie zostało to określone.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Opcjonalna pełna ścieżka do protokołu SCP. Przyjęto założenie, że protokół SCP znajduje się w PATH, jeśli nie zostanie określony",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Opcjonalna pełna ścieżka do rsync. Przyjęto założenie, że rsync znajduje się w PATH, jeśli nie zostało to określone",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Jeśli ma wartość true, pomiń podczas uruchamiania bez debugowania. Jeśli ma wartość false, pomiń podczas uruchamiania debugowania. Jeśli niezdefiniowane, nigdy nie pomijaj.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Krok polecenia SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Polecenie do wykonania za pomocą protokołu SSH. Polecenie po „-c” w poleceniu SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Opcjonalna pełna ścieżka do protokołu SSH. Przyjęto założenie, że protokół SSH znajduje się w PATH, jeśli nie zostanie określony.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Opcjonalna pełna ścieżka do protokołu SSH. Przyjęto założenie, że protokół SSH znajduje się w PATH, jeśli nie zostanie określony",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Opcjonalny wzorzec zakończenia w danych wyjściowych. Gdy ten wzorzec jest widoczny w danych wyjściowych, kontynuuj procedury wdrażania niezależnie od tego, czy ten krok zostanie zwrócony.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Krok polecenia powłoki.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Polecenie powłoki do wykonania.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Se for true, as falhas do comando deverão ser ignoradas. O valor padrão é false.",
|
||||
"c_cpp.debuggers.program.description": "Caminho completo para o executável do programa.",
|
||||
"c_cpp.debuggers.args.description": "Argumentos de linha de comando passados para o programa.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "O tipo do mecanismo. Precisa ser \"cppdbg\".",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "O tipo do mecanismo. Precisa ser \"cppvsdbg\".",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "A arquitetura do depurador. Ela será detectada automaticamente a menos que este parâmetro seja definido. Os valores permitidos são x86, arm, arm64, mips, x64, amd64 e x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "O diretório de trabalho do destino.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Um ou mais comandos GDB/LLDB para executar para configurar o depurador subjacente. Por exemplo: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Argumentos adicionais para o depurador MI (como o gdb).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Endereço de rede do Servidor de Depurador MI ao qual se conectar (exemplo: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Conecte-se ao MI Debugger Server com o modo remoto estendido de destino.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Parâmetro opcional. Se for `true`, o depurador deverá parar no ponto de entrada do destino. Se `processId` for passado, isso não terá efeito.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Parâmetro opcional. Se for true, o depurador deverá parar no ponto de entrada do destino. Se processId for passado, não terá efeito.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Caminho completo opcional para o servidor de depuração a ser lançado. O padrão é nulo. É usado em conjunto com \"miDebugServerAddress\" ou seu próprio servidor com um \"customSetupCommand\" que executa \"-target-select remote <server:port>\".",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Args opcionais do servidor de depuração. O padrão é null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Padrão iniciado pelo servidor opcional para procurar na saída do servidor de depuração. O padrão é null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Aplicativos de console serão lançadas em uma janela de terminal externo. A janela será reutilizada em cenários de relançamento e não desaparecerá automaticamente quando o aplicativo sair.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Os aplicativos de console serão iniciados em suas próprias janelas de console externas, que serão encerradas quando o aplicativo for interrompido. Os aplicativos que não são de console serão executados sem um terminal e as opções stdout/stderr serão ignoradas.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Se for true, desabilitará o redirecionamento do console do depurador requerido para o suporte do Terminal Integrado.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Mapeamentos opcionais de arquivo de origem passados para o mecanismo de depuração. Exemplo: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "ID do processo opcional ao qual anexar o depurador. Use `${command:pickProcess}` para obter uma lista de processos locais em execução aos quais anexar. Observe que algumas plataformas exigem privilégios de administrador para anexação a um processo.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Mapeamentos de arquivo de origem opcionais passados para o mecanismo de depuração. Exemplo: '{\"/original/source/path\":\"/current/source/path\"}'.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "ID do processo opcional ao qual anexar o depurador. Use \"${command:pickProcess}\" para obter uma lista de processos locais em execução aos quais anexar. Observe que algumas plataformas exigem privilégios de administrador para anexação a um processo.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Lista separada por ponto e vírgula de diretórios a serem usados para pesquisar arquivos de símbolo (ou seja, pdb). Exemplo: \"c:\\dir1;c:\\dir2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Caminho completo opcional para um arquivo de despejo para o programa especificado. Exemplo: \"c:\\temp\\app.dmp\". Usa nulo como padrão.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Se for false, o processo será iniciado com o heap de depuração desabilitado. Isso define a variável de ambiente '_NO_DEBUG_HEAP' como '1'.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Arquivos a serem copiados. Dá suporte ao padrão de caminho.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Diretório de destino.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Se for verdadeiro, copia pastas recursivamente.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Caminho completo opcional para SCP. Assume que o SCP está no PATH se não for especificado.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Caminho completo opcional para o rsync. Assume que o rsync está no PATH se não for especificado.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Caminho completo opcional para SCP. Supõe que o SCP está em PATH se não for especificado",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Caminho completo opcional para rsync. Pressupõe que rsync esteja em PATH se não for especificado",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Se for verdadeiro, ignore ao iniciar sem depuração. Se for falso, ignore ao iniciar a depuração. Se indefinido, nunca ignore.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Etapa de comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Comando a ser executado via SSH. O comando após “-c” no comando SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Caminho completo opcional para SSH. Pressupõe que o SSH está no PATH se não especificado.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Caminho completo opcional para SSH. Supõe que SSH está em PATH se não for especificado",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Um padrão de término opcional na saída. Quando esse padrão for visto na saída, continue os procedimentos de implantação, independentemente de esta etapa ser retornada.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Etapa de comando do shell.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Comando shell a ser executado.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Если задано значение true, сбои этой команды должны игнорироваться. Значение по умолчанию — false.",
|
||||
"c_cpp.debuggers.program.description": "Полный путь к исполняемому файлу программы.",
|
||||
"c_cpp.debuggers.args.description": "Аргументы командной строки, переданные в программу.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Тип подсистемы. Должно быть \"cppdbg\".",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Тип подсистемы. Должно быть \"cppvsdbg\".",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Архитектура отлаживаемого объекта. Будет определяться автоматически, если этот параметр не задан. Допустимые значения: x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Рабочий каталог целевой программы.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Одна или несколько команд GDB/LLDB, выполняемых для настройки базового отладчика. Пример: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "Дополнительные аргументы для отладчика MI (например, GDB).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Сетевой адрес сервера отладчика MI, к которому требуется подключиться (пример: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Подключение к серверу отладчика MI в целевом расширенном удаленном режиме.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "Необязательный параметр. Если задано значение `true`, отладчик должен остановиться в точке входа целевого объекта.. Если передается идентификатор процесса `processId`, этот параметр не действует.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "Необязательный параметр. Если задано значение true, отладчик должен остановиться на точке входа целевого объекта. Если передается идентификатор процесса (processId), он не оказывает никакого влияния.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Необязательный полный путь к запускаемому серверу отладки. Значение по умолчанию — NULL. Применяется с параметром miDebugServerAddress или с вашим собственным сервером через команду customSetupCommand, использующую -target-select remote <server:port>.",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "Необязательные аргументы сервера отладки. Значение по умолчанию: null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Дополнительный запускаемый сервером шаблон для поиска в выходных данных сервера отладки. Значение по умолчанию: null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Консольные приложения будут запускаться во внешнем окне терминала. Окно будет использовано снова при повторном запуске и не будет закрываться автоматически при выходе из приложения.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Консольные приложения будут запускаться в собственном внешнем окне консоли, которое будет закрываться при остановке приложения. Приложения, не являющиеся консольными, будут запускаться без терминала, и stdout/stderr будет игнорироваться.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Если задано значение true, отключается перенаправление консоли отлаживаемого объекта, необходимое для поддержки встроенного терминала.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Необязательные сопоставления исходных файлов, передаваемые подсистеме отладки. Пример: `{ \"<первоначальный путь к источнику>\": \"<текущий путь к источнику>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Необязательный идентификатор процесса, к которому требуется подключить отладчик. Используйте `${command:pickProcess}`, чтобы получить список локальных запущенных процессов для подключения. Обратите внимание, что для подключения к процессам на некоторых платформах требуются права администратора.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Необязательные сопоставления исходного файла, переданные в подсистему отладки. Пример: \"{ \"/original/source/path\":\"/current/source/path\" }\".",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Необязательный идентификатор процесса, к которому требуется подключить отладчик. Используйте \"${command:pickProcess}\", чтобы получить список локальных запущенных процессов для подключения. Обратите внимание, что для подключения к процессу на некоторых платформах требуются права администратора.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Список каталогов, разделенных точкой с запятой, который следует использовать для поиска файлов символов (таких как PDB). Пример: \"c:\\каталог_1;c:\\каталог_2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Необязательный полный путь к основному файлу дампа для указанной программы. Пример: \"c:\\temp\\app.dmp\". Значение по умолчанию: null.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Если задано значение false, процесс будет запущен с отключенной кучей отладки. При этом для переменной среды \"_NO_DEBUG_HEAP\" устанавливается значение \"1\".",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Файлы для копирования. Поддерживается шаблон пути.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Целевой каталог",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "Если установлено значение \"true\", папки копируются рекурсивно.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Необязательный полный путь к SCP. Предполагается, что SCP находится в PATH, если не указано иного.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Необязательный полный путь к rsync. Предполагается, что rsync находится в PATH, если не указано иного.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "Необязательный полный путь к SCP. Предположим, что SCP находится в PATH, если не указано",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "Необязательный полный путь к rsync. Предполагается, что rsync находится в PATH, если полный путь не указан.",
|
||||
"c_cpp.debuggers.deploySteps.debug": "Если ИСТИНА, пропустить при запуске без отладки. Если ЛОЖЬ, пропустить при запуске отладки. Если не определено, никогда не пропускать.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "Шаг команды SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "Команда для выполнения через SSH. Команда после '-c' в команде SSH.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Необязательный полный путь к SSH. Предполагается, что SSH находится в PATH, если не указано иного.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Необязательный полный путь к SSH. Предположим, что SSH находится в PATH, если не указано иного.",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Необязательный шаблон отделки на выходе. Когда этот шаблон виден в выходных данных, продолжайте процедуры развертывания независимо от того, вернется ли этот шаг.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Шаг команды оболочки.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Команда оболочки для выполнения.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
"c_cpp.debuggers.ignoreFailures.description": "Değer true ise komuttan gönderilen hatalar yoksayılmalıdır. Varsayılan olarak false değerini alır.",
|
||||
"c_cpp.debuggers.program.description": "Program yürütülebilirinin tam yolu.",
|
||||
"c_cpp.debuggers.args.description": "Programa geçirilen komut satırı bağımsız değişkenleri.",
|
||||
"c_cpp.debuggers.cppdbg.type.description": "Altyapının türü. \"cppdbg\" olmalıdır.",
|
||||
"c_cpp.debuggers.cppvsdbg.type.description": "Altyapının türü. \"cppvsdbg\" olmalıdır.",
|
||||
"c_cpp.debuggers.targetArchitecture.description": "Hata ayıklananın mimarisi. Bu parametre ayarlanmazsa, bu değer otomatik olarak algılanır. İzin verilen değerler: x86, arm, arm64, mips, x64, amd64, x86_64.",
|
||||
"c_cpp.debuggers.cwd.description": "Hedefin çalışma dizini.",
|
||||
"c_cpp.debuggers.setupCommands.description": "Temel alınan hata ayıklayıcısını ayarlamak için çalıştırılacak bir veya daha fazla GDB/LLDB komutu. Örnek: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
|
||||
@@ -309,7 +311,7 @@
|
||||
"c_cpp.debuggers.miDebuggerArgs.description": "MI hata ayıklayıcısı için ek bağımsız değişkenler (gdb gibi).",
|
||||
"c_cpp.debuggers.miDebuggerServerAddress.description": "Bağlanılacak MI Hata Ayıklayıcısı Sunucusunun ağ adresi (örnek: localhost:1234).",
|
||||
"c_cpp.debuggers.useExtendedRemote.description": "Hedef genişletilmiş uzak modundayken MI Hata Ayıklayıcısı Sunucusuna bağlanın.",
|
||||
"c_cpp.debuggers.stopAtEntry.markdownDescription": "İsteğe bağlı parametre. Değeri `true` ise, hata ayıklayıcısının hedefin giriş noktasında durması gerekir. `processId` geçirilirse bunun hiçbir etkisi olmaz.",
|
||||
"c_cpp.debuggers.stopAtEntry.description": "İsteğe bağlı parametre. Değeri true ise, hata ayıklayıcısının hedefin giriş noktasında durması gerekir. processId geçirilirse hiçbir etkisi olmaz.",
|
||||
"c_cpp.debuggers.debugServerPath.description": "Başlatılacak sunucuda hata ayıklama için isteğe bağlı tam yol. Varsayılan değeri null. \"miDebugServerAddress\" veya kendi sunucunuzun \"-target-select remote <server:port>\" çalıştıran bir \"customSetupCommand\" ile birlikte kullanılır.",
|
||||
"c_cpp.debuggers.debugServerArgs.description": "İsteğe bağlı hata ayıklama sunucusu bağımsız değişkenleri. Varsayılan olarak şu değeri alır: null.",
|
||||
"c_cpp.debuggers.serverStarted.description": "Hata ayıklama sunucusu çıktısında aranacak, sunucu tarafından başlatılan isteğe bağlı model. Varsayılan olarak şu değeri alır: null.",
|
||||
@@ -325,8 +327,8 @@
|
||||
"c_cpp.debuggers.cppvsdbg.console.externalTerminal.description": "Konsol uygulamaları, dış terminal penceresinde başlatılır. Pencere, yeniden başlatma senaryolarında tekrar kullanılır ve uygulama çıkış yaptığında otomatik olarak kaybolmaz.",
|
||||
"c_cpp.debuggers.cppvsdbg.console.newExternalWindow.description": "Konsol uygulamaları, uygulama durduğunda sona erecek olan kendi dış konsol penceresinde başlatılır. Konsol dışı uygulamalar terminal olmadan çalıştırılır ve stdout/stderr yoksayılır.",
|
||||
"c_cpp.debuggers.avoidWindowsConsoleRedirection.description": "Değer true ise, Tümleşik Terminal desteği için gerekli olan hata ayıklanan işlem konsol yeniden yönlendirmesini devre dışı bırakır.",
|
||||
"c_cpp.debuggers.sourceFileMap.markdownDescription": "Hata ayıklama altyapısına geçirilen isteğe bağlı kaynak dosya eşlemeleri. Örnek: `{ \"<original source path>\": \"<current source path>\" }`.",
|
||||
"c_cpp.debuggers.processId.anyOf.markdownDescription": "Hata ayıklayıcının ekleneceği isteğe bağlı işlem kimliği. Eklenilecek yerel çalışan işlemlerin bir listesini almak için `${command:pickProcess}` kullanın. Bazı platformların bir işleme ekleme yapmak için yönetici ayrıcalıkları gerektirdiğini unutmayın.",
|
||||
"c_cpp.debuggers.sourceFileMap.description": "Hata ayıklama altyapısına isteğe bağlı kaynak dosya eşlemeleri geçirildi. Örnek: '{ \"/özgün/kaynak/yolu\":\"/geçerli/kaynak/yolu\" }'.",
|
||||
"c_cpp.debuggers.processId.anyOf.description": "Hata ayıklayıcının ekleneceği isteğe bağlı işlem kimliği. Eklenilecek yerel çalışan işlemlerin bir listesini almak için \"${command:pickProcess}\" kullanın. Bazı platformların bir işleme ekleme yapmak için yönetici ayrıcalıkları gerektirdiğini unutmayın.",
|
||||
"c_cpp.debuggers.symbolSearchPath.description": "Sembol (yani pdb) dosyalarını aramak için kullanılacak, noktalı virgülle ayrılmış dizinlerin listesi. Örnek: \"c:\\dizin1;c:\\dizin2\".",
|
||||
"c_cpp.debuggers.dumpPath.description": "Belirtilen program için döküm dosyasının isteğe bağlı tam yolu. Örnek: \"c:\\temp\\app.dmp\". Varsayılan olarak null değerini alır.",
|
||||
"c_cpp.debuggers.enableDebugHeap.description": "Değer false ise, işlem hata ayıklama yığını devre dışı bırakılarak başlatılır. Bu işlem '_NO_DEBUG_HEAP' ortam değişkenini '1' olarak ayarlar.",
|
||||
@@ -357,12 +359,12 @@
|
||||
"c_cpp.debuggers.deploySteps.copyFile.files.description": "Kopyalanacak dosyalar. Yol desenini destekler.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.targetDir.description": "Hedef dizin.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.recursive.description": "True ise, klasörleri özyinelemeli olarak kopyalar.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP için isteğe bağlı tam yol. Belirtilmezse SCP'nin PATH üzerinde olduğunu varsayar.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync için isteğe bağlı tam yol. Belirtilmezse rsync'nin PATH üzerinde olduğunu varsayar.",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.scpPath.description": "SCP için isteğe bağlı tam yol. Belirtilmezse SCP'nin PATH üzerinde olduğunu varsayar",
|
||||
"c_cpp.debuggers.deploySteps.copyFile.rsyncPath.description": "rsync için isteğe bağlı tam yol. Belirtilmezse rsync'nin PATH üzerinde olduğunu varsayar",
|
||||
"c_cpp.debuggers.deploySteps.debug": "True ise, hata ayıklama olmadan başlatılırken atla. False ise hata ayıklamayı başlatırken atla. Tanımlanmamışsa hiçbir zaman atlama.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.description": "SSH komutu adımı.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.command.description": "SSH aracılığıyla yürütülecek komut. SSH komutunda '-c' işaretinden sonraki komut.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH için isteğe bağlı tam yol. Belirtilmezse SSH'nin PATH üzerinde olduğunu varsayar.",
|
||||
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "SSH için isteğe bağlı tam yol. Belirtilmezse SSH'nin PATH üzerinde olduğunu varsayar",
|
||||
"c_cpp.debuggers.deploySteps.continueOn.description": "Çıkışta isteğe bağlı bir bitiş deseni. Çıkışta bu desen görüldüğünde, bu adımın döndürülüp döndürülmediğinden bağımsız olarak dağıtım yordamlarına devam et.",
|
||||
"c_cpp.debuggers.deploySteps.shell.description": "Kabuk komut adımı.",
|
||||
"c_cpp.debuggers.deploySteps.shell.command.description": "Yürütülecek kabuk komutu.",
|
||||
|
||||
+1412
-24
File diff suppressed because it is too large
Load Diff
@@ -979,6 +979,69 @@
|
||||
"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.debuggers.cpplldb.debuggerPath.description": {
|
||||
"message": "Full path to the LLDB-DAP debugger executable. If not specified, the extension will search for the debugger in the system PATH.",
|
||||
"comment": [
|
||||
"{Locked=\"LLDB-DAP\"} {Locked=\"PATH\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.debuggerArgs.description": {
|
||||
"message": "Additional arguments for the LLDB-DAP debugger.",
|
||||
"comment": [
|
||||
"{Locked=\"LLDB-DAP\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.externalConsole.description": "If true, launch the external console for the debugger.",
|
||||
"c_cpp.debuggers.cpplldb.disableAslr.description": "Disable Address Space Layout Randomization (if supported).",
|
||||
"c_cpp.debuggers.cpplldb.disableStdio.description": "Disables the standard input/output streams during debugging.",
|
||||
"c_cpp.debuggers.cpplldb.expandShellArguments.description": "Expands program arguments as a shell would (does not actually launch the program in a shell).",
|
||||
"c_cpp.debuggers.cpplldb.detachOnError.description": "Detach the debugger when an error occurs.",
|
||||
"c_cpp.debuggers.cpplldb.debuggerRoot.description": "The directory where relative object files can be located.",
|
||||
"c_cpp.debuggers.cpplldb.targetTriple.description": "Overrides the target triple of the target program.",
|
||||
"c_cpp.debuggers.cpplldb.platformName.description": "Overrides the platform name of the target program.",
|
||||
"c_cpp.debuggers.cpplldb.initCommands.description": "LLDB commands executed upon debugger startup prior to creating the LLDB target.",
|
||||
"c_cpp.debuggers.cpplldb.preRunCommands.description": "LLDB commands executed just before launching/attaching, after the LLDB target has been created.",
|
||||
"c_cpp.debuggers.cpplldb.postRunCommands.description": "LLDB commands executed after launching when it's in a stopped state prior to any automatic continuation.",
|
||||
"c_cpp.debuggers.cpplldb.launchCommands.description": "Custom LLDB commands that are executed instead of launching a process.",
|
||||
"c_cpp.debuggers.cpplldb.stopCommands.description": "LLDB commands executed each time the program stops.",
|
||||
"c_cpp.debuggers.cpplldb.exitCommands.description": "LLDB commands executed when the program exits.",
|
||||
"c_cpp.debuggers.cpplldb.terminateCommands.description": "LLDB commands executed when the debugging session ends.",
|
||||
"c_cpp.debuggers.cpplldb.enableAutoVariableSummaries.description": "Enable auto-generated summaries for variables when no summaries exist for a given type. This feature can cause performance delays in large projects when viewing variables.",
|
||||
"c_cpp.debuggers.cpplldb.displayExtendedBacktrace.description": "Enable language-specific extended backtraces.",
|
||||
"c_cpp.debuggers.cpplldb.enableSyntheticChildDebugging.description": "If a variable is displayed using synthetic children, also display the actual contents of the variable at the end under an entry. This is useful when creating synthetic child plug-ins as it lets you see the actual contents of the variable.",
|
||||
"c_cpp.debuggers.cpplldb.commandEscapePrefix.description": "The escape prefix character to use for executing regular LLDB commands in the Debug Console, instead of printing variables.",
|
||||
"c_cpp.debuggers.cpplldb.customFrameFormat.markdownDescription": {
|
||||
"message": "When specified, stack frames will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html.",
|
||||
"comment": [
|
||||
"{Locked=\"https://lldb.llvm.org/use/formatting.html\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.customThreadFormat.markdownDescription": {
|
||||
"message": "When specified, threads will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html.",
|
||||
"comment": [
|
||||
"{Locked=\"https://lldb.llvm.org/use/formatting.html\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.attachCommands.description": "Custom LLDB commands that are executed instead of attaching to a process ID or to a process by name.",
|
||||
"c_cpp.debuggers.cpplldb.waitFor.markdownDescription": {
|
||||
"message": "Wait for the process to launch by looking for a process with a basename that matches the value specified in `program`.",
|
||||
"comment": [
|
||||
"{Locked=\"`program`\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.coreFile.description": "Path to the core file to debug.",
|
||||
"c_cpp.debuggers.cpplldb.gdbRemotePort.markdownDescription": {
|
||||
"message": "TCP/IP port to attach to a remote system. Specifying both `processId` and `port` is an error.",
|
||||
"comment": [
|
||||
"{Locked=\"`processId`\"} {Locked=\"`port`\"}"
|
||||
]
|
||||
},
|
||||
"c_cpp.debuggers.cpplldb.gdbRemoteHost.markdownDescription": {
|
||||
"message": "The hostname to connect to a remote system. The default hostname is `localhost`.",
|
||||
"comment": [
|
||||
"{Locked=\"`localhost`\"}"
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
|
||||
@@ -28,6 +28,10 @@ class RefreshButton implements vscode.QuickInputButton {
|
||||
|
||||
export interface AttachItem extends vscode.QuickPickItem {
|
||||
id?: string;
|
||||
name?: string;
|
||||
pid?: string;
|
||||
commandLine?: string;
|
||||
fullPath?: string;
|
||||
}
|
||||
|
||||
// We should not await on this function.
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as util from '../common';
|
||||
import { executableName, ProcessReturnType, spawnChildProcess } from '../common-remote-safe';
|
||||
import * as debugUtils from './utils';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
@@ -21,6 +22,28 @@ export interface AttachItemsProvider {
|
||||
getAttachItems(token?: vscode.CancellationToken): Promise<AttachItem[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a process matches the specified filter criteria.
|
||||
*
|
||||
* This function checks if the given process name or its full path matches
|
||||
* the provided filter string. It also normalizes the filter string to handle
|
||||
* relative paths and compares the executable name derived from the filter
|
||||
* with the executable name of the process.
|
||||
*
|
||||
* @param filterTo - The filter string to match against. This can be a process name,
|
||||
* an executable name, or a file path.
|
||||
* @param processName - The name of the process to check.
|
||||
* @param fullPath - The full path of the process executable, if available.
|
||||
* @returns `true` if the process matches the filter criteria; otherwise, `false`.
|
||||
*/
|
||||
export function processMatches(filterTo: string, processName: string, fullPath: string | undefined) {
|
||||
const normalized = path.resolve(filterTo);
|
||||
const executable = executableName(filterTo);
|
||||
|
||||
// Filter out the processes that do not somehow match.
|
||||
return processName === filterTo || executableName(processName) === executable || fullPath === filterTo || fullPath === normalized;
|
||||
}
|
||||
|
||||
export class AttachPicker {
|
||||
constructor(private attachItemsProvider: AttachItemsProvider) { }
|
||||
|
||||
@@ -28,6 +51,23 @@ export class AttachPicker {
|
||||
public async ShowAttachEntries(token?: vscode.CancellationToken): Promise<string | undefined> {
|
||||
return showQuickPick(() => this.attachItemsProvider.getAttachItems(token));
|
||||
}
|
||||
|
||||
/** Shows the Attach QuickPick, but if a valid filterTo process name/path is passed in, it only shows those entries. */
|
||||
public async ShowAttachEntriesFiltered(filterTo?: string, token?: vscode.CancellationToken): Promise<string | undefined> {
|
||||
return showQuickPick(async () => {
|
||||
|
||||
const items = await this.attachItemsProvider.getAttachItems(token);
|
||||
if (filterTo) {
|
||||
// Filter out the processes that do not somehow match.
|
||||
const filtered = items.filter(each => processMatches(filterTo, each.label, each.fullPath));
|
||||
if (filtered.length > 0) {
|
||||
// Only filter the list if we have actual matches.
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
return items;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoteAttachPicker {
|
||||
@@ -177,18 +217,17 @@ export class RemoteAttachPicker {
|
||||
return 0;
|
||||
}
|
||||
return aLower < bLower ? -1 : 1;
|
||||
})
|
||||
.map(p => p.toAttachItem());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getRemoteProcessesExtendedRemote(miDebuggerPath: string, miDebuggerServerAddress: string): Promise<AttachItem[]> {
|
||||
const args: string[] = [`-ex "target extended-remote ${miDebuggerServerAddress}"`, '-ex "info os processes"', '-batch'];
|
||||
let processListOutput: util.ProcessReturnType = await util.spawnChildProcess(miDebuggerPath, args);
|
||||
let processListOutput: ProcessReturnType = await spawnChildProcess(miDebuggerPath, args);
|
||||
// The device may not be responsive for a while during the restart after image deploy. Retry 5 times.
|
||||
for (let i: number = 0; i < 5 && !processListOutput.succeeded && processListOutput.outputError.length === 0; i++) {
|
||||
processListOutput = await util.spawnChildProcess(miDebuggerPath, args);
|
||||
processListOutput = await spawnChildProcess(miDebuggerPath, args);
|
||||
}
|
||||
|
||||
if (!processListOutput.succeeded) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { promisify } from 'util';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as util from '../common';
|
||||
import { executableName, ProcessReturnType, spawnChildProcess } from '../common-remote-safe';
|
||||
import { isWindows } from '../constants';
|
||||
import { expandAllStrings, ExpansionOptions, ExpansionVars } from '../expand';
|
||||
import { CppBuildTask, CppBuildTaskDefinition, cppBuildTaskProvider } from '../LanguageServer/cppBuildTaskProvider';
|
||||
@@ -21,8 +22,9 @@ import * as logger from '../logger';
|
||||
import { PlatformInformation } from '../platform';
|
||||
import { rsync, scp, ssh } from '../SSH/commands';
|
||||
import * as Telemetry from '../telemetry';
|
||||
import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess';
|
||||
import { ConfigMenu, ConfigMode, ConfigSource, CppDebugConfiguration, DebuggerEvent, DebuggerType, DebugType, IConfiguration, IConfigurationSnippet, isDebugLaunchStr, MIConfigurations, PipeTransportConfigurations, TaskStatus, WindowsConfigurations, WSLConfigurations } from './configurations';
|
||||
import { AttachItemsProvider, AttachPicker, processMatches, RemoteAttachPicker } from './attachToProcess';
|
||||
import { ConfigMenu, ConfigMode, ConfigSource, Configuration, CppDebugConfiguration, DebuggerEvent, DebuggerType, DebugType, IConfigurationSnippet, isDebugLaunchStr, LldbDapConfigurations, MIConfigurations, PipeTransportConfigurations, TaskStatus, WindowsConfigurations, WSLConfigurations } from './configurations';
|
||||
import { findLldbDap, translateToLldbDap } from './lldb-dap';
|
||||
import { NativeAttachItemsProviderFactory } from './nativeAttach';
|
||||
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
|
||||
import * as debugUtils from './utils';
|
||||
@@ -48,17 +50,13 @@ const globAsync: (pattern: string, options?: glob.IOptions | undefined) => Promi
|
||||
*/
|
||||
export class DebugConfigurationProvider implements vscode.DebugConfigurationProvider {
|
||||
|
||||
private type: DebuggerType;
|
||||
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) {
|
||||
this.assetProvider = assetProvider;
|
||||
this.type = type;
|
||||
public constructor(private assetProvider: ConfigurationAssetProvider, private type: DebuggerType) {
|
||||
}
|
||||
|
||||
public static ClearDetectedBuildTasks(): void {
|
||||
@@ -236,7 +234,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
if (config.type === DebuggerType.cppvsdbg) {
|
||||
// Fail if cppvsdbg type is running on non-Windows
|
||||
if (os.platform() !== 'win32') {
|
||||
void logger.getOutputChannelLogger().showWarningMessage(localize("debugger.not.available", "Debugger of type: '{0}' is only available on Windows. Use type: '{1}' on the current OS platform.", "cppvsdbg", "cppdbg"));
|
||||
void logger.getOutputChannelLogger().showWarningMessage(localize("debugger.not.available", "Debugger of type: '{0}' is only available on Windows. Use type: '{1}' or '{2}' on the current OS platform.", DebuggerType.cppvsdbg, DebuggerType.cppdbg, DebuggerType.cpplldb));
|
||||
return undefined; // Abort debugging silently.
|
||||
}
|
||||
|
||||
@@ -269,55 +267,57 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
|
||||
this.resolveSourceFileMapVariables(config);
|
||||
|
||||
// Modify WSL config for OpenDebugAD7
|
||||
if (os.platform() === 'win32' &&
|
||||
config.pipeTransport &&
|
||||
config.pipeTransport.pipeProgram) {
|
||||
let replacedPipeProgram: string | undefined;
|
||||
const pipeProgramStr: string = config.pipeTransport.pipeProgram.toLowerCase().trim();
|
||||
if (config.type === DebuggerType.cppdbg) {
|
||||
// Modify WSL config for OpenDebugAD7
|
||||
if (os.platform() === 'win32' &&
|
||||
config.pipeTransport &&
|
||||
config.pipeTransport.pipeProgram) {
|
||||
let replacedPipeProgram: string | undefined;
|
||||
const pipeProgramStr: string = config.pipeTransport.pipeProgram.toLowerCase().trim();
|
||||
|
||||
// OpenDebugAD7 is a 32-bit process. Make sure the WSL pipe transport is using the correct program.
|
||||
replacedPipeProgram = debugUtils.ArchitectureReplacer.checkAndReplaceWSLPipeProgram(pipeProgramStr, debugUtils.ArchType.ia32);
|
||||
// OpenDebugAD7 is a 32-bit process. Make sure the WSL pipe transport is using the correct program.
|
||||
replacedPipeProgram = debugUtils.ArchitectureReplacer.checkAndReplaceWSLPipeProgram(pipeProgramStr, debugUtils.ArchType.ia32);
|
||||
|
||||
// If pipeProgram does not get replaced and there is a pipeCwd, concatenate with pipeProgramStr and attempt to replace.
|
||||
if (!replacedPipeProgram && !path.isAbsolute(pipeProgramStr) && config.pipeTransport.pipeCwd) {
|
||||
const pipeCwdStr: string = config.pipeTransport.pipeCwd.toLowerCase().trim();
|
||||
const newPipeProgramStr: string = path.join(pipeCwdStr, pipeProgramStr);
|
||||
// If pipeProgram does not get replaced and there is a pipeCwd, concatenate with pipeProgramStr and attempt to replace.
|
||||
if (!replacedPipeProgram && !path.isAbsolute(pipeProgramStr) && config.pipeTransport.pipeCwd) {
|
||||
const pipeCwdStr: string = config.pipeTransport.pipeCwd.toLowerCase().trim();
|
||||
const newPipeProgramStr: string = path.join(pipeCwdStr, pipeProgramStr);
|
||||
|
||||
replacedPipeProgram = debugUtils.ArchitectureReplacer.checkAndReplaceWSLPipeProgram(newPipeProgramStr, debugUtils.ArchType.ia32);
|
||||
replacedPipeProgram = debugUtils.ArchitectureReplacer.checkAndReplaceWSLPipeProgram(newPipeProgramStr, debugUtils.ArchType.ia32);
|
||||
}
|
||||
|
||||
if (replacedPipeProgram) {
|
||||
config.pipeTransport.pipeProgram = replacedPipeProgram;
|
||||
}
|
||||
}
|
||||
|
||||
if (replacedPipeProgram) {
|
||||
config.pipeTransport.pipeProgram = replacedPipeProgram;
|
||||
}
|
||||
}
|
||||
const macOSMIMode: string = config.osx?.MIMode ?? config.MIMode;
|
||||
const macOSMIDebuggerPath: string = config.osx?.miDebuggerPath ?? config.miDebuggerPath;
|
||||
|
||||
const macOSMIMode: string = config.osx?.MIMode ?? config.MIMode;
|
||||
const macOSMIDebuggerPath: string = config.osx?.miDebuggerPath ?? config.miDebuggerPath;
|
||||
const lldb_mi_10_x_path: string = path.join(util.extensionPath, "debugAdapters", "lldb-mi", "bin", "lldb-mi");
|
||||
|
||||
const lldb_mi_10_x_path: string = path.join(util.extensionPath, "debugAdapters", "lldb-mi", "bin", "lldb-mi");
|
||||
// Validate LLDB-MI
|
||||
if (os.platform() === 'darwin' && // Check for macOS
|
||||
fs.existsSync(lldb_mi_10_x_path) && // lldb-mi 10.x exists
|
||||
(!macOSMIMode || macOSMIMode === 'lldb') &&
|
||||
!macOSMIDebuggerPath // User did not provide custom lldb-mi
|
||||
) {
|
||||
const frameworkPath: string | undefined = this.getLLDBFrameworkPath();
|
||||
|
||||
// Validate LLDB-MI
|
||||
if (os.platform() === 'darwin' && // Check for macOS
|
||||
fs.existsSync(lldb_mi_10_x_path) && // lldb-mi 10.x exists
|
||||
(!macOSMIMode || macOSMIMode === 'lldb') &&
|
||||
!macOSMIDebuggerPath // User did not provide custom lldb-mi
|
||||
) {
|
||||
const frameworkPath: string | undefined = this.getLLDBFrameworkPath();
|
||||
if (!frameworkPath) {
|
||||
const moreInfoButton: string = localize("lldb.framework.install.xcode", "More Info");
|
||||
const LLDBFrameworkMissingMessage: string = localize("lldb.framework.not.found", "Unable to locate 'LLDB.framework' for lldb-mi. Please install XCode or XCode Command Line Tools.");
|
||||
|
||||
if (!frameworkPath) {
|
||||
const moreInfoButton: string = localize("lldb.framework.install.xcode", "More Info");
|
||||
const LLDBFrameworkMissingMessage: string = localize("lldb.framework.not.found", "Unable to locate 'LLDB.framework' for lldb-mi. Please install XCode or XCode Command Line Tools.");
|
||||
void vscode.window.showErrorMessage(LLDBFrameworkMissingMessage, moreInfoButton)
|
||||
.then(value => {
|
||||
if (value === moreInfoButton) {
|
||||
const helpURL: string = "https://aka.ms/vscode-cpptools/LLDBFrameworkNotFound";
|
||||
void vscode.env.openExternal(vscode.Uri.parse(helpURL));
|
||||
}
|
||||
});
|
||||
|
||||
void vscode.window.showErrorMessage(LLDBFrameworkMissingMessage, moreInfoButton)
|
||||
.then(value => {
|
||||
if (value === moreInfoButton) {
|
||||
const helpURL: string = "https://aka.ms/vscode-cpptools/LLDBFrameworkNotFound";
|
||||
void vscode.env.openExternal(vscode.Uri.parse(helpURL));
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,18 +355,69 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
processId = await remoteAttachPicker.ShowAttachEntries(config);
|
||||
} else {
|
||||
const attachItemsProvider: AttachItemsProvider = NativeAttachItemsProviderFactory.Get();
|
||||
const attacher: AttachPicker = new AttachPicker(attachItemsProvider);
|
||||
processId = await attacher.ShowAttachEntries(token);
|
||||
|
||||
// LLDB-DAP supports attaching to process by pid or by name.
|
||||
// If they do specify 'program', then we can check to see if there
|
||||
// is a process that matches, or they are using 'waitFor' (on Linux/macOS).
|
||||
if (config.program) {
|
||||
// If they specified 'program', get the tasks that match that.
|
||||
const items = (await attachItemsProvider.getAttachItems(token)).filter(each => processMatches(config.program, each.label, each.fullPath));
|
||||
|
||||
switch (items.length) {
|
||||
case 0:
|
||||
// No matching processes
|
||||
if (config.type === DebuggerType.cpplldb && config.waitFor) {
|
||||
if (isWindows) {
|
||||
// On Windows, waitFor on lldb-dap is not supported - so we'll let the user know.
|
||||
void logger.getOutputChannelLogger().showWarningMessage(localize("waitFor.not.supported", "The {0} debugger does not support '{1}' on Windows.", "LLDB-DAP", "waitFor"));
|
||||
|
||||
// Drop the waitFor and program (which will just have the picker show all processes).
|
||||
delete config.program;
|
||||
delete config.waitFor;
|
||||
}
|
||||
|
||||
// They did specify 'waitFor' so then let's get out fast and let lldb-dap handle it.
|
||||
logger.note(localize("waiting.for.process", "Waiting to attach process '{0}'", config.program));
|
||||
translateToLldbDap(config);
|
||||
Telemetry.logDebuggerEvent(config.request, { "debuggerType": config.type });
|
||||
return config;
|
||||
}
|
||||
|
||||
// Just let the picker show all processes.
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// If there is only a single process that matches, auto-select it.
|
||||
processId = config.processId = items[0].id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If they didn't specify a processId, we'll show the picker.
|
||||
if (!processId) {
|
||||
// Show the picker to let the user select a process, but if they did specify a program, we'll narrow the list for them.
|
||||
const attacher: AttachPicker = new AttachPicker(attachItemsProvider);
|
||||
processId = await attacher.ShowAttachEntriesFiltered(config.program, token);
|
||||
}
|
||||
}
|
||||
|
||||
if (processId) {
|
||||
config.processId = processId;
|
||||
delete config.program;
|
||||
} else {
|
||||
void logger.getOutputChannelLogger().showErrorMessage("No process was selected.");
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish translating the config for lldb-dap.
|
||||
if (config.type === DebuggerType.cpplldb) {
|
||||
translateToLldbDap(config);
|
||||
Telemetry.logDebuggerEvent(config.request, { "debuggerType": config.type });
|
||||
return config;
|
||||
}
|
||||
|
||||
Telemetry.logDebuggerEvent(config.request, { "debuggerType": config.type, mimode: config.MIMode });
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -394,7 +445,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
if (!command) {
|
||||
return false;
|
||||
}
|
||||
if (defaultTemplateConfig.name.startsWith("(Windows) ")) {
|
||||
if (defaultTemplateConfig?.name.startsWith("(Windows) ")) {
|
||||
if (command.startsWith("cl.exe")) {
|
||||
return true;
|
||||
}
|
||||
@@ -427,13 +478,17 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
const newConfig: CppDebugConfiguration = { ...defaultTemplateConfig }; // Copy enumerables and properties
|
||||
newConfig.existing = false;
|
||||
|
||||
newConfig.name = configPrefix + compilerName + " " + this.buildAndDebugActiveFileStr();
|
||||
newConfig.name = `${configPrefix}${compilerName} [Debugger: ${newConfig.type}] ${this.buildAndDebugActiveFileStr()}`;
|
||||
newConfig.preLaunchTask = task.name;
|
||||
if (newConfig.type === DebuggerType.cppdbg) {
|
||||
newConfig.externalConsole = false;
|
||||
} else {
|
||||
newConfig.console = "integratedTerminal";
|
||||
switch (newConfig.type) {
|
||||
case DebuggerType.cppdbg:
|
||||
newConfig.externalConsole = false;
|
||||
break;
|
||||
case DebuggerType.cppvsdbg:
|
||||
newConfig.console = "integratedTerminal";
|
||||
break;
|
||||
}
|
||||
|
||||
// Extract the .exe path from the defined task.
|
||||
const definedExePath: string | undefined = util.findExePathInArgs(task.definition.args);
|
||||
newConfig.program = definedExePath ? definedExePath : util.defaultExePath();
|
||||
@@ -473,28 +528,27 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
newConfig.type = DebuggerType.cppvsdbg;
|
||||
return newConfig;
|
||||
} else {
|
||||
debuggerName = "gdb";
|
||||
}
|
||||
if (isWindows) {
|
||||
debuggerName = debuggerName.endsWith(".exe") ? debuggerName : (debuggerName + ".exe");
|
||||
debuggerName = executableName("gdb");
|
||||
}
|
||||
const compilerDirname: string = path.dirname(compilerPath);
|
||||
const debuggerPath: string = path.join(compilerDirname, debuggerName);
|
||||
|
||||
// Check if debuggerPath exists.
|
||||
if (await util.checkFileExists(debuggerPath)) {
|
||||
newConfig.miDebuggerPath = debuggerPath;
|
||||
} else if (await util.whichAsync(debuggerName) !== undefined) {
|
||||
// Check if debuggerName exists on $PATH
|
||||
newConfig.miDebuggerPath = debuggerName;
|
||||
} else {
|
||||
// Try the usr path for non-Windows platforms.
|
||||
const usrDebuggerPath: string = path.join("/usr", "bin", debuggerName);
|
||||
if (!isWindows && await util.checkFileExists(usrDebuggerPath)) {
|
||||
newConfig.miDebuggerPath = usrDebuggerPath;
|
||||
if (newConfig.type === DebuggerType.cppdbg) {
|
||||
// Check if debuggerPath exists.
|
||||
if (await util.checkFileExists(debuggerPath)) {
|
||||
newConfig.miDebuggerPath = debuggerPath;
|
||||
} else if (await util.whichAsync(debuggerName) !== undefined) {
|
||||
// Check if debuggerName exists on $PATH
|
||||
newConfig.miDebuggerPath = debuggerName;
|
||||
} else {
|
||||
logger.getOutputChannelLogger().appendLine(localize('debugger.path.not.exists', "Unable to find the {0} debugger. The debug configuration for {1} is ignored.", `\"${debuggerName}\"`, compilerName));
|
||||
return undefined;
|
||||
// Try the usr path for non-Windows platforms.
|
||||
const usrDebuggerPath: string = path.join("/usr", "bin", debuggerName);
|
||||
if (!isWindows && await util.checkFileExists(usrDebuggerPath)) {
|
||||
newConfig.miDebuggerPath = usrDebuggerPath;
|
||||
} else {
|
||||
logger.getOutputChannelLogger().appendLine(localize('debugger.path.not.exists', "Unable to find the {0} debugger. The debug configuration for {1} is ignored.", `\"${debuggerName}\"`, compilerName));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -890,11 +944,12 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
await cppBuildTaskProvider.writeBuildTask(selectedConfig.preLaunchTask);
|
||||
}
|
||||
// Remove the extra properties that are not a part of the DebugConfiguration, as these properties will be written in launch.json.
|
||||
selectedConfig.detail = undefined;
|
||||
selectedConfig.taskStatus = undefined;
|
||||
selectedConfig.isDefault = undefined;
|
||||
selectedConfig.source = undefined;
|
||||
selectedConfig.debuggerEvent = undefined;
|
||||
// Use 'delete' instead of 'undefined' to remove the property from the object (undefined properties still exist!).
|
||||
delete selectedConfig.detail;
|
||||
delete selectedConfig.taskStatus;
|
||||
delete selectedConfig.isDefault;
|
||||
delete selectedConfig.source;
|
||||
delete selectedConfig.debuggerEvent;
|
||||
// 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" });
|
||||
@@ -934,10 +989,19 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
}
|
||||
|
||||
// Get debug configurations for all debugger types.
|
||||
let configs: CppDebugConfiguration[] = await this.provideDebugConfigurationsForType(DebuggerType.cppdbg, folder);
|
||||
if (os.platform() === 'win32') {
|
||||
configs = configs.concat(await this.provideDebugConfigurationsForType(DebuggerType.cppvsdbg, folder));
|
||||
let configs: CppDebugConfiguration[] = [];
|
||||
if (isWindows) {
|
||||
// When on Windows - prefer cppvsdbg.
|
||||
configs.push(...await this.provideDebugConfigurationsForType(DebuggerType.cppvsdbg, folder));
|
||||
}
|
||||
|
||||
if (!isWindows && await findLldbDap()) {
|
||||
// Only include lldb-dap tasks if it's not Windows and lldb-dap is actually available.
|
||||
configs.push(...await this.provideDebugConfigurationsForType(DebuggerType.cpplldb, folder));
|
||||
}
|
||||
|
||||
configs.push(...await this.provideDebugConfigurationsForType(DebuggerType.cppdbg, folder));
|
||||
|
||||
if (onlyWorkspaceFolder) {
|
||||
configs = configs.filter(item => !item.configSource || item.configSource === ConfigSource.workspaceFolder);
|
||||
}
|
||||
@@ -1065,7 +1129,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
return false;
|
||||
}
|
||||
|
||||
let scpResult: util.ProcessReturnType;
|
||||
let scpResult: ProcessReturnType;
|
||||
if (isScp) {
|
||||
scpResult = await scp(files, host, step.targetDir, config.scpPath, config.recursive, jumpHosts, cancellationToken);
|
||||
} else {
|
||||
@@ -1086,7 +1150,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
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);
|
||||
const sshResult: ProcessReturnType = await ssh(host, step.command, config.sshPath, jumpHosts, localForwards, continueOn, cancellationToken);
|
||||
if (!sshResult.succeeded || cancellationToken?.isCancellationRequested) {
|
||||
return false;
|
||||
}
|
||||
@@ -1097,7 +1161,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
void 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);
|
||||
const taskResult: ProcessReturnType = await spawnChildProcess(step.command, undefined, step.continueOn);
|
||||
if (!taskResult.succeeded || cancellationToken?.isCancellationRequested) {
|
||||
void logger.getOutputChannelLogger().showErrorMessage(taskResult.output);
|
||||
return false;
|
||||
@@ -1113,13 +1177,26 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
|
||||
}
|
||||
}
|
||||
|
||||
export interface IConfigurationAssetProvider {
|
||||
getInitialConfigurations(debuggerType: DebuggerType): any;
|
||||
getConfigurationSnippets(): vscode.CompletionItem[];
|
||||
}
|
||||
export class ConfigurationAssetProvider {
|
||||
configurations: Configuration[] = [];
|
||||
|
||||
export class ConfigurationAssetProviderFactory {
|
||||
public static getConfigurationProvider(): IConfigurationAssetProvider {
|
||||
protected constructor() {
|
||||
}
|
||||
|
||||
public getInitialConfigurations(debuggerType: DebuggerType): any[] {
|
||||
return this.configurations.map(configuration => configuration.GetLaunchConfiguration())
|
||||
.filter(snippet => snippet.debuggerType === debuggerType && snippet.isInitialConfiguration)
|
||||
.map(snippet => snippet.body);
|
||||
}
|
||||
|
||||
public getConfigurationSnippets(): vscode.CompletionItem[] {
|
||||
return this.configurations.map(configuration => [
|
||||
convertConfigurationSnippetToCompletionItem(configuration.GetLaunchConfiguration()),
|
||||
convertConfigurationSnippetToCompletionItem(configuration.GetAttachConfiguration())]
|
||||
).flat();
|
||||
}
|
||||
|
||||
static getConfigurationAssetProvider(): ConfigurationAssetProvider {
|
||||
switch (os.platform()) {
|
||||
case 'win32':
|
||||
return new WindowsConfigurationProvider();
|
||||
@@ -1128,104 +1205,79 @@ export class ConfigurationAssetProviderFactory {
|
||||
case 'linux':
|
||||
return new LinuxConfigurationProvider();
|
||||
default:
|
||||
throw new Error(localize("unexpected.os", "Unexpected OS type"));
|
||||
return new ConfigurationAssetProvider(); // At least this will return empty results if the platform is not recognized.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DefaultConfigurationProvider implements IConfigurationAssetProvider {
|
||||
configurations: IConfiguration[] = [];
|
||||
|
||||
public getInitialConfigurations(debuggerType: DebuggerType): any {
|
||||
const configurationSnippet: IConfigurationSnippet[] = [];
|
||||
|
||||
// Only launch configurations are initial configurations
|
||||
this.configurations.forEach(configuration => {
|
||||
configurationSnippet.push(configuration.GetLaunchConfiguration());
|
||||
});
|
||||
|
||||
const initialConfigurations: any = configurationSnippet.filter(snippet => snippet.debuggerType === debuggerType && snippet.isInitialConfiguration)
|
||||
.map(snippet => JSON.parse(snippet.bodyText));
|
||||
|
||||
// If configurations is empty, then it will only have an empty configurations array in launch.json. Users can still add snippets.
|
||||
return initialConfigurations;
|
||||
}
|
||||
|
||||
public getConfigurationSnippets(): vscode.CompletionItem[] {
|
||||
const completionItems: vscode.CompletionItem[] = [];
|
||||
|
||||
this.configurations.forEach(configuration => {
|
||||
completionItems.push(convertConfigurationSnippetToCompletionItem(configuration.GetLaunchConfiguration()));
|
||||
completionItems.push(convertConfigurationSnippetToCompletionItem(configuration.GetAttachConfiguration()));
|
||||
});
|
||||
|
||||
return completionItems;
|
||||
}
|
||||
}
|
||||
|
||||
class WindowsConfigurationProvider extends DefaultConfigurationProvider {
|
||||
class WindowsConfigurationProvider extends ConfigurationAssetProvider {
|
||||
private executable: string = "a.exe";
|
||||
private pipeProgram: string = "<" + localize("path.to.pipe.program", "full path to pipe program such as {0}", "plink.exe").replace(/"/g, '') + ">";
|
||||
private MIMode: string = 'gdb';
|
||||
private setupCommandsBlock: string = `"setupCommands": [
|
||||
{
|
||||
"description": "${localize("enable.pretty.printing", "Enable pretty-printing for {0}", "gdb").replace(/"/g, '')}",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "${localize("enable.intel.disassembly.flavor", "Set Disassembly Flavor to {0}", "Intel").replace(/"/g, '')}",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]`;
|
||||
|
||||
private additionalProperties = {
|
||||
setupCommands: [
|
||||
{
|
||||
description: localize("enable.pretty.printing", "Enable pretty-printing for {0}", "gdb").replace(/"/g, ''),
|
||||
text: "-enable-pretty-printing",
|
||||
ignoreFailures: true
|
||||
},
|
||||
{
|
||||
description: localize("enable.intel.disassembly.flavor", "Set Disassembly Flavor to {0}", "Intel").replace(/"/g, ''),
|
||||
text: "-gdb-set disassembly-flavor intel",
|
||||
ignoreFailures: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.configurations = [
|
||||
new MIConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock),
|
||||
new PipeTransportConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock),
|
||||
new WindowsConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock),
|
||||
new WSLConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock)
|
||||
new WindowsConfigurations(this.executable, this.additionalProperties),
|
||||
new MIConfigurations('gdb', this.executable, this.additionalProperties),
|
||||
new PipeTransportConfigurations('gdb', this.executable, this.pipeProgram, this.additionalProperties),
|
||||
new WSLConfigurations('gdb', this.executable, this.additionalProperties),
|
||||
new LldbDapConfigurations(this.executable)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class OSXConfigurationProvider extends DefaultConfigurationProvider {
|
||||
private MIMode: string = 'lldb';
|
||||
class OSXConfigurationProvider extends ConfigurationAssetProvider {
|
||||
|
||||
private executable: string = "a.out";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.configurations = [
|
||||
new LldbDapConfigurations(this.executable),
|
||||
new MIConfigurations('lldb', this.executable)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class LinuxConfigurationProvider extends ConfigurationAssetProvider {
|
||||
private additionalProperties = {
|
||||
setupCommands: [
|
||||
{
|
||||
description: localize("enable.pretty.printing", "Enable pretty-printing for {0}", "gdb").replace(/"/g, ''),
|
||||
text: "-enable-pretty-printing",
|
||||
ignoreFailures: true
|
||||
},
|
||||
{
|
||||
description: localize("enable.intel.disassembly.flavor", "Set Disassembly Flavor to {0}", "Intel").replace(/"/g, ''),
|
||||
text: "-gdb-set disassembly-flavor intel",
|
||||
ignoreFailures: true
|
||||
}
|
||||
]
|
||||
};
|
||||
private executable: string = "a.out";
|
||||
private pipeProgram: string = "/usr/bin/ssh";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.configurations = [
|
||||
new MIConfigurations(this.MIMode, this.executable, this.pipeProgram)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class LinuxConfigurationProvider extends DefaultConfigurationProvider {
|
||||
private MIMode: string = 'gdb';
|
||||
private setupCommandsBlock: string = `"setupCommands": [
|
||||
{
|
||||
"description": "${localize("enable.pretty.printing", "Enable pretty-printing for {0}", "gdb").replace(/"/g, '')}",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "${localize("enable.intel.disassembly.flavor", "Set Disassembly Flavor to {0}", "Intel").replace(/"/g, '')}",
|
||||
"text": "-gdb-set disassembly-flavor intel",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]`;
|
||||
private executable: string = "a.out";
|
||||
private pipeProgram: string = "/usr/bin/ssh";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.configurations = [
|
||||
new MIConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock),
|
||||
new PipeTransportConfigurations(this.MIMode, this.executable, this.pipeProgram, this.setupCommandsBlock)
|
||||
new MIConfigurations('gdb', this.executable, this.additionalProperties),
|
||||
new PipeTransportConfigurations('gdb', this.executable, this.pipeProgram, this.additionalProperties),
|
||||
new LldbDapConfigurations(this.executable)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1233,17 +1285,15 @@ class LinuxConfigurationProvider extends DefaultConfigurationProvider {
|
||||
function convertConfigurationSnippetToCompletionItem(snippet: IConfigurationSnippet): vscode.CompletionItem {
|
||||
const item: vscode.CompletionItem = new vscode.CompletionItem(snippet.label, vscode.CompletionItemKind.Module);
|
||||
|
||||
item.insertText = snippet.bodyText;
|
||||
item.insertText = JSON.stringify(snippet.body, null, '\t');
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
export class ConfigurationSnippetProvider implements vscode.CompletionItemProvider {
|
||||
private provider: IConfigurationAssetProvider;
|
||||
private snippets: vscode.CompletionItem[];
|
||||
|
||||
constructor(provider: IConfigurationAssetProvider) {
|
||||
this.provider = provider;
|
||||
constructor(private provider: ConfigurationAssetProvider) {
|
||||
this.snippets = this.provider.getConfigurationSnippets();
|
||||
}
|
||||
public resolveCompletionItem(item: vscode.CompletionItem, _token: vscode.CancellationToken): Thenable<vscode.CompletionItem> {
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as os from 'os';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { configPrefix } from '../LanguageServer/extension';
|
||||
import { isWindows } from '../constants';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
|
||||
export function isDebugLaunchStr(str: string): boolean {
|
||||
return str.startsWith("(gdb) ") || str.startsWith("(lldb) ") || str.startsWith("(Windows) ");
|
||||
return str.startsWith("(gdb) ") || str.startsWith("(lldb") || str.startsWith("(Windows) ");
|
||||
}
|
||||
|
||||
export interface ConfigMenu extends vscode.QuickPickItem {
|
||||
@@ -22,6 +22,7 @@ export interface ConfigMenu extends vscode.QuickPickItem {
|
||||
export enum DebuggerType {
|
||||
cppvsdbg = "cppvsdbg",
|
||||
cppdbg = "cppdbg",
|
||||
cpplldb = "cpplldb",
|
||||
all = "all"
|
||||
}
|
||||
|
||||
@@ -70,147 +71,121 @@ export interface CppDebugConfiguration extends vscode.DebugConfiguration {
|
||||
export interface IConfigurationSnippet {
|
||||
label: string;
|
||||
description: string;
|
||||
bodyText: string;
|
||||
body: Record<string, any>;
|
||||
|
||||
// Internal
|
||||
isInitialConfiguration?: boolean;
|
||||
debuggerType: DebuggerType;
|
||||
}
|
||||
|
||||
export function indentJsonString(json: string, numTabs: number = 1): string {
|
||||
return json.split('\n').map(line => '\t'.repeat(numTabs) + line).join('\n').trim();
|
||||
function createLaunchBlock(name: string, type: string, executable: string): Record<string, any> {
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
request: "launch",
|
||||
program: localize("enter.program.name", "enter program name, for example {0}", "${workspaceFolder}" + "/" + executable).replace(/"/g, ''),
|
||||
args: [],
|
||||
stopAtEntry: false,
|
||||
cwd: "${fileDirname}",
|
||||
environment: [],
|
||||
externalConsole: type === DebuggerType.cppdbg ? false : type === DebuggerType.cpplldb ? true : undefined,
|
||||
console: type === DebuggerType.cppvsdbg ? "externalTerminal" : undefined
|
||||
};
|
||||
}
|
||||
|
||||
function formatString(format: string, args: string[]): string {
|
||||
args.forEach((arg: string, index: number) => {
|
||||
format = format.replace("{" + index + "}", arg);
|
||||
});
|
||||
return format;
|
||||
function createAttachBlock(name: string, type: string, executable: string): Record<string, any> {
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
request: "attach",
|
||||
program: type === DebuggerType.cppdbg ? localize("enter.program.name", "enter program name, for example {0}", "${workspaceFolder}" + "/" + executable).replace(/"/g, '') : undefined
|
||||
};
|
||||
}
|
||||
|
||||
function createLaunchString(name: string, type: string, executable: string): string {
|
||||
return `"name": "${name}",
|
||||
"type": "${type}",
|
||||
"request": "launch",
|
||||
"program": "${localize("enter.program.name", "enter program name, for example {0}", "$\{workspaceFolder\}" + "/" + executable).replace(/"/g, '')}",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "$\{fileDirname\}",
|
||||
"environment": [],
|
||||
${ type === "cppdbg" ? `"externalConsole": false` : `"console": "externalTerminal"` }
|
||||
`;
|
||||
function createRemoteAttachBlock(name: string, type: string, executable: string): Record<string, any> {
|
||||
return {
|
||||
name: name,
|
||||
type: type,
|
||||
request: "attach",
|
||||
program: localize("enter.program.name", "enter program name, for example {0}", "${workspaceFolder}" + "/" + executable).replace(/"/g, ''),
|
||||
processId: "${command:pickRemoteProcess}"
|
||||
};
|
||||
}
|
||||
|
||||
function createAttachString(name: string, type: string, executable: string): string {
|
||||
return formatString(`
|
||||
"name": "${name}",
|
||||
"type": "${type}",
|
||||
"request": "attach",{0}
|
||||
`, [type === "cppdbg" ? `${os.EOL}"program": "${localize("enter.program.name", "enter program name, for example {0}", "$\{workspaceFolder\}" + "/" + executable).replace(/"/g, '')}",` : ""]);
|
||||
function createPipeTransportBlock(pipeProgram: string, debuggerProgram: string, pipeArgs: string[] = []): Record<string, any> {
|
||||
return {
|
||||
pipeTransport: {
|
||||
debuggerPath: `/usr/bin/${debuggerProgram}`,
|
||||
pipeProgram: pipeProgram,
|
||||
pipeArgs: pipeArgs,
|
||||
pipeCwd: ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createRemoteAttachString(name: string, type: string, executable: string): string {
|
||||
return `
|
||||
"name": "${name}",
|
||||
"type": "${type}",
|
||||
"request": "attach",
|
||||
"program": "${localize("enter.program.name", "enter program name, for example {0}", "$\{workspaceFolder\}" + "/" + executable).replace(/"/g, '')}",
|
||||
"processId": "$\{command:pickRemoteProcess\}"
|
||||
`;
|
||||
}
|
||||
|
||||
function createPipeTransportString(pipeProgram: string, debuggerProgram: string, pipeArgs: string[] = []): string {
|
||||
return `
|
||||
"pipeTransport": {
|
||||
\t"debuggerPath": "/usr/bin/${debuggerProgram}",
|
||||
\t"pipeProgram": "${pipeProgram}",
|
||||
\t"pipeArgs": ${JSON.stringify(pipeArgs)},
|
||||
\t"pipeCwd": ""
|
||||
}`;
|
||||
}
|
||||
|
||||
export interface IConfiguration {
|
||||
GetLaunchConfiguration(): IConfigurationSnippet;
|
||||
GetAttachConfiguration(): IConfigurationSnippet;
|
||||
}
|
||||
|
||||
abstract class Configuration implements IConfiguration {
|
||||
|
||||
public executable: string;
|
||||
public pipeProgram: string;
|
||||
public MIMode: string;
|
||||
public additionalProperties: string;
|
||||
|
||||
public miDebugger = "cppdbg";
|
||||
public windowsDebugger = "cppvsdbg";
|
||||
|
||||
constructor(MIMode: string, executable: string, pipeProgram: string, additionalProperties: string = "") {
|
||||
this.MIMode = MIMode;
|
||||
this.executable = executable;
|
||||
this.pipeProgram = pipeProgram;
|
||||
this.additionalProperties = additionalProperties;
|
||||
}
|
||||
|
||||
export abstract class Configuration {
|
||||
abstract GetLaunchConfiguration(): IConfigurationSnippet;
|
||||
abstract GetAttachConfiguration(): IConfigurationSnippet;
|
||||
}
|
||||
|
||||
/** Creates Configurations for an MI debugger */
|
||||
export class MIConfigurations extends Configuration {
|
||||
|
||||
constructor(public MIMode: string, public executable: string, public additionalProperties: Record<string, any> = {}) {
|
||||
super();
|
||||
}
|
||||
|
||||
public GetLaunchConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("launch.string", "Launch").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`{
|
||||
\t${indentJsonString(createLaunchString(name, this.miDebugger, this.executable))},
|
||||
\t"MIMode": "${this.MIMode}"{0}{1}
|
||||
}`, [this.miDebugger === "cppdbg" && os.platform() === "win32" ? `,${os.EOL}\t"miDebuggerPath": "/path/to/gdb"` : "",
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("launch.with", "Launch with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"isInitialConfiguration": true,
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("launch.with", "Launch with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createLaunchBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
MIMode: this.MIMode,
|
||||
miDebuggerPath: isWindows ? `<${localize("path.to.gdb", "path to gdb").replace(/"/g, '')}>` : undefined,
|
||||
...this.additionalProperties
|
||||
},
|
||||
isInitialConfiguration: true,
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
}
|
||||
|
||||
public GetAttachConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("attach.string", "Attach").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`{
|
||||
\t${indentJsonString(createAttachString(name, this.miDebugger, this.executable))}
|
||||
\t"MIMode": "${this.MIMode}"{0}{1}
|
||||
}`, [this.miDebugger === "cppdbg" && os.platform() === "win32" ? `,${os.EOL}\t"miDebuggerPath": "/path/to/gdb"` : "",
|
||||
this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("attach.with", "Attach with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("attach.with", "Attach with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createAttachBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
MIMode: this.MIMode,
|
||||
miDebuggerPath: isWindows ? `<${localize("path.to.gdb", "path to gdb").replace(/"/g, '')}>` : undefined,
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class PipeTransportConfigurations extends Configuration {
|
||||
|
||||
constructor(public MIMode: string, public executable: string, public pipeProgram: string, public additionalProperties: Record<string, any> = {}) {
|
||||
super();
|
||||
}
|
||||
public GetLaunchConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("pipe.launch", "Pipe Launch").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`
|
||||
{
|
||||
\t${indentJsonString(createLaunchString(name, this.miDebugger, this.executable))},
|
||||
\t${indentJsonString(createPipeTransportString(this.pipeProgram, this.MIMode))},
|
||||
\t"MIMode": "${this.MIMode}"{0}
|
||||
}`, [this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("pipe.launch.with", "Pipe Launch with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("pipe.launch.with", "Pipe Launch with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createLaunchBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
...createPipeTransportBlock(this.pipeProgram, this.MIMode),
|
||||
MIMode: this.MIMode,
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
|
||||
}
|
||||
@@ -218,38 +193,35 @@ export class PipeTransportConfigurations extends Configuration {
|
||||
public GetAttachConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("pipe.attach", "Pipe Attach").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`
|
||||
{
|
||||
\t${indentJsonString(createRemoteAttachString(name, this.miDebugger, this.executable))},
|
||||
\t${indentJsonString(createPipeTransportString(this.pipeProgram, this.MIMode))},
|
||||
\t"MIMode": "${this.MIMode}"{0}
|
||||
}`, [this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("pipe.attach.with", "Pipe Attach with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("pipe.attach.with", "Pipe Attach with {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createRemoteAttachBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
...createPipeTransportBlock(this.pipeProgram, this.MIMode),
|
||||
MIMode: this.MIMode,
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowsConfigurations extends Configuration {
|
||||
constructor(public executable: string, public additionalProperties: Record<string, any> = {}) {
|
||||
super();
|
||||
}
|
||||
|
||||
public GetLaunchConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(Windows) ${localize("launch.string", "Launch").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = `
|
||||
{
|
||||
\t${indentJsonString(createLaunchString(name, this.windowsDebugger, this.executable))}
|
||||
}`;
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("launch.with.vs.debugger", "Launch with the Visual Studio C/C++ debugger.").replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"isInitialConfiguration": true,
|
||||
"debuggerType": DebuggerType.cppvsdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("launch.with.vs.debugger", "Launch with the Visual Studio C/C++ debugger.").replace(/"/g, ''),
|
||||
body: createLaunchBlock(name, DebuggerType.cppvsdbg, this.executable),
|
||||
isInitialConfiguration: true,
|
||||
debuggerType: DebuggerType.cppvsdbg
|
||||
};
|
||||
|
||||
}
|
||||
@@ -257,56 +229,85 @@ export class WindowsConfigurations extends Configuration {
|
||||
public GetAttachConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(Windows) ${localize("attach.string", "Attach").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = `
|
||||
{
|
||||
\t${indentJsonString(createAttachString(name, this.windowsDebugger, this.executable))}
|
||||
}`;
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("attach.with.vs.debugger", "Attach to a process with the Visual Studio C/C++ debugger.").replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppvsdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("attach.with.vs.debugger", "Attach to a process with the Visual Studio C/C++ debugger.").replace(/"/g, ''),
|
||||
body: createAttachBlock(name, DebuggerType.cppvsdbg, this.executable),
|
||||
debuggerType: DebuggerType.cppvsdbg
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class WSLConfigurations extends Configuration {
|
||||
constructor(public MIMode: string, public executable: string, public additionalProperties: Record<string, any> = {}) {
|
||||
super();
|
||||
}
|
||||
// Detects if the current VSCode is 32-bit and uses the correct bash.exe
|
||||
public bashPipeProgram = process.arch === 'ia32' ? "${env:windir}\\\\sysnative\\\\bash.exe" : "${env:windir}\\\\system32\\\\bash.exe";
|
||||
|
||||
public GetLaunchConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("bash.on.windows.launch", "Bash on Windows Launch").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`
|
||||
{
|
||||
\t${indentJsonString(createLaunchString(name, this.miDebugger, this.executable))},
|
||||
\t${indentJsonString(createPipeTransportString(this.bashPipeProgram, this.MIMode, ["-c"]))}{0}
|
||||
}`, [this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("launch.bash.windows", "Launch in Bash on Windows using {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("launch.bash.windows", "Launch in Bash on Windows using {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createLaunchBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
...createPipeTransportBlock(this.bashPipeProgram, this.MIMode, ["-c"]),
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
}
|
||||
|
||||
public GetAttachConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(${this.MIMode}) ${localize("bash.on.windows.attach", "Bash on Windows Attach").replace(/"/g, '')}`;
|
||||
|
||||
const body: string = formatString(`
|
||||
{
|
||||
\t${indentJsonString(createRemoteAttachString(name, this.miDebugger, this.executable))},
|
||||
\t${indentJsonString(createPipeTransportString(this.bashPipeProgram, this.MIMode, ["-c"]))}{0}
|
||||
}`, [this.additionalProperties ? `,${os.EOL}\t${indentJsonString(this.additionalProperties)}` : ""]);
|
||||
|
||||
return {
|
||||
"label": configPrefix + name,
|
||||
"description": localize("remote.attach.bash.windows", "Attach to a remote process running in Bash on Windows using {0}.", this.MIMode).replace(/"/g, ''),
|
||||
"bodyText": body.trim(),
|
||||
"debuggerType": DebuggerType.cppdbg
|
||||
label: configPrefix + name,
|
||||
description: localize("remote.attach.bash.windows", "Attach to a remote process running in Bash on Windows using {0}.", this.MIMode).replace(/"/g, ''),
|
||||
body: {
|
||||
...createRemoteAttachBlock(name, DebuggerType.cppdbg, this.executable),
|
||||
...createPipeTransportBlock(this.bashPipeProgram, this.MIMode, ["-c"]),
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cppdbg
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates Configurations for an LLDB-DAP debugger */
|
||||
export class LldbDapConfigurations extends Configuration {
|
||||
|
||||
constructor(public executable: string, public additionalProperties: Record<string, any> = {}) {
|
||||
super();
|
||||
}
|
||||
|
||||
public GetLaunchConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(lldb-dap) ${localize("launch.string", "Launch").replace(/"/g, '')}`;
|
||||
|
||||
return {
|
||||
label: configPrefix + name,
|
||||
description: localize("launch.with", "Launch with {0}.", "LLDB-DAP").replace(/"/g, ''),
|
||||
body: {
|
||||
...createLaunchBlock(name, DebuggerType.cpplldb, this.executable),
|
||||
...this.additionalProperties
|
||||
},
|
||||
isInitialConfiguration: true,
|
||||
debuggerType: DebuggerType.cpplldb
|
||||
};
|
||||
}
|
||||
|
||||
public GetAttachConfiguration(): IConfigurationSnippet {
|
||||
const name: string = `(lldb-dap) ${localize("attach.string", "Attach").replace(/"/g, '')}`;
|
||||
return {
|
||||
label: configPrefix + name,
|
||||
description: localize("attach.with", "Attach with {0}.", "LLDB-DAP").replace(/"/g, ''),
|
||||
body: {
|
||||
...createAttachBlock(name, DebuggerType.cpplldb, this.executable),
|
||||
...this.additionalProperties
|
||||
},
|
||||
debuggerType: DebuggerType.cpplldb
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from "vscode";
|
||||
import * as nls from 'vscode-nls';
|
||||
import { DebuggerType } from './configurations';
|
||||
import { findLldbDap, isValidLldbDap } from './lldb-dap';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
@@ -40,7 +42,7 @@ export class CppvsdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterD
|
||||
|
||||
async createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor | null> {
|
||||
if (os.platform() !== 'win32') {
|
||||
void vscode.window.showErrorMessage(localize("debugger.not.available", "Debugger type '{0}' is not available for non-Windows machines.", "cppvsdbg"));
|
||||
void vscode.window.showErrorMessage(localize("debugger.not.available", "Debugger type '{0}' is not available for non-Windows machines.", DebuggerType.cppvsdbg));
|
||||
return null;
|
||||
} else {
|
||||
return new vscode.DebugAdapterExecutable(
|
||||
@@ -50,3 +52,43 @@ export class CppvsdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generates the command line for the LLDB-DAP debugger */
|
||||
export class CpplldbDebugAdapterDescriptorFactory extends AbstractDebugAdapterDescriptorFactory {
|
||||
async createDebugAdapterDescriptor(session: vscode.DebugSession, executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor | null> {
|
||||
|
||||
// The adapter path can be specified in the launch.json entry.
|
||||
let adapter: string | undefined = session.configuration.debuggerPath || executable?.command;
|
||||
|
||||
if (adapter) {
|
||||
// Verify that the path is actually valid.
|
||||
if (!await isValidLldbDap(adapter)) {
|
||||
adapter = await findLldbDap();
|
||||
if (adapter) {
|
||||
void vscode.window.showErrorMessage(localize("debugger.path.not.available.falling.back", "The specified LLDB-DAP debuggerPath '{0}' is not valid, falling back to {1}.", session.configuration.debuggerPath, adapter));
|
||||
} else {
|
||||
void vscode.window.showErrorMessage(localize("debugger.path.not.available", "The specified LLDB-DAP debuggerPath '{0}' is not valid and no fallback was found.", session.configuration.debuggerPath));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!adapter) {
|
||||
adapter = await findLldbDap();
|
||||
}
|
||||
|
||||
if (!adapter) {
|
||||
void vscode.window.showErrorMessage(localize("lldbdap.debugger.not.available", "No LLDB-DAP debugger found. Please add it to the path, or set the debuggerPath property in the launch.json file."));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Prepare the command to run the lldb-dap executable.
|
||||
const debuggerArgs = session.configuration.debuggerArgs || [];
|
||||
|
||||
// Future: add support for pipeTransport (so that the lldb-dap executable can be run on a remote machine or wsl).
|
||||
// Future: add support for --server mode (so that the lldb-dap executable can be run in server mode).
|
||||
|
||||
// Prepare the command to run the lldb-dap executable.
|
||||
return new vscode.DebugAdapterExecutable(adapter, [...debuggerArgs]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ import { SshTargetsProvider, getActiveSshTarget, initializeSshTargets, selectSsh
|
||||
import { TargetLeafNode, setActiveSshTarget } from '../SSH/TargetsView/targetNodes';
|
||||
import { sshCommandToConfig } from '../SSH/sshCommandToConfig';
|
||||
import { getSshConfiguration, getSshConfigurationFiles, parseFailures, writeSshConfiguration } from '../SSH/sshHosts';
|
||||
import { pathAccessible } from '../common';
|
||||
import { pathAccessible } from '../common-remote-safe';
|
||||
import { instrument } from '../instrumentation';
|
||||
import { getSshChannel } from '../logger';
|
||||
import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess';
|
||||
import { ConfigurationAssetProviderFactory, ConfigurationSnippetProvider, DebugConfigurationProvider, IConfigurationAssetProvider } from './configurationProvider';
|
||||
import { ConfigurationAssetProvider, ConfigurationSnippetProvider, DebugConfigurationProvider } from './configurationProvider';
|
||||
import { DebuggerType } from './configurations';
|
||||
import { CppdbgDebugAdapterDescriptorFactory, CppvsdbgDebugAdapterDescriptorFactory } from './debugAdapterDescriptorFactory';
|
||||
import { CppdbgDebugAdapterDescriptorFactory, CpplldbDebugAdapterDescriptorFactory, CppvsdbgDebugAdapterDescriptorFactory } from './debugAdapterDescriptorFactory';
|
||||
import { NativeAttachItemsProviderFactory } from './nativeAttach';
|
||||
|
||||
// The extension deactivate method is asynchronous, so we handle the disposables ourselves instead of using extensionContext.subscriptions.
|
||||
@@ -40,18 +40,20 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
|
||||
disposables.push(vscode.commands.registerCommand('extension.pickRemoteNativeProcess', (any) => remoteAttacher.ShowAttachEntries(any)));
|
||||
|
||||
// Activate ConfigurationProvider
|
||||
const assetProvider: IConfigurationAssetProvider = ConfigurationAssetProviderFactory.getConfigurationProvider();
|
||||
const assetProvider = ConfigurationAssetProvider.getConfigurationAssetProvider();
|
||||
|
||||
// Register DebugConfigurationProviders for "Run and Debug" in Debug Panel.
|
||||
// On Windows platforms, the cppvsdbg debugger will also be registered for initial configurations.
|
||||
let cppVsDebugProvider: DebugConfigurationProvider | null = null;
|
||||
if (os.platform() === 'win32') {
|
||||
cppVsDebugProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppvsdbg);
|
||||
const cppVsDebugProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppvsdbg);
|
||||
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppvsdbg, instrument(cppVsDebugProvider), vscode.DebugConfigurationProviderTriggerKind.Dynamic));
|
||||
}
|
||||
const cppDebugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppdbg);
|
||||
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cppdbg, instrument(cppDebugProvider), vscode.DebugConfigurationProviderTriggerKind.Dynamic));
|
||||
|
||||
const cpplldbDebugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cpplldb);
|
||||
disposables.push(vscode.debug.registerDebugConfigurationProvider(DebuggerType.cpplldb, instrument(cpplldbDebugProvider), vscode.DebugConfigurationProviderTriggerKind.Dynamic));
|
||||
|
||||
// Register DebugConfigurationProviders for "Run and Debug" play button.
|
||||
const debugProvider: DebugConfigurationProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.all);
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
@@ -81,6 +83,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
|
||||
// Register Debug Adapters
|
||||
disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory(DebuggerType.cppvsdbg, new CppvsdbgDebugAdapterDescriptorFactory(context)));
|
||||
disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory(DebuggerType.cppdbg, new CppdbgDebugAdapterDescriptorFactory(context)));
|
||||
disposables.push(vscode.debug.registerDebugAdapterDescriptorFactory(DebuggerType.cpplldb, new CpplldbDebugAdapterDescriptorFactory(context)));
|
||||
|
||||
// SSH Targets View
|
||||
await initializeSshTargets();
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import { isMainThread, parentPort } from 'node:worker_threads';
|
||||
|
||||
import { appendLineAtLevel, executableName, findInPath, initialize, isExecutable, localize, searchFolders, spawnChildProcess } from '../common-remote-safe';
|
||||
import { isLinux, isMacOS, isWindows } from '../constants';
|
||||
import { TroubleshootingLldbDap } from '../links';
|
||||
import { ManualPromise } from '../Utility/Async/manualPromise';
|
||||
import { RemoteConnection, startRemoting } from '../Utility/Remoting/snare';
|
||||
|
||||
let remote: RemoteConnection | undefined;
|
||||
|
||||
/**
|
||||
* Base interface for debug configurations.
|
||||
* Represents a configuration used by the VS Code debugger.
|
||||
*/
|
||||
export interface DebugConfiguration {
|
||||
/**
|
||||
* The type of the debug session.
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* The name of the debug session.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The request type of the debug session.
|
||||
*/
|
||||
request: string;
|
||||
|
||||
/**
|
||||
* Additional debug type specific properties.
|
||||
*/
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* C++ specific debug configuration interface.
|
||||
* Extends the base debug configuration with C++ specific properties.
|
||||
*/
|
||||
export interface CppDebugConfiguration extends DebugConfiguration {
|
||||
/** Detailed description of the configuration. */
|
||||
detail?: string;
|
||||
|
||||
/** Status of the associated build task. */
|
||||
taskStatus?: any;
|
||||
|
||||
/**
|
||||
* Indicates whether this is the default debug configuration.
|
||||
* The debug configuration is considered as default if the prelaunch task is set as default.
|
||||
*/
|
||||
isDefault?: boolean;
|
||||
|
||||
/** Source of the configuration (e.g., auto-generated, user-defined). */
|
||||
configSource?: any;
|
||||
|
||||
/** Debugger-specific event information. */
|
||||
debuggerEvent?: any;
|
||||
|
||||
/** Type of debugging to perform. */
|
||||
debugType?: any;
|
||||
|
||||
/** Indicates whether this configuration represents an existing debug session. */
|
||||
existing?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum representing the supported debugger types in the C++ extension.
|
||||
*/
|
||||
export enum DebuggerType {
|
||||
/** Microsoft Visual Studio Debugger */
|
||||
cppvsdbg = "cppvsdbg",
|
||||
|
||||
/** GDB Debugger */
|
||||
cppdbg = "cppdbg",
|
||||
|
||||
/** LLDB Debugger with Debug Adapter Protocol support */
|
||||
cpplldb = "cpplldb",
|
||||
|
||||
/** Represents all debugger types */
|
||||
all = "all"
|
||||
}
|
||||
|
||||
/** Cached path to the lldb-dap executable once found. */
|
||||
let lldbDapPath: string | undefined;
|
||||
|
||||
/** Cached path to the xcrun tool on macOS. */
|
||||
let xcRunPath: string | undefined;
|
||||
|
||||
/**
|
||||
* On macOS, calls xcrun to find a given xtools binary (usually they don't expose the binary to the PATH).
|
||||
*
|
||||
* @param filename The name of the binary to find (e.g., lldb-vscode or lldb-dap).
|
||||
* @returns The path to the binary or undefined if it was not found.
|
||||
*/
|
||||
export async function xcRun(filename: string) {
|
||||
if (isMacOS) {
|
||||
try {
|
||||
xcRunPath ??= await findInPath('xcrun');
|
||||
if (xcRunPath) {
|
||||
const xcRun = await spawnChildProcess(xcRunPath, ['--find', filename]);
|
||||
|
||||
if (xcRun.succeeded) {
|
||||
const path = xcRun.output.trim();
|
||||
if (await isValidLldbDap(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore failure to run xcrun, or no results found.
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Promise representing an ongoing search for the lldb-dap executable. */
|
||||
let searching: ManualPromise<string | undefined> | undefined;
|
||||
|
||||
/**
|
||||
* List of candidate file names and patterns to search for when looking for the lldb-dap executable.
|
||||
* Includes both string literals and regular expressions to match version-specific binaries.
|
||||
*/
|
||||
const candidates = [
|
||||
executableName('lldb-dap'),
|
||||
/^lldb-dap-\d+$|^lldb-dap-\d+\.exe$/,
|
||||
executableName('lldb-vscode'),
|
||||
/^lldb-vscode-\d+$|^lldb-vscode-\d+\.exe$/
|
||||
];
|
||||
|
||||
/**
|
||||
* The search implementation to find the viable lldb-dap executable.
|
||||
*
|
||||
* We absolutely prefer an lldb-dap binary that is in the path.
|
||||
* Failing that, we'll:
|
||||
* - Try xcrun on macOS to see if xtools can give it to us
|
||||
* - Try searching the secure well-known locations for a binary
|
||||
*
|
||||
* And if we can't find the actual lldb-dap binary, we'll try the same thing
|
||||
* for 'lldb-vscode' (the old name for the DAP binary)
|
||||
* and then 'lldb-dap-##' and 'lldb-vscode-##'. In practice, one might find a
|
||||
* binary with the LLVM major version number in it.
|
||||
*
|
||||
* @returns The path to the lldb-dap executable or undefined if it was not found.
|
||||
*/
|
||||
async function searchForLldbDap() {
|
||||
if (lldbDapPath) {
|
||||
return lldbDapPath;
|
||||
}
|
||||
const start = Date.now();
|
||||
// PATH binaries take priority.
|
||||
for (const candidate of candidates) {
|
||||
// First, search the environment PATH for the binary.
|
||||
lldbDapPath = await findInPath(candidate, isValidLldbDap);
|
||||
if (lldbDapPath) {
|
||||
appendLineAtLevel(6, `Discovered lldb-dap binary at '${lldbDapPath}' ${Date.now() - start} msec`);
|
||||
return lldbDapPath;
|
||||
}
|
||||
}
|
||||
|
||||
// Well-known locations next.
|
||||
for (const candidate of candidates) {
|
||||
if (isMacOS) {
|
||||
// If that fails, use xcrun to find the path.
|
||||
if (typeof candidate === 'string') {
|
||||
lldbDapPath = await xcRun(candidate);
|
||||
if (lldbDapPath) {
|
||||
appendLineAtLevel(6, `Discovered lldb-dap binary for macOS at '${lldbDapPath}' ${Date.now() - start} msec`);
|
||||
return lldbDapPath;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, it's not in the PATH or via xcrun - but worry not,
|
||||
// we'll do a check of well known secured locations where it might be installed.
|
||||
lldbDapPath = await searchFolders(['/Applications', '/opt/homebrew'], candidate, isValidLldbDap, 8);
|
||||
if (lldbDapPath) {
|
||||
appendLineAtLevel(6, `Discovered lldb-dap binary for macOS at '${lldbDapPath}' ${Date.now() - start} msec`);
|
||||
return lldbDapPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (isWindows) {
|
||||
// If we got this far, it's not in the PATH - but worry not,
|
||||
// we'll do a check of well known secured locations where it might be installed.
|
||||
lldbDapPath = await searchFolders(['c:/Program Files/LLVM', 'c:/Program Files/', 'C:/program files (x86)/'], candidate, isValidLldbDap);
|
||||
if (lldbDapPath) {
|
||||
appendLineAtLevel(6, `Discovered lldb-dap binary for Windows at '${lldbDapPath}' ${Date.now() - start} msec`);
|
||||
return lldbDapPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isLinux) {
|
||||
// If we got this far, it's not in the PATH - but worry not,
|
||||
// we'll do a check of well known secured locations where it might be installed.
|
||||
lldbDapPath = await searchFolders(['/usr', '/opt'], candidate, isValidLldbDap, 8);
|
||||
if (lldbDapPath) {
|
||||
appendLineAtLevel(6, `Discovered lldb-dap binary for Linux at '${lldbDapPath}' ${Date.now() - start} msec`);
|
||||
return lldbDapPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
appendLineAtLevel(1, localize('lldb-dap.notfound', "Unable to find a working '{0}' adapter ({1} msec). See: {2}", 'lldb-dap', Date.now() - start, TroubleshootingLldbDap));
|
||||
return lldbDapPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls searchForLldbDap, but only runs one search at a time. Subsequent calls return the current search.
|
||||
*
|
||||
* @returns The path to the lldb-dap executable or undefined if it was not found.
|
||||
*/
|
||||
export async function findLldbDapImpl() {
|
||||
// If we already have a path, return it.
|
||||
if (lldbDapPath) {
|
||||
return lldbDapPath;
|
||||
}
|
||||
if (searching) {
|
||||
return searching;
|
||||
}
|
||||
|
||||
// Only run one search at a time, so if we are already searching, return that.
|
||||
searching = new ManualPromise<string | undefined>();
|
||||
searchForLldbDap().then((result: string | undefined): void => {
|
||||
if (searching) {
|
||||
searching.resolve(result);
|
||||
searching = undefined;
|
||||
}
|
||||
}).catch(error => {
|
||||
if (searching) {
|
||||
searching.reject(error);
|
||||
searching = undefined;
|
||||
}
|
||||
});
|
||||
return searching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given path is a valid lldb-dap executable (actually runs it to check).
|
||||
*
|
||||
* @param lldbDap The path to the lldb-dap executable.
|
||||
* @returns True if the path is valid, false otherwise.
|
||||
*/
|
||||
export async function isValidLldbDap(lldbDap: string | undefined) {
|
||||
if (lldbDap) {
|
||||
if (await isExecutable(lldbDap)) {
|
||||
const proc = await spawnChildProcess(lldbDap, ['--help'], undefined, true);
|
||||
if (proc.succeeded && proc.output.includes('USAGE')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
appendLineAtLevel(6, localize('lldb-dap.not.valid', "The lldb-dap binary at '{0}' does not appear to be functional. See: {1}", lldbDap, TroubleshootingLldbDap));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isMainThread) {
|
||||
// If this is loaded in a worker thread, we'll set up the remoting interface.
|
||||
try {
|
||||
/** This is the SNARE remote call interface dispatcher that the worker thread supports. */
|
||||
remote = parentPort ? startRemoting(parentPort, {
|
||||
// These are the functions that this worker exposes to the parent thread.
|
||||
findLldbDapImpl
|
||||
}) : undefined; // If we're not in a worker thread - then we don't really have a remote interface.
|
||||
initialize(remote);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
appendLineAtLevel(6, `Error in worker thread: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import { resolve } from 'node:path';
|
||||
import { isMainThread } from 'node:worker_threads';
|
||||
import { appendLine, appendLineAtLevel, localize, log, note } from '../common-remote-safe';
|
||||
import { isWindows } from '../constants';
|
||||
import { RemoteConnection, startRemoting, startWorker } from '../Utility/Remoting/snare';
|
||||
import { CppDebugConfiguration, DebuggerType } from './configurations';
|
||||
import { findLldbDapImpl } from './lldb-dap-worker';
|
||||
export { isValidLldbDap } from './lldb-dap-worker';
|
||||
|
||||
/** Translates the cpplldb configuration to the lldb-dap configuration.
|
||||
* Note: this modifies the existing configuration object in place.
|
||||
*
|
||||
* @param config The cpplldb configuration to translate.
|
||||
* @returns The translated lldb-dap configuration.
|
||||
*/
|
||||
export function translateToLldbDap(config: CppDebugConfiguration) {
|
||||
// Adapt the cpplldb config to the lldb-dap config.
|
||||
if (config.type !== DebuggerType.cpplldb) {
|
||||
throw new Error(`Invalid config type ${config.type} for lldb-dap`);
|
||||
}
|
||||
|
||||
// Translate environment to env.
|
||||
if (config.environment) {
|
||||
// 'config.environment' is an array of { "name":<string>, "value":<string> } objects.
|
||||
// lldb-dap expects an object of { <name>:<value>, ... }.
|
||||
const env: { [key: string]: string } = {};
|
||||
for (const each of config.environment) {
|
||||
if (typeof each.name === 'string' && typeof each.value === 'string') {
|
||||
env[each.name] = each.value;
|
||||
}
|
||||
}
|
||||
delete config.environment;
|
||||
}
|
||||
|
||||
// Translate stopAtEntry to stopOnEntry.
|
||||
if (config.stopAtEntry !== undefined) {
|
||||
config.stopOnEntry = config.stopAtEntry;
|
||||
delete config.stopAtEntry;
|
||||
}
|
||||
|
||||
// Translate serverLaunchTimeout (msec) to timeout (seconds).
|
||||
if (config.serverLaunchTimeout !== undefined) {
|
||||
config.timeout = Math.floor(config.serverLaunchTimeout / 1000);
|
||||
delete config.serverLaunchTimeout;
|
||||
}
|
||||
|
||||
// Translate externalConsole to runInTerminal (!inverse).
|
||||
if (config.externalConsole !== undefined) {
|
||||
config.runInTerminal = !config.externalConsole;
|
||||
delete config.externalConsole;
|
||||
}
|
||||
|
||||
// TODO: translate sourceFileMap to sourcePath and sourceMap.
|
||||
|
||||
// Translate processId to pid.
|
||||
if (config.processId !== undefined) {
|
||||
config.pid = Number(config.processId);
|
||||
delete config.program;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/** Connection to the worker thread handling lldb-dap related operations. */
|
||||
let remote: RemoteConnection | undefined;
|
||||
|
||||
/** Cached path to the lldb-dap executable once found. */
|
||||
let lldbDapExecutable: string | undefined;
|
||||
|
||||
/**
|
||||
* Finds the path to the lldb-dap executable.
|
||||
*
|
||||
* This function uses a worker thread if available, otherwise calls the implementation directly.
|
||||
* The result is cached for subsequent calls.
|
||||
*
|
||||
* @returns A promise that resolves to the path of the lldb-dap executable, or undefined if not found.
|
||||
*/
|
||||
export async function findLldbDap() {
|
||||
return lldbDapExecutable ??= remote ? await remote.request('findLldbDapImpl') : findLldbDapImpl();
|
||||
}
|
||||
|
||||
// This code must only run in the main thread.
|
||||
if (isMainThread && !remote) {
|
||||
try {
|
||||
// Find the entry point for the worker thread.
|
||||
const file = resolve(__dirname.substring(0, __dirname.lastIndexOf('dist')), "dist", "src", "Debugger", 'lldb-dap-worker.js');
|
||||
// Create the worker and connection.
|
||||
remote = startRemoting(startWorker(file), {
|
||||
// These are the functions that the main thread exposes to the worker thread.
|
||||
log,
|
||||
note,
|
||||
localize,
|
||||
appendLine,
|
||||
appendLineAtLevel
|
||||
});
|
||||
|
||||
if (!isWindows) {
|
||||
// If we are not on Windows, we'll start it searching for the lldb-dap executable as early as possible.
|
||||
// Mainly, because the LLDB-DAP debugger isn't a common standalone debugger for Windows.
|
||||
void findLldbDap();
|
||||
}
|
||||
} catch (e) {
|
||||
// If we fail to start the worker, we can still use the implementation directly.
|
||||
appendLineAtLevel(6, "Failed to start the worker thread for LLDB-DAP remote calls. Falling back to direct calls.");
|
||||
remote = undefined;
|
||||
}
|
||||
}
|
||||
@@ -5,25 +5,44 @@
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import * as os from 'os';
|
||||
import { normalize } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { findPowerShell } from '../common';
|
||||
import { isMacOS } from '../constants';
|
||||
import { AttachItem } from './attachQuickPick';
|
||||
import { AttachItemsProvider } from './attachToProcess';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
|
||||
export class Process {
|
||||
constructor(public name: string, public pid?: string, public commandLine?: string) { }
|
||||
export class Process implements AttachItem {
|
||||
get label() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public toAttachItem(): AttachItem {
|
||||
return {
|
||||
label: this.name,
|
||||
description: this.pid,
|
||||
detail: this.commandLine,
|
||||
id: this.pid
|
||||
};
|
||||
get description() {
|
||||
// If the fullPath is known and different than the process name, put that in the description after the pid
|
||||
// to let the user can find the actual process they are looking for.
|
||||
return this.fullPath && this.fullPath !== this.name ? `${this.pid} [${this.fullPath}]` : this.pid;
|
||||
}
|
||||
|
||||
get detail() {
|
||||
return this.commandLine;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.pid;
|
||||
}
|
||||
|
||||
constructor(public name: string, public pid?: string, public commandLine?: string, public fullPath?: string) {
|
||||
if (this.fullPath) {
|
||||
// If we have a full path, clean it up.
|
||||
if (this.fullPath?.startsWith('"') && this.fullPath.endsWith('"')) {
|
||||
this.fullPath = this.fullPath.slice(1, -1);
|
||||
}
|
||||
this.fullPath = normalize(this.fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +81,7 @@ abstract class NativeAttachItemsProvider implements AttachItemsProvider {
|
||||
}
|
||||
return aLower < bLower ? -1 : 1;
|
||||
});
|
||||
const attachItems: AttachItem[] = processEntries.map(p => p.toAttachItem());
|
||||
return attachItems;
|
||||
return processEntries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,33 +111,26 @@ export class PsAttachItemsProvider extends NativeAttachItemsProvider {
|
||||
// QuickPick UI in VSCode.
|
||||
|
||||
protected async getInternalProcessEntries(token?: vscode.CancellationToken): Promise<Process[]> {
|
||||
let processCmd: string = '';
|
||||
switch (os.platform()) {
|
||||
case 'darwin':
|
||||
processCmd = PsProcessParser.psDarwinCommand;
|
||||
break;
|
||||
return PsProcessParser.ParseProcessFromPs(await spawnChildProcess(PsProcessParser.psDarwinCommand, token));
|
||||
case 'linux':
|
||||
processCmd = PsProcessParser.psLinuxCommand;
|
||||
break;
|
||||
return PsProcessParser.ParseProcessFromPs(await spawnChildProcess(PsProcessParser.psLinuxCommand, token));
|
||||
default:
|
||||
throw new Error(localize("os.not.supported", 'Operating system "{0}" not supported.', os.platform()));
|
||||
}
|
||||
const processes: string = await spawnChildProcess(processCmd, token);
|
||||
return PsProcessParser.ParseProcessFromPs(processes);
|
||||
}
|
||||
}
|
||||
|
||||
export class PsProcessParser {
|
||||
private static get secondColumnCharacters(): number { return 50; }
|
||||
private static get commColumnTitle(): string { return Array(PsProcessParser.secondColumnCharacters).join("a"); }
|
||||
// the BSD version of ps uses '-c' to have 'comm' only output the executable name and not
|
||||
// the full path. The Linux version of ps has 'comm' to only display the name of the executable
|
||||
// Use a large fixed width - the default on macOS is quite small.
|
||||
static fixedWidth = ''.padEnd(512, 'a');
|
||||
|
||||
// Note that comm on Linux systems is truncated to 16 characters:
|
||||
// https://bugzilla.redhat.com/show_bug.cgi?id=429565
|
||||
// Since 'args' contains the full path to the executable, even if truncated, searching will work as desired.
|
||||
public static get psLinuxCommand(): string { return `ps axww -o pid=,comm=${PsProcessParser.commColumnTitle},args=`; }
|
||||
public static get psDarwinCommand(): string { return `ps axww -o pid=,comm=${PsProcessParser.commColumnTitle},args= -c`; }
|
||||
public static get psToyboxCommand(): string { return `ps -A -o pid=,comm=${PsProcessParser.commColumnTitle},args=`; }
|
||||
public static get psLinuxCommand(): string { return `ps axww -o pid=,exe=${this.fixedWidth},args=${this.fixedWidth}`; }
|
||||
public static get psDarwinCommand(): string { return `ps axww -o pid=,comm=${this.fixedWidth},args=${this.fixedWidth}`; }
|
||||
public static get psToyboxCommand(): string { return `ps -A -o pid=,comm=${this.fixedWidth},args=${this.fixedWidth}`; }
|
||||
|
||||
// Only public for tests.
|
||||
public static ParseProcessFromPs(processes: string): Process[] {
|
||||
@@ -147,21 +158,40 @@ export class PsProcessParser {
|
||||
}
|
||||
|
||||
private static parseLineFromPs(line: string): Process | undefined {
|
||||
// Explanation of the regex:
|
||||
// - any leading whitespace
|
||||
// - PID
|
||||
// - whitespace
|
||||
// - executable name --> this is PsAttachItemsProvider.secondColumnCharacters - 1 because ps reserves one character
|
||||
// for the whitespace separator
|
||||
// - whitespace
|
||||
// - args (might be empty)
|
||||
const psEntry: RegExp = new RegExp(`^\\s*([0-9]+)\\s+(.{${PsProcessParser.secondColumnCharacters - 1}})\\s+(.*)$`);
|
||||
const psEntry = isMacOS ?
|
||||
// On macOS, we're using fixed-width columns, so we have to use a fixed-width regex.
|
||||
// <start>whitespace(NUMBERS)whitespace(FIXED-WIDTH)whitespace(EVERYTHING-ELSE)<end>
|
||||
new RegExp(`^\\s*([0-9]+)\\s+(.{${PsProcessParser.fixedWidth.length - 1}})\\s+(.*)$`) :
|
||||
|
||||
// On Linux, column widths cannot be guaranteed - but we do get escaped spaces in the command line.
|
||||
// <start>whitespace(NUMBERS)whitespace(NOTWHITESPACE)whitespace(EVERYTHING-ELSE)<end>
|
||||
/^\s*(\d+)\s+((?:\\\s|\S)+)\s+([\s\S]*)$/;
|
||||
|
||||
const matches: RegExpExecArray | null = psEntry.exec(line);
|
||||
if (matches && matches.length === 4) {
|
||||
const pid: string = matches[1].trim();
|
||||
const executable: string = matches[2].trim();
|
||||
const cmdline: string = matches[3].trim();
|
||||
return new Process(executable, pid, cmdline);
|
||||
let fullPath: string = matches[2].trim();
|
||||
const rawCommandLine = matches[3].trim();
|
||||
|
||||
// Trim the full path off the command line so that we optimize for seeing '<cmd> <args>'.
|
||||
const cmdline: string = rawCommandLine.replace(/^\s*[\/\\]*(?:(?:[^\\\/\s]|\\.)+[\/\\])*([^\\\/\s]+)(?=\s|$)/, "$1");
|
||||
|
||||
// If the fullPath == '-', let's grab the arg0 from the raw command line.
|
||||
if (fullPath === '-') {
|
||||
const args = /^((?:\\\s|\S)+)\s*([\s\S]*)$/.exec(rawCommandLine);
|
||||
if (args) {
|
||||
fullPath = args[1];
|
||||
}
|
||||
}
|
||||
|
||||
const executable: string = fullPath.replace(/^.*\//, '');
|
||||
|
||||
// Skip processes that are '<defunct>'.
|
||||
if (executable === '<defunct>' || cmdline.includes('<defunct>')) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new Process(executable, pid, cmdline, fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,7 +367,7 @@ export class CimAttachItemsProvider extends NativeAttachItemsProvider {
|
||||
|
||||
protected async getInternalProcessEntries(token?: vscode.CancellationToken): Promise<Process[]> {
|
||||
const pwshCommand: string = `${this.pwsh} -NoProfile -Command`;
|
||||
const cimCommand: string = 'Get-CimInstance Win32_Process | Select-Object Name,ProcessId,CommandLine | ConvertTo-JSON -Compress';
|
||||
const cimCommand: string = 'Get-CimInstance Win32_Process | Select-Object Name,ProcessId,CommandLine,Path | ConvertTo-JSON -Compress';
|
||||
const processes: string = await spawnChildProcess(`${pwshCommand} "${cimCommand}"`, token);
|
||||
return CimProcessParser.ParseProcessFromCim(processes);
|
||||
}
|
||||
@@ -347,6 +377,7 @@ type CimProcessInfo = {
|
||||
Name: string;
|
||||
ProcessId: number;
|
||||
CommandLine: string | null;
|
||||
Path: string | null;
|
||||
};
|
||||
|
||||
export class CimProcessParser {
|
||||
@@ -364,7 +395,7 @@ export class CimProcessParser {
|
||||
if (cmdline?.startsWith(this.ntObjectManagerPathPrefix)) {
|
||||
cmdline = cmdline.slice(this.ntObjectManagerPathPrefix.length);
|
||||
}
|
||||
return new Process(info.Name, `${info.ProcessId}`, cmdline);
|
||||
return new Process(info.Name, `${info.ProcessId}`, cmdline, info.Path || undefined);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import { CloseAction, DidOpenTextDocumentParams, ErrorAction, LanguageClientOpti
|
||||
import { LanguageClient, ServerOptions } from 'vscode-languageclient/node';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { DebugConfigurationProvider } from '../Debugger/configurationProvider';
|
||||
import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from '../LanguageServer/customProviders';
|
||||
import { ManualPromise } from '../Utility/Async/manualPromise';
|
||||
import { ManualSignal } from '../Utility/Async/manualSignal';
|
||||
import { logAndReturn } from '../Utility/Async/returns';
|
||||
@@ -56,7 +57,6 @@ import {
|
||||
import { Location, TextEdit, WorkspaceEdit } from './commonTypes';
|
||||
import * as configs from './configurations';
|
||||
import { CopilotCompletionContextFeatures, CopilotCompletionContextProvider } from './copilotCompletionContextProvider';
|
||||
import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from './customProviders';
|
||||
import { DataBinding } from './dataBinding';
|
||||
import { cachedEditorConfigSettings, getEditorConfigSettings } from './editorConfig';
|
||||
import { CppSourceStr, clients, configPrefix, initializeIntervalTimer, updateLanguageConfigurations, usesCrashHandler, watchForCrashes } from './extension';
|
||||
@@ -590,24 +590,6 @@ export interface CopilotCompletionContextParams {
|
||||
doAggregateSnippets: boolean;
|
||||
}
|
||||
|
||||
export interface CopilotRefactorContextParams {
|
||||
uri: string;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface CopilotSymbolRefEntry {
|
||||
uri: string;
|
||||
offset: number;
|
||||
}
|
||||
|
||||
export interface CopilotRefactorContextResult {
|
||||
requestId: number;
|
||||
defUri: string;
|
||||
defStartOffset: number;
|
||||
defEndOffset: number;
|
||||
symbolRefs: CopilotSymbolRefEntry[];
|
||||
}
|
||||
|
||||
// Requests
|
||||
const PreInitializationRequest: RequestType<void, string, void> = new RequestType<void, string, void>('cpptools/preinitialize');
|
||||
const InitializationRequest: RequestType<CppInitializationParams, CppInitializationResult, void> = new RequestType<CppInitializationParams, CppInitializationResult, void>('cpptools/initialize');
|
||||
@@ -630,7 +612,6 @@ const ChangeCppPropertiesRequest: RequestType<CppPropertiesParams, void, void> =
|
||||
const IncludesRequest: RequestType<GetIncludesParams, GetIncludesResult, void> = new RequestType<GetIncludesParams, GetIncludesResult, void>('cpptools/getIncludes');
|
||||
const CppContextRequest: RequestType<TextDocumentIdentifier, ChatContextResult, void> = new RequestType<TextDocumentIdentifier, ChatContextResult, void>('cpptools/getChatContext');
|
||||
const CopilotCompletionContextRequest: RequestType<CopilotCompletionContextParams, CopilotCompletionContextResult, void> = new RequestType<CopilotCompletionContextParams, CopilotCompletionContextResult, void>('cpptools/getCompletionContext');
|
||||
const CopilotRefactorContextRequest: RequestType<CopilotRefactorContextParams, CopilotRefactorContextResult, void> = new RequestType<CopilotRefactorContextParams, CopilotRefactorContextResult, void>('cpptools/getRefactorContext');
|
||||
|
||||
// Notifications to the server
|
||||
const DidOpenNotification: NotificationType<DidOpenTextDocumentParams> = new NotificationType<DidOpenTextDocumentParams>('textDocument/didOpen');
|
||||
@@ -866,7 +847,6 @@ export interface Client {
|
||||
getChatContext(uri: vscode.Uri, token: vscode.CancellationToken): Promise<ChatContextResult>;
|
||||
filesEncodingChanged(filesEncodingChanged: FilesEncodingChanged): void;
|
||||
getCompletionContext(fileName: vscode.Uri, caretOffset: number, featureFlag: CopilotCompletionContextFeatures, maxSnippetCount: number, maxSnippetLength: number, doAggregateSnippets: boolean, token: vscode.CancellationToken): Promise<CopilotCompletionContextResult>;
|
||||
getRefactorContext(file: vscode.Uri, offset: number, token: vscode.CancellationToken): Promise<CopilotRefactorContextResult>
|
||||
}
|
||||
|
||||
export function createClient(workspaceFolder?: vscode.WorkspaceFolder): Client {
|
||||
@@ -909,11 +889,6 @@ export class DefaultClient implements Client {
|
||||
private settingsTracker: SettingsTracker;
|
||||
private loggingLevel: number = 1;
|
||||
private configurationProvider?: string;
|
||||
private mergeConfigurations: boolean = false;
|
||||
private includePath?: string[];
|
||||
private defines?: string[];
|
||||
private forcedInclude?: string[];
|
||||
private browsePath?: string[];
|
||||
private hoverProvider: HoverProvider | undefined;
|
||||
private copilotHoverProvider: CopilotHoverProvider | undefined;
|
||||
private copilotCompletionProvider?: CopilotCompletionContextProvider;
|
||||
@@ -2206,7 +2181,6 @@ export class DefaultClient implements Client {
|
||||
if (configs && configs.length > 0 && configs[0]) {
|
||||
const fileConfiguration: configs.Configuration | undefined = this.configuration.CurrentConfiguration;
|
||||
if (fileConfiguration?.mergeConfigurations) {
|
||||
configs = deepCopy(configs);
|
||||
configs.forEach(config => {
|
||||
if (fileConfiguration.includePath) {
|
||||
fileConfiguration.includePath.forEach(p => {
|
||||
@@ -2389,13 +2363,6 @@ export class DefaultClient implements Client {
|
||||
{ uri: file.toString(), caretOffset, featureFlag, maxSnippetCount, maxSnippetLength, doAggregateSnippets }, token), token);
|
||||
}
|
||||
|
||||
public async getRefactorContext(file: vscode.Uri, offset: number,
|
||||
token: vscode.CancellationToken): Promise<CopilotRefactorContextResult> {
|
||||
await withCancellation(this.ready, token);
|
||||
return DefaultClient.withLspCancellationHandling(
|
||||
() => this.languageClient.sendRequest(CopilotRefactorContextRequest, { uri: file.toString(), offset }, token), token);
|
||||
}
|
||||
|
||||
/**
|
||||
* a Promise that can be awaited to know when it's ok to proceed.
|
||||
*
|
||||
@@ -3172,45 +3139,11 @@ export class DefaultClient implements Client {
|
||||
const configName: string | undefined = configurations[params.currentConfiguration].name ?? "";
|
||||
this.model.activeConfigName.setValueIfActive(configName);
|
||||
const newProvider: string | undefined = this.configuration.CurrentConfigurationProvider;
|
||||
const previousProvider: string | undefined = this.configurationProvider;
|
||||
let updateCustomConfigs: boolean = false;
|
||||
if (!isSameProviderExtensionId(previousProvider, newProvider)) {
|
||||
this.configurationProvider = newProvider;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
if (newProvider !== undefined) {
|
||||
const newMergeConfigurations: boolean = this.configuration.CurrentMergeConfigurations;
|
||||
if (this.mergeConfigurations !== newMergeConfigurations) {
|
||||
this.mergeConfigurations = newMergeConfigurations;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
if (newMergeConfigurations) {
|
||||
const newIncludePath: string[] | undefined = this.configuration.CurrentIncludePath;
|
||||
if (!util.equals(this.includePath, newIncludePath)) {
|
||||
this.includePath = newIncludePath;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
const newDefines: string[] | undefined = this.configuration.CurrentDefines;
|
||||
if (!util.equals(this.defines, newDefines)) {
|
||||
this.defines = newDefines;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
const newForcedInclude: string[] | undefined = this.configuration.CurrentForcedInclude;
|
||||
if (!util.equals(this.forcedInclude, newForcedInclude)) {
|
||||
this.forcedInclude = newForcedInclude;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
const newBrowsePath: string[] | undefined = this.configuration.CurrentBrowsePath;
|
||||
if (!util.equals(this.browsePath, newBrowsePath)) {
|
||||
this.browsePath = newBrowsePath;
|
||||
updateCustomConfigs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updateCustomConfigs) {
|
||||
if (previousProvider) {
|
||||
if (!isSameProviderExtensionId(newProvider, this.configurationProvider)) {
|
||||
if (this.configurationProvider) {
|
||||
void this.clearCustomBrowseConfiguration().catch(logAndReturn.undefined);
|
||||
}
|
||||
this.configurationProvider = newProvider;
|
||||
void this.updateCustomBrowseConfiguration().catch(logAndReturn.undefined);
|
||||
void this.updateCustomConfigurations().catch(logAndReturn.undefined);
|
||||
}
|
||||
@@ -4350,5 +4283,4 @@ class NullClient implements Client {
|
||||
getChatContext(uri: vscode.Uri, token: vscode.CancellationToken): Promise<ChatContextResult> { return Promise.resolve({} as ChatContextResult); }
|
||||
filesEncodingChanged(filesEncodingChanged: FilesEncodingChanged): void { }
|
||||
getCompletionContext(file: vscode.Uri, caretOffset: number, featureFlag: CopilotCompletionContextFeatures, maxSnippetCount: number, maxSnippetLength: number, doAggregateSnippets: boolean, token: vscode.CancellationToken): Promise<CopilotCompletionContextResult> { return Promise.resolve({} as CopilotCompletionContextResult); }
|
||||
getRefactorContext(file: vscode.Uri, offset: number, token: vscode.CancellationToken): Promise<CopilotRefactorContextResult> { return Promise.resolve({} as CopilotRefactorContextResult); }
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export interface Configuration {
|
||||
forcedInclude?: string[];
|
||||
configurationProviderInCppPropertiesJson?: string;
|
||||
configurationProvider?: string;
|
||||
mergeConfigurations?: boolean;
|
||||
mergeConfigurations?: boolean | string;
|
||||
browse?: Browse;
|
||||
recursiveIncludes?: RecursiveIncludes;
|
||||
customConfigurationVariables?: { [key: string]: string };
|
||||
@@ -204,41 +204,6 @@ export class CppProperties {
|
||||
return new CppSettings(this.rootUri).defaultConfigurationProvider;
|
||||
}
|
||||
|
||||
public get CurrentMergeConfigurations(): boolean {
|
||||
if (this.CurrentConfiguration?.mergeConfigurations) {
|
||||
return this.CurrentConfiguration.mergeConfigurations;
|
||||
}
|
||||
return new CppSettings(this.rootUri).defaultMergeConfigurations;
|
||||
}
|
||||
|
||||
public get CurrentIncludePath(): string[] | undefined {
|
||||
if (this.CurrentConfiguration?.includePath) {
|
||||
return this.CurrentConfiguration.includePath;
|
||||
}
|
||||
return new CppSettings(this.rootUri).defaultIncludePath;
|
||||
}
|
||||
|
||||
public get CurrentDefines(): string[] | undefined {
|
||||
if (this.CurrentConfiguration?.defines) {
|
||||
return this.CurrentConfiguration.defines;
|
||||
}
|
||||
return new CppSettings(this.rootUri).defaultDefines;
|
||||
}
|
||||
|
||||
public get CurrentForcedInclude(): string[] | undefined {
|
||||
if (this.CurrentConfiguration?.forcedInclude) {
|
||||
return this.CurrentConfiguration.forcedInclude;
|
||||
}
|
||||
return new CppSettings(this.rootUri).defaultForcedInclude;
|
||||
}
|
||||
|
||||
public get CurrentBrowsePath(): string[] | undefined {
|
||||
if (this.CurrentConfiguration?.browse?.path) {
|
||||
return this.CurrentConfiguration.browse.path;
|
||||
}
|
||||
return new CppSettings(this.rootUri).defaultBrowsePath;
|
||||
}
|
||||
|
||||
public get ConfigurationNames(): string[] | undefined {
|
||||
const result: string[] = [];
|
||||
if (this.configurationJson) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import { TargetPopulation } from 'vscode-tas-client';
|
||||
import * as which from 'which';
|
||||
import { logAndReturn } from '../Utility/Async/returns';
|
||||
import * as util from '../common';
|
||||
import { ProcessReturnType, spawnChildProcess } from '../common-remote-safe';
|
||||
import { modelSelector } from '../constants';
|
||||
import { instrument } from '../instrumentation';
|
||||
import { getCrashCallStacksChannel } from '../logger';
|
||||
@@ -37,7 +38,6 @@ import { NodeType, TreeNode } from './referencesModel';
|
||||
import { CppSettings } from './settings';
|
||||
import { LanguageStatusUI, getUI } from './ui';
|
||||
import { makeLspRange, rangeEquals, showInstallCompilerWalkthrough } from './utils';
|
||||
import { invokeRefactoringAgent } from './refactoring-agent';
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
@@ -168,20 +168,6 @@ export async function activate(): Promise<void> {
|
||||
clients = new ClientCollection();
|
||||
ui = getUI();
|
||||
|
||||
const refactoringAgenthandler: vscode.ChatRequestHandler = async (
|
||||
request: vscode.ChatRequest,
|
||||
context: vscode.ChatContext,
|
||||
stream: vscode.ChatResponseStream,
|
||||
token: vscode.CancellationToken
|
||||
) =>
|
||||
{
|
||||
await invokeRefactoringAgent(request, context, stream, token);
|
||||
return;
|
||||
};
|
||||
|
||||
// Create refactoring agent chat participant.
|
||||
vscode.chat.createChatParticipant('chat.refactoring-agent', refactoringAgenthandler);
|
||||
|
||||
// There may have already been registered CustomConfigurationProviders.
|
||||
// Request for configurations from those providers.
|
||||
clients.forEach(client => {
|
||||
@@ -1259,9 +1245,9 @@ async function handleCrashFileRead(crashDirectory: string, crashFile: string, cr
|
||||
let funcStr: string = line.substring(startPos2, offsetPos);
|
||||
let origFuncStr: string = "";
|
||||
if (filtPath && filtPath.length !== 0) {
|
||||
let ret: util.ProcessReturnType | undefined = await util.spawnChildProcess(filtPath, ["--no-strip-underscore", funcStr], undefined, true).catch(logAndReturn.undefined);
|
||||
let ret: ProcessReturnType | undefined = await spawnChildProcess(filtPath, ["--no-strip-underscore", funcStr], undefined, true).catch(logAndReturn.undefined);
|
||||
if (ret?.output === funcStr) {
|
||||
ret = await util.spawnChildProcess(filtPath, [funcStr], undefined, true).catch(logAndReturn.undefined);
|
||||
ret = await spawnChildProcess(filtPath, [funcStr], undefined, true).catch(logAndReturn.undefined);
|
||||
}
|
||||
if (ret !== undefined && ret.succeeded && !ret.output.startsWith("Could not open input file")) {
|
||||
origFuncStr = funcStr;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,443 +0,0 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { clients } from './extension';
|
||||
const path = require('path'); // Import Node.js path module
|
||||
let suffixPrompt = " Output the changed code along with the rest of the entire input code snippet unchanged. Make sure entire output is formatted correctly";
|
||||
|
||||
interface ErrorDiagnostic {
|
||||
filePath: string;
|
||||
message: string;
|
||||
range: vscode.Range;
|
||||
}
|
||||
|
||||
export interface ContextItem {
|
||||
updatedTextSpan?: string,
|
||||
filePath: string;
|
||||
startLine: number;
|
||||
closestRange?: vscode.Range;
|
||||
}
|
||||
|
||||
async function parseChatResponse(chatResponse: vscode.LanguageModelChatResponse): Promise<string[]> {
|
||||
let accumulatedResponse = '';
|
||||
for await (const fragment of chatResponse.text) {
|
||||
accumulatedResponse += fragment;
|
||||
}
|
||||
|
||||
const codeSnippets: string[] = [];
|
||||
|
||||
// Use a regular expression to extract all code blocks
|
||||
const codeBlockRegex = /```(?:\w+)?\n([\s\S]*?)```/g;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = codeBlockRegex.exec(accumulatedResponse)) !== null) {
|
||||
codeSnippets.push(match[1].trim());
|
||||
}
|
||||
|
||||
if (codeSnippets.length === 0) {
|
||||
// vscode.window.showErrorMessage('No code blocks found in the response.');
|
||||
}
|
||||
|
||||
return codeSnippets;
|
||||
}
|
||||
|
||||
async function validateEdits(): Promise<boolean> {
|
||||
// execute CMake: Build command and check if build output is exit code 0 for pass or 1 for failure.
|
||||
try {
|
||||
// Rescan workspace to get rid of any stuck diagnostics left over.
|
||||
await vscode.commands.executeCommand('C_Cpp.RescanWorkspace');
|
||||
// await vscode.commands.executeCommand('cmake.clean');
|
||||
var buildResult = await vscode.commands.executeCommand('cmake.build');
|
||||
if (buildResult === 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Purposely ignore if, else keywords since Copilot is not always accuraete with those responses.
|
||||
const foldableKeyWords: { [keyWord: string]: boolean } = {
|
||||
"if": true,
|
||||
"else": true,
|
||||
"while": true,
|
||||
"for": true,
|
||||
"switch": true,
|
||||
"case": true,
|
||||
"do": true,
|
||||
};
|
||||
|
||||
async function getClosestFoldingRange(editor: vscode.TextEditor, startLine: number): Promise<vscode.FoldingRange | undefined> {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
const foldingRanges = await vscode.commands.executeCommand<vscode.FoldingRange[]>('vscode.executeFoldingRangeProvider', editor.document.uri);
|
||||
let closestRange: vscode.FoldingRange | undefined;
|
||||
if (foldingRanges && foldingRanges.length > 0) {
|
||||
const selectionStart = startLine;
|
||||
for (const range of foldingRanges) {
|
||||
if (
|
||||
range.start <= selectionStart &&
|
||||
range.end >= selectionStart &&
|
||||
(!closestRange ||
|
||||
(range.start >= closestRange.start && range.end <= closestRange.end))
|
||||
) {
|
||||
const start = editor.document.lineAt(range.start).range.start;
|
||||
const end = editor.document.lineAt(range.end).range.end;
|
||||
var snippetInputRange = new vscode.Range(start, end);
|
||||
var nearestRangeTextSpan = editor.document.getText(snippetInputRange);
|
||||
const startsWithKeyword = Object.keys(foldableKeyWords).some(keyword => nearestRangeTextSpan.trim().startsWith(keyword));
|
||||
// const startsWithBracket = nearestRangeTextSpan.trim().startsWith('{');
|
||||
// if (startsWithBracket) {
|
||||
// closestRange = range;
|
||||
// closestRange.start += 1; // Increment start by 1 if it starts with a bracket to avoid adding bracket into the snippet.
|
||||
// }
|
||||
if (!startsWithKeyword) {
|
||||
// Make sure to avoid foldableKeyWords since Copilot is not always accurate with those.
|
||||
closestRange = range;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestRange;
|
||||
}
|
||||
|
||||
async function fallsWithinPreviouslyEditedRanges(previouslyEditedRanges: { [filePath: string]: vscode.Range[] }, closestRange: vscode.FoldingRange, fileVisiting: string): Promise<boolean> {
|
||||
if (!previouslyEditedRanges[fileVisiting] || !closestRange) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const range of previouslyEditedRanges[fileVisiting]) {
|
||||
if (
|
||||
(closestRange.start >= range.start.line &&
|
||||
closestRange.end <= range.end.line) ||
|
||||
closestRange.start === range.start.line // when a range is updated the end line may change, but the start line remains the same.
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function reiterate(
|
||||
buildError: ErrorDiagnostic,
|
||||
stream: vscode.ChatResponseStream,
|
||||
request: vscode.ChatRequest,
|
||||
context: vscode.ChatContext,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<void> {
|
||||
const document = await vscode.workspace.openTextDocument(buildError.filePath);
|
||||
await vscode.window.showTextDocument(document, { preview: false });
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor || editor.document.languageId !== 'cpp') {
|
||||
return;
|
||||
}
|
||||
var closestRange = await getClosestFoldingRange(editor, buildError.range.start.line);
|
||||
var nearestRangeTextSpan: string = '';
|
||||
|
||||
let snippetInputRange: vscode.Range | undefined = undefined;
|
||||
if (closestRange) {
|
||||
// Store text span of closestRange in nearestRangeTextSpan.
|
||||
const start = editor.document.lineAt(closestRange.start).range.start;
|
||||
const end = editor.document.lineAt(closestRange.end).range.end;
|
||||
snippetInputRange = new vscode.Range(start, end);
|
||||
nearestRangeTextSpan = editor.document.getText(snippetInputRange);
|
||||
}
|
||||
let errorReiterationPrompt = `@refactor The build failed with the following error:\n\n\`\`\`cpp\n${buildError.message}\n\`\`\`\n\Fix the error in the following code snippet.${suffixPrompt}Could it be there are missing #includes?\n\n${nearestRangeTextSpan}`;
|
||||
var messages = [vscode.LanguageModelChatMessage.User(errorReiterationPrompt)];
|
||||
const reiterationResponse = await request.model.sendRequest(messages, {}, token);
|
||||
var reiteratedCodeSnippets = await parseChatResponse(reiterationResponse);
|
||||
|
||||
if (reiteratedCodeSnippets.length > 0) {
|
||||
// Parse for includes.
|
||||
var includeRegex = /#include\s*["<](.*?)[">]/g;
|
||||
var includes: string[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = includeRegex.exec(reiteratedCodeSnippets[reiteratedCodeSnippets.length - 1])) !== null) {
|
||||
includes.push(match[0]);
|
||||
}
|
||||
|
||||
// If any includes exist in the fix responde then insert includes at the top of the file.
|
||||
// Rest of fix response snippet can be ignored for now since the includes may have been the root issue. If not, it will be caught in the next build+reiteration.
|
||||
if (includes.length > 0) {
|
||||
const topOfFileRange = new vscode.Range(0, 0, 0, 0);
|
||||
const includesText = includes.join('\n') + '\n';
|
||||
await applyDynamicEdit(buildError.filePath, topOfFileRange, includesText, stream, undefined, true);
|
||||
}
|
||||
else {
|
||||
await applyDynamicEdit(buildError.filePath, snippetInputRange, reiteratedCodeSnippets[reiteratedCodeSnippets.length - 1], stream, undefined, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function applyDynamicEdit(filePath: string, range: vscode.Range | undefined, updatedTextSpan: string | undefined, stream: vscode.ChatResponseStream, refStartLine: number | undefined, reiterationEdit: boolean): Promise<void> {
|
||||
const document = await vscode.workspace.openTextDocument(filePath);
|
||||
await vscode.window.showTextDocument(document, { preview: false });
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor && editor.document.languageId === 'cpp') {
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor.selection = new vscode.Selection(range.start, range.end);
|
||||
editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
|
||||
|
||||
// Replace the range with updatedTextSpan if it exists
|
||||
if (updatedTextSpan) {
|
||||
const singleEdit = new vscode.WorkspaceEdit();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
singleEdit.replace(editor.document.uri, range, updatedTextSpan);
|
||||
await vscode.workspace.applyEdit(singleEdit);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
await editor.document.save();
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
var startLine: number = range.start.line;
|
||||
if (refStartLine !== undefined) {
|
||||
startLine = refStartLine; // Use the provided start line if it exists.
|
||||
}
|
||||
|
||||
var messageText: string = "Updated code snippet in";
|
||||
if (reiterationEdit) {
|
||||
messageText = "Applied fix in";
|
||||
}
|
||||
stream.markdown(`\n\n${messageText} \`${path.basename(filePath)}\` at line \`${startLine + 1}\``);
|
||||
}
|
||||
|
||||
editor.selection = new vscode.Selection(range.end, range.end);
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called when your extension is activated
|
||||
export async function invokeRefactoringAgent(request: vscode.ChatRequest, context: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken): Promise<void> {
|
||||
const batchableEditCount = 1;
|
||||
|
||||
// Add in the user's message.
|
||||
var usersPrompt: string = request.prompt;
|
||||
const messages = [vscode.LanguageModelChatMessage.User(usersPrompt)];
|
||||
messages.push(vscode.LanguageModelChatMessage.User(suffixPrompt));
|
||||
let primaryFilePath = '';
|
||||
var primaryOffset: number = 1852;
|
||||
const activeEditor = vscode.window.activeTextEditor;
|
||||
if (!activeEditor || activeEditor.selection.isEmpty || activeEditor.document.languageId !== 'cpp') {
|
||||
return;
|
||||
}
|
||||
|
||||
primaryFilePath = activeEditor.document.uri.fsPath;
|
||||
const selectedSymbol = activeEditor.document.getText(activeEditor.selection);
|
||||
const cursorPosition = activeEditor.selection.active;
|
||||
primaryOffset = activeEditor.document.offsetAt(cursorPosition) - 1; // Gets offset from the highlighted symbol, minus 1 to account for the cursor being at the end of the symbol.
|
||||
|
||||
// Get full method range based on the current symbol position.
|
||||
const symbolsResult = await vscode.commands.executeCommand('vscode.executeDocumentSymbolProvider', activeEditor.document.uri);
|
||||
const symbols = Array.isArray(symbolsResult) ? symbolsResult as vscode.DocumentSymbol[] : [];
|
||||
if (!symbols || symbols.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var primaryMethodRange: vscode.Range | undefined = undefined;
|
||||
for (const symbol of symbols) {
|
||||
if (symbol.name.startsWith(selectedSymbol)) {
|
||||
if (symbol.range) {
|
||||
primaryMethodRange = symbol.range;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!primaryMethodRange) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullPrimaryMethodTextSpan = activeEditor.document.getText(primaryMethodRange);
|
||||
messages.push(vscode.LanguageModelChatMessage.User(`\n\n\`\`\`cpp\n${fullPrimaryMethodTextSpan}\n\`\`\``));
|
||||
const initialChatResponse = await request.model.sendRequest(messages, {}, token);
|
||||
|
||||
// Stream the initial chat response to the Copilot Chat UI.
|
||||
for await (const fragment of initialChatResponse.text) {
|
||||
stream.markdown(fragment);
|
||||
}
|
||||
|
||||
var initialChatResponseSnippet = await parseChatResponse(initialChatResponse);
|
||||
if (initialChatResponseSnippet.length > 0) {
|
||||
const updatedTextSpan = initialChatResponseSnippet[0].toString();
|
||||
await applyDynamicEdit(primaryFilePath, primaryMethodRange, updatedTextSpan, stream, undefined, false);
|
||||
}
|
||||
|
||||
stream.progress("\n\nSearching for references in database...");
|
||||
const client = clients.getClientFor(activeEditor.document.uri);
|
||||
if (!client) { throw new Error('No active client found'); }
|
||||
const cancellationToken = new vscode.CancellationTokenSource().token;
|
||||
var symbolRefs = await client.getRefactorContext(activeEditor.document.uri, primaryOffset, cancellationToken);
|
||||
|
||||
// TODO: Later: Ask user if that is the result they expected?
|
||||
// TODO: Later: Generate an example and ask user to confirm if it is correct before applying edits to all refs based on that example.
|
||||
// TODO: Later: Extract the symbol from this prompt or selected text to run FAR on it. Ben M. is working on something similar.
|
||||
|
||||
stream.markdown("\n\nFound \`" + symbolRefs.symbolRefs.length + "\` references in database to update...");
|
||||
var numContextItemsUpdated = symbolRefs.symbolRefs.length;
|
||||
const previouslyEditedRanges: { [filePath: string]: vscode.Range[] } = {};
|
||||
while (symbolRefs.symbolRefs.length > 0) {
|
||||
const numEditsToBeBatched = Math.min(batchableEditCount, symbolRefs.symbolRefs.length);
|
||||
const batchedCodeSnippets = symbolRefs.symbolRefs.splice(-numEditsToBeBatched, numEditsToBeBatched);
|
||||
var generateEditsPrompt: string = `@refactor Now update all of the FillShader::Fill references below to reflect the new functionality of \"${usersPrompt}\".${suffixPrompt}`;
|
||||
var shouldExecuteRequest: boolean = false;
|
||||
var leadingWhiteSpace: string = '';
|
||||
var currentContextItemFilePath: string = '';
|
||||
var currentContextItemStartLine: number = 0;
|
||||
var currentContextItemClosestFoldingRange: vscode.Range | undefined = undefined;
|
||||
for (let i = batchedCodeSnippets.length - 1; i >= 0; i--) {
|
||||
var codeSnippetInput = batchedCodeSnippets[i];
|
||||
const uri = vscode.Uri.parse(codeSnippetInput.uri);
|
||||
currentContextItemFilePath = uri.fsPath.toLowerCase();
|
||||
var editor = vscode.window.activeTextEditor;
|
||||
if (currentContextItemFilePath != editor?.document.uri.fsPath) {
|
||||
const document = await vscode.workspace.openTextDocument(currentContextItemFilePath);
|
||||
await vscode.window.showTextDocument(document, { preview: false });
|
||||
editor = vscode.window.activeTextEditor;
|
||||
}
|
||||
|
||||
if (!editor || editor.document.languageId !== 'cpp') {
|
||||
return;
|
||||
}
|
||||
|
||||
currentContextItemStartLine = editor.document.positionAt(codeSnippetInput.offset).line;
|
||||
if (currentContextItemFilePath.toLowerCase() == primaryFilePath.toLowerCase() && codeSnippetInput.offset == primaryOffset) {
|
||||
continue; // Primary file and offset are already handled in initial user prompt so we can skip that reference now.
|
||||
}
|
||||
|
||||
var closestRange = await getClosestFoldingRange(editor, currentContextItemStartLine);
|
||||
var nearestRangeTextSpan: string = '';
|
||||
|
||||
if (closestRange) {
|
||||
if (!previouslyEditedRanges[currentContextItemFilePath.toLowerCase()]) {
|
||||
previouslyEditedRanges[currentContextItemFilePath.toLowerCase()] = [];
|
||||
}
|
||||
|
||||
const start = editor.document.lineAt(closestRange.start).range.start;
|
||||
const end = editor.document.lineAt(closestRange.end).range.end;
|
||||
const range = new vscode.Range(start, end);
|
||||
if (await fallsWithinPreviouslyEditedRanges(previouslyEditedRanges, closestRange, currentContextItemFilePath.toLowerCase())) {
|
||||
continue; // If already edited this range, then skip it.
|
||||
}
|
||||
|
||||
previouslyEditedRanges[currentContextItemFilePath.toLowerCase()].push(range);
|
||||
}
|
||||
|
||||
if (closestRange) {
|
||||
// Store text span of closestRange in nearestRangeTextSpan.
|
||||
const start = editor.document.lineAt(closestRange.start).range.start;
|
||||
const end = editor.document.lineAt(closestRange.end).range.end;
|
||||
let snippetInputRange = new vscode.Range(start, end);
|
||||
nearestRangeTextSpan = editor.document.getText(snippetInputRange);
|
||||
// trim leading whitespace, indentation, and newlines from nearestRangeTextSpan and store in leadingWhiteSpace.
|
||||
const matchLeadingWhitespace = nearestRangeTextSpan.match(/^\s*/);
|
||||
leadingWhiteSpace = matchLeadingWhitespace ? matchLeadingWhitespace[0] : '';
|
||||
currentContextItemClosestFoldingRange = snippetInputRange;
|
||||
}
|
||||
|
||||
stream.progress("Updating code snippet in " + path.basename(currentContextItemFilePath) + " at line " + (currentContextItemStartLine + 1) + "...");
|
||||
generateEditsPrompt += `\n\n\`\`\`${nearestRangeTextSpan}\`\`\``;
|
||||
var shouldExecuteRequest: boolean = true;
|
||||
}
|
||||
|
||||
if (!shouldExecuteRequest) {
|
||||
// Usually occurs if there was no new range(s) that needed to be edited.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Send dynamic request and get response for each context item.
|
||||
// Check token size before sending the request
|
||||
const messages = [vscode.LanguageModelChatMessage.User(generateEditsPrompt)];
|
||||
|
||||
// TODO: Use tokenCount to determine if request needs to be split into smaller requests instead of batching.
|
||||
// const tokenCount = await request.model.countTokens(generateEditsPrompt);
|
||||
|
||||
const generateEditsChatResponse = await request.model.sendRequest(messages, {}, token);
|
||||
var codeSnippets = await parseChatResponse(generateEditsChatResponse);
|
||||
|
||||
if (codeSnippets.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply the edits one at a time.
|
||||
var codeSnippetResponseCounter = 0;
|
||||
for (let i = batchedCodeSnippets.length - 1; i >= 0; i--) {
|
||||
var updatedTextSpan: string = codeSnippets[codeSnippetResponseCounter].toString();
|
||||
var codeSnippetInput = batchedCodeSnippets[i];
|
||||
await applyDynamicEdit(currentContextItemFilePath, currentContextItemClosestFoldingRange, leadingWhiteSpace + updatedTextSpan, stream, currentContextItemStartLine, false);
|
||||
codeSnippetResponseCounter++;
|
||||
}
|
||||
} // End of while loop foriterating through all FARContextItems.
|
||||
|
||||
|
||||
stream.progress("\n\nBuilding project...");
|
||||
var buildResult = await validateEdits();
|
||||
var reiterationAttemptsCounter: number = 0;
|
||||
while (!buildResult) {
|
||||
if (reiterationAttemptsCounter >= 3) {
|
||||
reiterationAttemptsCounter = 0;
|
||||
// TODO: Ask user to manually fix errors, then click this button to continue the agent.
|
||||
}
|
||||
|
||||
stream.progress("\n\nBuild failed. Agent will attempt to fix error(s)...");
|
||||
const allDiagnostics = vscode.languages.getDiagnostics();
|
||||
let buildErrorsInHeaderFiles: ErrorDiagnostic[] = [];
|
||||
let buildErrorsInSourceFiles: ErrorDiagnostic[] = [];
|
||||
for (const [uri, diagnostics] of allDiagnostics) {
|
||||
for (const diagnostic of diagnostics) {
|
||||
// const normalizedFsPath = uri.fsPath.replace(/\\/g, '/');
|
||||
if (diagnostic.severity === vscode.DiagnosticSeverity.Error && uri.fsPath.toLowerCase() in previouslyEditedRanges) {
|
||||
const isHeader = uri.fsPath.endsWith('.h') || uri.fsPath.endsWith('.hpp');
|
||||
if (isHeader) {
|
||||
const error: ErrorDiagnostic = {
|
||||
filePath: uri.fsPath,
|
||||
message: diagnostic.message,
|
||||
range: diagnostic.range
|
||||
};
|
||||
buildErrorsInHeaderFiles.push(error);
|
||||
}
|
||||
else {
|
||||
const error: ErrorDiagnostic = {
|
||||
filePath: uri.fsPath,
|
||||
message: diagnostic.message,
|
||||
range: diagnostic.range
|
||||
};
|
||||
buildErrorsInSourceFiles.push(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the correct build error to pass in first to reiterate on.
|
||||
let buildErrorToReiterateOn: ErrorDiagnostic | undefined;
|
||||
if (buildErrorsInHeaderFiles.length > 0) {
|
||||
// Iterate through errors from header files first from top to bottom since those are more likely to be the root cause of cascading issues.
|
||||
buildErrorToReiterateOn = buildErrorsInHeaderFiles[0];
|
||||
}
|
||||
else if (buildErrorsInSourceFiles.length > 0) {
|
||||
buildErrorToReiterateOn = buildErrorsInSourceFiles[0];
|
||||
}
|
||||
|
||||
if (buildErrorToReiterateOn) {
|
||||
// Reiterate and build again to validate new edits.
|
||||
await reiterate(buildErrorToReiterateOn, stream, request, context, token);
|
||||
stream.progress("\n\nBuilding project...");
|
||||
buildResult = await validateEdits();
|
||||
reiterationAttemptsCounter++;
|
||||
}
|
||||
} // while loop for validating edits and reiterating.
|
||||
|
||||
// Build has fully succeeded.
|
||||
stream.markdown(`\n\nBuild succeeded. Successfully applied \`${numContextItemsUpdated}\` edits`);
|
||||
|
||||
// Launch the git diff viewer tool to show all the changes made.
|
||||
try {
|
||||
await vscode.commands.executeCommand('workbench.view.scm');
|
||||
} catch (err) {
|
||||
console.error('Failed to open Source Control view:', err);
|
||||
}
|
||||
|
||||
const finalDocToDisplay = await vscode.workspace.openTextDocument(primaryFilePath);
|
||||
await vscode.window.showTextDocument(finalDocToDisplay, { preview: false });
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -440,7 +440,7 @@ export class CppSettings extends Settings {
|
||||
public get defaultCStandard(): string | undefined { return this.getAsStringOrUndefined("default.cStandard"); }
|
||||
public get defaultCppStandard(): string | undefined { return this.getAsStringOrUndefined("default.cppStandard"); }
|
||||
public get defaultConfigurationProvider(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.configurationProvider")); }
|
||||
public get defaultMergeConfigurations(): boolean { return this.getAsBoolean("default.mergeConfigurations"); }
|
||||
public get defaultMergeConfigurations(): boolean | undefined { return this.getAsBooleanOrUndefined("default.mergeConfigurations"); }
|
||||
public get defaultBrowsePath(): string[] | undefined { return this.getArrayOfStringsWithUndefinedDefault("default.browse.path"); }
|
||||
public get defaultDatabaseFilename(): string | undefined { return changeBlankStringToUndefined(this.getAsStringOrUndefined("default.browse.databaseFilename")); }
|
||||
public get defaultLimitSymbolsToIncludedHeaders(): boolean { return this.getAsBoolean("default.browse.limitSymbolsToIncludedHeaders"); }
|
||||
@@ -569,6 +569,21 @@ export class CppSettings extends Settings {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Returns the value of a setting as a boolean with proper type validation and checks for valid enum values while returning an undefined value if necessary.
|
||||
private getAsBooleanOrUndefined(settingName: string): boolean | undefined {
|
||||
const value: any = super.Section.get<any>(settingName);
|
||||
const setting = getRawSetting("C_Cpp." + settingName, true);
|
||||
if (setting.default !== undefined) {
|
||||
console.error(`Default value for ${settingName} is expected to be undefined.`);
|
||||
}
|
||||
|
||||
if (isBoolean(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isValidDefault(isValid: (x: any) => boolean, value: any, allowNull: boolean): boolean {
|
||||
return isValid(value) || (allowNull && value === null);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
import { constants } from 'fs';
|
||||
import { TreeItem } from "vscode";
|
||||
import * as nls from 'vscode-nls';
|
||||
import { extensionContext, ISshConfigHostInfo, pathAccessible } from "../../common";
|
||||
import { extensionContext, ISshConfigHostInfo } from "../../common";
|
||||
import { pathAccessible } from '../../common-remote-safe';
|
||||
import { LabelLeafNode } from "./common";
|
||||
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { getFullHostAddress, getFullHostAddressNoPort, ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
|
||||
import { getFullHostAddress, getFullHostAddressNoPort, ISshHostInfo, ISshLocalForwardInfo } from '../common';
|
||||
import { ProcessReturnType } from '../common-remote-safe';
|
||||
import { defaultSystemInteractor } from './commandInteractors';
|
||||
import { runSshTerminalCommandWithLogin } from './sshCommandRunner';
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { CppSettings } from '../LanguageServer/settings';
|
||||
import { ManualPromise } from '../Utility/Async/manualPromise';
|
||||
import { ISshHostInfo, ProcessReturnType, getNumericLoggingLevel, splitLines, stripEscapeSequences } from '../common';
|
||||
import { ISshHostInfo, getNumericLoggingLevel, splitLines, stripEscapeSequences } from '../common';
|
||||
import { ProcessReturnType } from '../common-remote-safe';
|
||||
import { isWindows } from '../constants';
|
||||
import { getSshChannel } from '../logger';
|
||||
import {
|
||||
|
||||
@@ -43,14 +43,14 @@ export class ManualPromise<T = void> implements Promise<T> {
|
||||
* A method to manually resolve the Promise.
|
||||
*/
|
||||
public resolve: (value?: T | PromiseLike<T> | undefined) => void = (v) => {
|
||||
void v; /* */
|
||||
void v;
|
||||
};
|
||||
|
||||
/**
|
||||
* A method to manually reject the Promise
|
||||
*/
|
||||
public reject: (e: any) => void = (e) => {
|
||||
void e; /* */
|
||||
void e;
|
||||
};
|
||||
|
||||
private state: 'pending' | 'resolved' | 'rejected' = 'pending';
|
||||
|
||||
@@ -0,0 +1,541 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import { fail, ok } from 'node:assert';
|
||||
import { isPromise } from 'node:util/types';
|
||||
import { MessagePort, SHARE_ENV, Worker, isMainThread } from 'node:worker_threads';
|
||||
|
||||
import { ManualPromise } from '../Async/manualPromise';
|
||||
import { finalize } from '../System/finalize';
|
||||
import { is } from '../System/guards';
|
||||
|
||||
/*
|
||||
* SNARE: Simple Nodejs Asynchronous Remoting Engine
|
||||
*
|
||||
* SNARE is an extremely lightweight remoting engine that
|
||||
* allows you to call functions in a nodejs worker thread
|
||||
*
|
||||
* It supports:
|
||||
* - notifications (no response)
|
||||
* - requests (async calls with a response)
|
||||
* - error handling
|
||||
* - simple byref object management
|
||||
*
|
||||
* As long as the values you pass and return are supported by the Structured Clone Algorithm,
|
||||
* (see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)
|
||||
* you can pass them by value to the remote thread.
|
||||
*
|
||||
* If you need to pass an object by reference, you can manually craft a remote object extending
|
||||
* the MarshalByReference.
|
||||
*/
|
||||
|
||||
// Enable typescript disposable types/interfaces.
|
||||
/// <reference lib="esnext.disposable" />
|
||||
|
||||
// Polyfill `Symbol.dispose`
|
||||
(Symbol as any).dispose ??= Symbol("Symbol.dispose");
|
||||
(Symbol as any).asyncDispose ??= Symbol("Symbol.asyncDispose");
|
||||
|
||||
const results = new Map<number, ManualPromise<any>>();
|
||||
let next = 0;
|
||||
|
||||
/**
|
||||
* Internal interface representing a message payload exchanged between threads.
|
||||
* Contains operation names, sequence numbers, and associated data.
|
||||
*/
|
||||
interface Payload {
|
||||
/** The operation to perform (function name or built-in command). */
|
||||
operation: string;
|
||||
|
||||
/** Sequence number for matching requests with responses (0 for notifications). */
|
||||
sequence: number;
|
||||
|
||||
/** Function parameters when sending a request. */
|
||||
parameters?: any[];
|
||||
|
||||
/** Return value when sending a response. */
|
||||
result?: any;
|
||||
|
||||
/** Error information when an operation fails. */
|
||||
error?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a connection to a remote thread that can be used to invoke operations.
|
||||
* Provides methods for making requests, sending notifications, and managing remote objects.
|
||||
*/
|
||||
export interface RemoteConnection {
|
||||
/** The underlying Worker or MessagePort used for communication. */
|
||||
connection: Worker | MessagePort;
|
||||
|
||||
/** Terminates the connection and cleans up resources. */
|
||||
terminate(): void;
|
||||
|
||||
/**
|
||||
* Makes a request to the remote thread and awaits a response.
|
||||
*
|
||||
* @param operation The operation name to invoke.
|
||||
* @param parameters Parameters to pass to the remote operation.
|
||||
* @returns A promise that resolves with the operation result.
|
||||
*/
|
||||
request(operation: string, ...parameters: any[]): Promise<any>;
|
||||
|
||||
/**
|
||||
* Sends a notification to the remote thread (fire and forget).
|
||||
*
|
||||
* @param operation The operation name to invoke.
|
||||
* @param parameters Parameters to pass to the remote operation.
|
||||
*/
|
||||
notify(operation: string, ...parameters: any[]): void;
|
||||
|
||||
/**
|
||||
* Creates a proxy for a remote object.
|
||||
*
|
||||
* @param ctor Constructor for the proxy type.
|
||||
* @param instance Promise of a remote object instance ID.
|
||||
* @returns Promise of a proxy to the remote object.
|
||||
*/
|
||||
marshall<T extends MarshalByReference>(ctor: new (remote: RemoteConnection, instance: number) => T, instance: Promise<number>): Promise<T | undefined>;
|
||||
|
||||
/**
|
||||
* Creates a proxy for a remote object.
|
||||
*
|
||||
* @param ctor Constructor for the proxy type.
|
||||
* @param instance A remote object instance ID.
|
||||
* @returns A proxy to the remote object.
|
||||
*/
|
||||
marshall<T extends MarshalByReference>(ctor: new (remote: RemoteConnection, instance: number) => T, instance: number): T | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type representing a set of functions that can be called remotely.
|
||||
* The endpoint serves as the API that can be invoked from the other thread.
|
||||
*/
|
||||
export type Endpoint = Record<string, (...args: any[]) => any>;
|
||||
|
||||
/** SNARE: Simple Nodejs Asynchronous Remoting Engine */
|
||||
export function startRemoting(connection: Worker | MessagePort, endpoint: Endpoint): RemoteConnection { // Main thread needs to wait for the connection to be ready before doing anything.
|
||||
// The worker threads don't have an 'online' event (the port is already connected).
|
||||
let ready = isMainThread ? new ManualPromise<undefined>() : undefined;
|
||||
connection.on('online', () => ready?.resolve());
|
||||
|
||||
function postResult(sequence: number, retVal: any) {
|
||||
if (is.promise(retVal)) {
|
||||
retVal.then(
|
||||
(result) => connection.postMessage({ operation: "#result", sequence: sequence, result: sanitize(result) }),
|
||||
(error) => connection.postMessage({ operation: "#error", sequence: sequence, error: sanitize(error) })); // Call failed, threw an error.
|
||||
return;
|
||||
}
|
||||
|
||||
connection.postMessage({ operation: "#result", sequence: sequence, result: sanitize(retVal) });
|
||||
}
|
||||
|
||||
// Handle messages from the remote thread.
|
||||
connection.on('message', ({ operation, sequence, parameters, result, error }: Payload) => {
|
||||
// Unwrap incoming parameters that are byref or function references.
|
||||
parameters = parameters?.map(unwrapValue) || []; // Switch based on the operation type.
|
||||
switch (operation) {
|
||||
// If the message is an error, reject the promise.
|
||||
case '#error':
|
||||
results.get(sequence)?.reject(error);
|
||||
return results.delete(sequence);
|
||||
|
||||
// If the message is a result, resolve the promise.
|
||||
case '#result':
|
||||
results.get(sequence)?.resolve(unwrapValue(result));
|
||||
return results.delete(sequence);
|
||||
|
||||
// Unref is a built-in function to release a byref object.
|
||||
case '#unref':
|
||||
unref(parameters[0]);
|
||||
return;
|
||||
|
||||
// Callback is a built-in function to call a callback function.
|
||||
case '#callback':
|
||||
try {
|
||||
postResult(sequence, getByRef(parameters[0])(...parameters.slice(1)));
|
||||
} catch (err) {
|
||||
connection.postMessage({ operation: "#error", sequence, error: sanitize(err) });
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Otherwise, we're going to call a remote function.
|
||||
|
||||
// Get the sequence number for the result (0 indicates that it's a notification).
|
||||
try {
|
||||
// Call the endpoint.
|
||||
if (!is.function(endpoint[operation])) {
|
||||
throw new Error(`Attempting to call unknown remote method on endpoint: ${operation}`);
|
||||
}
|
||||
|
||||
const retVal = endpoint[operation](...parameters);
|
||||
if (sequence) {
|
||||
// Is it a request? If so, post the result.
|
||||
postResult(sequence, retVal);
|
||||
}
|
||||
} catch (err) {
|
||||
if (sequence) {
|
||||
connection.postMessage({ operation: "#error", sequence, error: sanitize(err) }); // Call failed, threw an error.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const remote = {
|
||||
connection,
|
||||
request: async (operation: string, ...parameters: any[]) => {
|
||||
let result: ManualPromise<any> | undefined;
|
||||
let payload: Payload | undefined;
|
||||
try {
|
||||
if (ready) {
|
||||
await ready;
|
||||
}
|
||||
result = new ManualPromise<any>();
|
||||
payload = { operation, parameters: sanitizeParameters(parameters), sequence: ++next };
|
||||
results.set(payload.sequence, result);
|
||||
|
||||
connection.postMessage(payload);
|
||||
} catch (err) {
|
||||
// If we can't post the message, then we need to reject the promise.
|
||||
if (payload) {
|
||||
results.delete(payload.sequence);
|
||||
}
|
||||
if (result) {
|
||||
result.reject(err);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
notify: (operation: string, ...parameters: any[]) => {
|
||||
try {
|
||||
if (ready) {
|
||||
void ready.then(() => {
|
||||
ready = undefined;
|
||||
connection.postMessage({ operation, parameters: sanitizeParameters(parameters), sequence: 0 });
|
||||
});
|
||||
} else {
|
||||
connection.postMessage({ operation, parameters: sanitizeParameters(parameters), sequence: 0 });
|
||||
}
|
||||
} catch (err: any) {
|
||||
// Ignore the errors on notifications, as they are not expected to return a result.
|
||||
}
|
||||
},
|
||||
marshall: <T extends MarshalByReference>(ctor: new (remote: RemoteConnection, instance: number) => T, instance: number | Promise<number>) => instance ? is.promise(instance) ? instance.then(i => new ctor(remote, i)) : new ctor(remote, instance) : undefined,
|
||||
terminate: () => isMainThread ? finalize(connection) : undefined
|
||||
};
|
||||
|
||||
function unwrapValue(value: any) {
|
||||
return isReference(value) ?
|
||||
value.kind === 'function' ? (...args: any[]) => remote.request('#callback', value.identity, ...args) : // If it is a referenced function, we'll create a wrapper function to call it.
|
||||
getByRef(value.identity) : // If it is a referenced object, we'll get the object.
|
||||
value;
|
||||
}
|
||||
connection.on('close', () => { // Disable the remote connection interface so that it can't be used anymore.
|
||||
const r = remote as any;
|
||||
r.request = r.marshal = async () => { };
|
||||
r.notify = r.terminate = () => { };
|
||||
r.connection = undefined;
|
||||
|
||||
// The connection is closed, so reject all pending requests.
|
||||
for (const result of results.values()) {
|
||||
try {
|
||||
result.reject('Connection closed');
|
||||
} catch {
|
||||
// Ignore errors when rejecting.
|
||||
}
|
||||
}
|
||||
// Clear the results map.
|
||||
results.clear();
|
||||
|
||||
// Clear out any byref objects.
|
||||
identityIndex.length = 0;
|
||||
instanceIndex.clear();
|
||||
|
||||
});
|
||||
|
||||
return remote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the current code is running on the main thread.
|
||||
*
|
||||
* @throws If not running on the main thread.
|
||||
*/
|
||||
export function ensureIsMainThread() {
|
||||
ok(isMainThread, "Remoting: Failed to start host thread responder - not on main thread");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new worker thread.
|
||||
*
|
||||
* @param workerPath Path to the worker script file.
|
||||
* @returns A new Worker instance with stderr, stdout, and environment variables shared.
|
||||
*/
|
||||
export function startWorker(workerPath: string) {
|
||||
return new Worker(workerPath, { stderr: true, stdout: true, env: SHARE_ENV });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that is safe to go over the connection.
|
||||
*
|
||||
* This includes:
|
||||
* - functions (which are marshalled as references)
|
||||
* - MarshalByReference objects (which are marshalled as references)
|
||||
*
|
||||
* Otherwise, we do a deep filtered clone of the object.
|
||||
*
|
||||
* @param value The value to sanitize
|
||||
* @returns A sanitized version of the value that can be safely sent over the connection
|
||||
*/
|
||||
function sanitize(value: any) {
|
||||
return is.function(value) || value instanceof MarshalByReference ? ref(value) : filteredClone(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes an array of parameters for remoting.
|
||||
*
|
||||
* @param parameters Array of parameter values to sanitize.
|
||||
* @returns Array of sanitized parameters.
|
||||
*/
|
||||
function sanitizeParameters(parameters: any[]) {
|
||||
return parameters.map(sanitize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard to check if a value is a reference object.
|
||||
* References are objects with identity and kind properties.
|
||||
*
|
||||
* @param p The value to check.
|
||||
* @returns True if the value is a reference object.
|
||||
*/
|
||||
function isReference(p: any): p is Reference {
|
||||
return is.object(p) && 'identity' in p && 'kind' in p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface representing a reference to an object or function in another thread.
|
||||
* References are used to represent values that cannot be cloned.
|
||||
*/
|
||||
interface Reference {
|
||||
/** Unique identifier for the referenced object. */
|
||||
identity: number;
|
||||
|
||||
/** The kind of reference - either an object or function. */
|
||||
kind: 'object' | 'function';
|
||||
}
|
||||
|
||||
/** Array of objects indexed by their identity number. */
|
||||
const identityIndex = new Array<any>();
|
||||
|
||||
/** Maps objects to their [identity, reference count] pairs. */
|
||||
const instanceIndex = new Map<any, [number, number]>();
|
||||
|
||||
/**
|
||||
* Gets an object by its reference identity.
|
||||
*
|
||||
* @param identity The unique identifier of the referenced object.
|
||||
* @returns The referenced object.
|
||||
* @throws If the identity doesn't correspond to a valid referenced object.
|
||||
*/
|
||||
export function getByRef<T = any>(identity: number): T {
|
||||
return identityIndex[identity] ?? fail(`Invalid ${identity} for ByRef object`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a reference to an object or function that can be sent to another thread.
|
||||
*
|
||||
* @param instance A Promise resolving to the object to reference.
|
||||
* @returns A Promise resolving to a reference object, or undefined if the value can't be referenced.
|
||||
*/
|
||||
export function ref(instance: Promise<any>): Promise<Reference | undefined>;
|
||||
|
||||
/**
|
||||
* Creates a reference to an object or function that can be sent to another thread.
|
||||
*
|
||||
* @param instance The object to reference.
|
||||
* @returns A reference object, or undefined if the value can't be referenced.
|
||||
*/
|
||||
export function ref(instance: any): Reference | undefined;
|
||||
|
||||
/**
|
||||
* Implementation of the ref function handling both synchronous and asynchronous cases.
|
||||
*
|
||||
* @param instance The object or Promise to reference.
|
||||
* @returns A reference object, a Promise to a reference object, or undefined.
|
||||
*/
|
||||
export function ref(instance: any | Promise<any>): Reference | undefined | Promise<Reference | undefined> {
|
||||
if (is.promise(instance)) {
|
||||
return instance.then(ref);
|
||||
}
|
||||
|
||||
const kind = typeof instance;
|
||||
switch (kind) {
|
||||
case 'object':
|
||||
case 'function':
|
||||
// Lookup the instance in the index.
|
||||
const [identity, refcount] = instanceIndex.get(instance) ?? [++next, 0];
|
||||
|
||||
// If refcount is zero, then we need to add it to the index.
|
||||
if (!refcount) {
|
||||
identityIndex[identity] = instance;
|
||||
}
|
||||
|
||||
// Increment the refcount.
|
||||
instanceIndex.set(instance, [identity, refcount + 1]);
|
||||
|
||||
// Return the identity.
|
||||
return { identity, kind };
|
||||
}
|
||||
// Otherwise, we can't ref it.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the reference count for a referenced object.
|
||||
* If the reference count reaches zero, the object is removed from the index and finalized.
|
||||
*
|
||||
* @param identity The identity of the referenced object to unreference.
|
||||
*/
|
||||
export function unref(identity: number) {
|
||||
// Lookup the instance.
|
||||
const instance = getByRef(identity);
|
||||
if (instance) {
|
||||
// Decrement the refcount.
|
||||
const [identity, refcount] = instanceIndex.get(instance) ?? [0, 0];
|
||||
if (refcount > 1) {
|
||||
// Reduce the refcount by one.
|
||||
return instanceIndex.set(instance, [identity, refcount - 1]);
|
||||
}
|
||||
// It's the last reference, so remove it from the index.
|
||||
identityIndex[identity] = undefined;
|
||||
instanceIndex.delete(instance);
|
||||
finalize(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for objects that are passed by reference to a remote thread.
|
||||
*
|
||||
* All MarshalByReference wrappers are references to an object that lives in the remote thread.
|
||||
* It is important to call .dispose() when you are done with it, as this enables the remote
|
||||
* thread to release the object and free up resources.
|
||||
*/
|
||||
export class MarshalByReference implements Disposable {
|
||||
constructor(protected remote: RemoteConnection, protected instance: number) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This disposes the ByRef object and notifies the remote thread to reduce the refcount,
|
||||
* which would dispose the remote object if it was the last reference.
|
||||
*/
|
||||
[Symbol.dispose]() {
|
||||
void this.remote.notify('#unref', this.instance);
|
||||
this.instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered structured clone of an object that can be safely transmitted between threads.
|
||||
*
|
||||
* This recursively drops items that are:
|
||||
* - undefined
|
||||
* - functions
|
||||
* - symbols
|
||||
* - promises
|
||||
* - asyncIterators
|
||||
*
|
||||
* It should correctly handle:
|
||||
* - circular references by keeping a map of references that have already been cloned
|
||||
* - arrays, sets, maps, and iterables (iterables are converted to arrays)
|
||||
* - dates, regex, errors, and buffers by returning them directly
|
||||
* - vscode.Uri by converting it to a string
|
||||
* - all other objects by recursively cloning them
|
||||
*
|
||||
* @param data The data to clone.
|
||||
* @param references Map of already cloned objects (for handling circular references).
|
||||
* @param options Additional options for controlling the cloning process.
|
||||
* @returns A filtered clone of the input data suitable for transmission.
|
||||
*/
|
||||
export function filteredClone(data: any, references = new Map<any, any>(), options?: { breakCircular?: boolean }): any {
|
||||
// Fast checks for null and undefined.
|
||||
if (data === undefined || data === null) {
|
||||
return undefined;
|
||||
}
|
||||
if (references.has(data)) {
|
||||
return references.get(data);
|
||||
}
|
||||
|
||||
switch (typeof data) {
|
||||
case 'symbol':
|
||||
case 'function':
|
||||
return undefined;
|
||||
|
||||
case 'object':
|
||||
if (options?.breakCircular) {
|
||||
references.set(data, undefined);
|
||||
}
|
||||
if (isPromise(data) || typeof data.then === 'function' || typeof data[Symbol.asyncIterator] === 'function') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (data instanceof Set) {
|
||||
const result = new Set();
|
||||
references.set(data, result);
|
||||
for (const item of data) {
|
||||
result.add(filteredClone(item, references, options));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (data instanceof Map) {
|
||||
const result = new Map();
|
||||
references.set(data, result);
|
||||
for (const [key, value] of data) {
|
||||
const k = filteredClone(key, references, options);
|
||||
if (k !== undefined) {
|
||||
result.set(k, filteredClone(value, references, options));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (data[Symbol.iterator]) {
|
||||
const result: any[] = [];
|
||||
references.set(data, result);
|
||||
for (const item of data) {
|
||||
result.push(filteredClone(item, references, options));
|
||||
} return result;
|
||||
}
|
||||
|
||||
// These are ok to return the value directly.
|
||||
if (data instanceof Date || data instanceof RegExp || data instanceof Error || data instanceof Buffer) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Special case for vscode.Uri - we'll just return the string.
|
||||
if ('path' in data && 'scheme' in data && 'authority' in data && 'fragment' in data) {
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
// Everything else is an object that we'll recursively clone.
|
||||
const result: any = {};
|
||||
if (!options?.breakCircular) {
|
||||
references.set(data, result);
|
||||
}
|
||||
|
||||
for (const key in data) {
|
||||
if (key.startsWith('_')) {
|
||||
continue;
|
||||
}
|
||||
const v = filteredClone(data[key], references, options);
|
||||
if (v !== undefined) {
|
||||
// Drop undefined values entirely.
|
||||
result[key] = v;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,463 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
/** @file The functions here are safe to call from a worker thread or the main thread. */
|
||||
|
||||
import { ChildProcess, spawn } from 'node:child_process';
|
||||
import { access, constants, readdir, stat } from 'node:fs/promises';
|
||||
import { basename, delimiter, dirname, isAbsolute, normalize, resolve } from 'node:path';
|
||||
import { isMainThread } from 'node:worker_threads';
|
||||
|
||||
import { isWindows } from './constants';
|
||||
import { ManualPromise } from './Utility/Async/manualPromise';
|
||||
import { RemoteConnection } from './Utility/Remoting/snare';
|
||||
import { is } from './Utility/System/guards';
|
||||
|
||||
/**
|
||||
* @file These are vscode-extension functions that have been wrapped
|
||||
* so that they can be safely called from the main thread or worker threads.
|
||||
*
|
||||
* If this is imported in a module running in a worker thread, the worker
|
||||
* thread must call `initialize(remote)` with a valid `RemoteConnection`
|
||||
* instance before using these functions, otherwise they will be a no-op.
|
||||
*/
|
||||
|
||||
let remoteConnection: RemoteConnection | undefined;
|
||||
|
||||
// In the main thread, grab the logger and localize functions directly.
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const logFn = isMainThread ? require('./logger').log : () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const noteFn = isMainThread ? require('./logger').note : () => { };
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const localizeFn = isMainThread ? require('./localization').localize : (info: { key: string; comment: string[] } | string, message: string, ...args: (string | number | boolean | undefined | null)[]) => message.replace(/\{(\d+)\}/g, (_, index) => String(args[Number(index)] ?? 'undefined'));
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const getOutputChannelLoggerFn = isMainThread ? require('./logger').getOutputChannelLogger : () => undefined;
|
||||
|
||||
/**
|
||||
* Used when this is imported in a module running in a worker thread.
|
||||
*
|
||||
* This ensures that the remote connection is set up before any of the
|
||||
* functions are called. If this is not called, the functions will be no-ops.
|
||||
*
|
||||
* @param remote The remote connection instance to use.
|
||||
*/
|
||||
export function initialize(remote: RemoteConnection | undefined): void {
|
||||
if (!isMainThread) {
|
||||
remoteConnection = remote;
|
||||
}
|
||||
}
|
||||
|
||||
/** Appends the message to the log file.
|
||||
*
|
||||
* @param message The message to log. If this is a Promise, it will be resolved and logged.
|
||||
*/
|
||||
export function log(message: string | Promise<string>) {
|
||||
if (is.promise(message)) {
|
||||
void message.then(log);
|
||||
return;
|
||||
}
|
||||
return isMainThread ? logFn(message) : remoteConnection?.notify('log', message);
|
||||
}
|
||||
|
||||
/** Sets a transient message in the vscode status bar.
|
||||
*
|
||||
* The mesage will be displayed for a short time and then cleared.
|
||||
* @param message The message to display.
|
||||
*/
|
||||
export function note(message: string | Promise<string>) {
|
||||
if (is.promise(message)) {
|
||||
void message.then(note);
|
||||
return;
|
||||
}
|
||||
return isMainThread ? noteFn(message) : remoteConnection?.notify('note', message);
|
||||
}
|
||||
|
||||
/** Localizes a message.
|
||||
*
|
||||
* This function is used to localize a message in the vscode extension.
|
||||
*
|
||||
* @param info The localization information.
|
||||
* @param message The message to localize.
|
||||
* @param args The arguments for the message.
|
||||
*/
|
||||
export const localize: AsyncLocalizeFunc = (infoOrKey, message, ...args) => {
|
||||
if (isMainThread) {
|
||||
if (typeof infoOrKey === 'string') {
|
||||
return localizeFn(infoOrKey, message, ...args);
|
||||
} else {
|
||||
return localizeFn(infoOrKey as LocalizeInfo, message, ...args);
|
||||
}
|
||||
}
|
||||
return remoteConnection?.request('localize', infoOrKey, message, ...args) ??
|
||||
message.replace(/\{(\d+)\}/g, (_, index) => String(args[Number(index)] ?? 'undefined'));
|
||||
};
|
||||
|
||||
export function appendLineAtLevel(level: number, message: string | Promise<string>): void {
|
||||
if (is.promise(message)) {
|
||||
void message.then((msg) => appendLineAtLevel(level, msg));
|
||||
return;
|
||||
}
|
||||
if (isMainThread) {
|
||||
getOutputChannelLoggerFn()?.appendLineAtLevel(level, message);
|
||||
} else {
|
||||
remoteConnection?.notify('appendLineAtLevel', level, message);
|
||||
}
|
||||
}
|
||||
|
||||
export function appendLine(message: string | Promise<string>): void {
|
||||
if (is.promise(message)) {
|
||||
void message.then(appendLine);
|
||||
return;
|
||||
}
|
||||
if (isMainThread) {
|
||||
getOutputChannelLoggerFn()?.appendLine(message);
|
||||
} else {
|
||||
remoteConnection?.notify('appendLine', message);
|
||||
}
|
||||
}
|
||||
|
||||
/** When on Windows, ensures that the given executable name ends in an '.exe'.
|
||||
* @param executableName The name of the executable to check.
|
||||
* @returns The executable name with .exe appended if on Windows and the name does not already end in an '.exe'.
|
||||
*/
|
||||
export function executableName(executableName: string) {
|
||||
return isWindows && !/\.exe$/i.test(executableName) ? `${executableName}.exe` : executableName;
|
||||
}
|
||||
/**
|
||||
* Represents a type which can release resources, such
|
||||
* as event listening or a timer.
|
||||
*
|
||||
* (This is similar to the `Disposable` interface in VS Code.)
|
||||
*/
|
||||
export interface Disposable {
|
||||
/**
|
||||
* Dispose this object.
|
||||
*/
|
||||
dispose(): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a typed event.
|
||||
*
|
||||
* A function that represents an event to which you subscribe by calling it with
|
||||
* a listener function as argument.
|
||||
*
|
||||
* (This is similar to the `Event` interface in VS Code.)
|
||||
*
|
||||
* @example
|
||||
* item.onDidChange(function(event) { console.log("Event happened: " + event); });
|
||||
*
|
||||
* @param listener The listener function will be called when the event happens.
|
||||
* @param thisArgs The `this`-argument which will be used when calling the event listener.
|
||||
* @param disposables An array to which a {@link Disposable} will be added.
|
||||
* @returns A disposable which unsubscribes the event listener.
|
||||
*/
|
||||
export type Event<T> = (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]) => Disposable;
|
||||
|
||||
/** The key for a localize call.
|
||||
* This interface provides structure for localization information.
|
||||
*/
|
||||
export interface LocalizeInfo {
|
||||
/** The localization key identifier. */
|
||||
key: string;
|
||||
/** Comments providing context for translators. */
|
||||
comment: string[];
|
||||
}
|
||||
|
||||
/** The type for the localize function for string localization, but can work asynchronously (can be called via remoting). */
|
||||
export type AsyncLocalizeFunc = (
|
||||
infoOrKey: LocalizeInfo | string,
|
||||
message: string,
|
||||
...args: (string | number | boolean | undefined | null)[]
|
||||
) => string | Promise<string>;
|
||||
|
||||
/**
|
||||
* A cancellation token is passed to an asynchronous or long running
|
||||
* operation to request cancellation, like cancelling a request
|
||||
* for completion items because the user continued to type.
|
||||
*
|
||||
* (This is similar to the `CancellationToken` interface in VS Code.)
|
||||
*
|
||||
* To get an instance of a `CancellationToken` use a
|
||||
* {@link CancellationTokenSource}.
|
||||
*/
|
||||
export interface CancellationToken {
|
||||
|
||||
/**
|
||||
* Is `true` when the token has been cancelled, `false` otherwise.
|
||||
*/
|
||||
isCancellationRequested: boolean;
|
||||
|
||||
/**
|
||||
* An {@link Event} which fires upon cancellation.
|
||||
*/
|
||||
onCancellationRequested: Event<any>;
|
||||
}
|
||||
|
||||
/** Searches the PATH for a given executable program, using an optional predicate to control if the candidate is accepted.
|
||||
* @param filename The name of the executable to search for (string or a regular expression).
|
||||
* @param predicate A function that takes a binary file path and returns a boolean indicating whether to include it in the results.
|
||||
* @returns A promise that resolves to the full path of the executable if found, or undefined if not found.
|
||||
*/
|
||||
export async function findInPath(filename: string | RegExp, predicate?: (binary: string) => Promise<boolean>): Promise<string | undefined> {
|
||||
return searchFolders(process.env["PATH"]?.split(delimiter) || [], filename, predicate, 0);
|
||||
}
|
||||
|
||||
/** Checks if a path is accessible with the specified permissions.
|
||||
*
|
||||
* @param filePath The path to check for accessibility.
|
||||
* @param permission fs file access constants: https://nodejs.org/api/fs.html#file-access-constants
|
||||
* @returns A promise that resolves to true if the path is accessible with the specified permissions, false otherwise.
|
||||
*/
|
||||
export async function pathAccessible(filePath: string, permission: number = constants.F_OK): Promise<boolean> {
|
||||
return filePath ? access(filePath, permission).then(() => true).catch(() => false) : false;
|
||||
}
|
||||
|
||||
/** Checks if a file is executable by the current user.
|
||||
* @param file The path to the file to check.
|
||||
* @returns A promise that resolves to true if the file is executable, false otherwise.
|
||||
*/
|
||||
export function isExecutable(file: string): Promise<boolean> {
|
||||
return pathAccessible(file, constants.X_OK);
|
||||
}
|
||||
|
||||
/** Represents the result of spawning a child process.
|
||||
* Contains information about the process exit code, standard output and error output.
|
||||
*/
|
||||
export interface ProcessReturnType {
|
||||
succeeded: boolean;
|
||||
exitCode?: number | NodeJS.Signals;
|
||||
output: string;
|
||||
outputError: string;
|
||||
}
|
||||
|
||||
/** Escapes special characters in a string to make it safe for use in a regular expression.
|
||||
* @param str The string to escape.
|
||||
* @returns A new string with all special regex characters escaped with backslashes.
|
||||
*/
|
||||
export function escapeStringForRegex(str: string): string {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
|
||||
}
|
||||
|
||||
/** Spawns a child process and returns its output.
|
||||
* @param program The path to the program to execute.
|
||||
* @param args The command line arguments to pass to the program.
|
||||
* @param localizer The function to use for localization.
|
||||
* @param continueOn Optional string pattern that, when found in stdout, will cause the process to be considered complete before it exits.
|
||||
* @param skipLogging Optional flag to skip logging process output.
|
||||
* @param cancellationToken Optional token that can be used to cancel the process.
|
||||
* @returns A promise that resolves to an object containing process output and exit information.
|
||||
*/
|
||||
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, skipLogging?: boolean, cancellationToken?: CancellationToken): Promise<ProcessReturnType> {
|
||||
// Do not use CppSettings to avoid circular require()
|
||||
if (skipLogging === undefined || !skipLogging) {
|
||||
appendLineAtLevel(5, `$ ${program} ${args.join(' ')}`);
|
||||
}
|
||||
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, skipLogging, cancellationToken);
|
||||
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
|
||||
if (programOutput.exitCode) {
|
||||
return { succeeded: false, exitCode, outputError: programOutput.stderr, output: programOutput.stderr || programOutput.stdout || await 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 = await localize('process.succeeded', 'Process executed successfully.');
|
||||
}
|
||||
return { succeeded: true, exitCode, outputError: programOutput.stderr, output: stdout };
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents the output of a child process spawned by the extension.
|
||||
* Contains the raw output streams and exit code information.
|
||||
*/
|
||||
interface ProcessOutput {
|
||||
/** The exit code of the process, or the signal that terminated it. */
|
||||
exitCode?: number | NodeJS.Signals;
|
||||
/** The standard output of the process as a string. */
|
||||
stdout: string;
|
||||
/** The standard error output of the process as a string. */
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
/** Implementation of the process spawning functionality.
|
||||
* This function handles the actual creation and management of the child process.
|
||||
*
|
||||
* @param program The path to the program to execute.
|
||||
* @param args The command line arguments to pass to the program.
|
||||
* @param continueOn Optional string pattern that, when found in stdout, will cause the process to be considered complete before it exits.
|
||||
* @param skipLogging Optional flag to skip logging process output.
|
||||
* @param cancellationToken Optional token that can be used to cancel the process.
|
||||
* @returns A promise that resolves to the process output, including stdout, stderr and exit code.
|
||||
*/
|
||||
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, skipLogging?: boolean, cancellationToken?: CancellationToken): Promise<ProcessOutput> {
|
||||
const result = new ManualPromise<ProcessOutput>();
|
||||
|
||||
let proc: ChildProcess;
|
||||
if (await isExecutable(program)) {
|
||||
proc = spawn(`.${isWindows ? '\\' : '/'}${basename(program)}`, args, { shell: true, cwd: dirname(program) });
|
||||
} else {
|
||||
proc = spawn(program, args, { shell: true });
|
||||
}
|
||||
|
||||
const cancellationTokenListener: Disposable | undefined = cancellationToken?.onCancellationRequested(() => {
|
||||
|
||||
appendLine(localize('killing.process', 'Killing process {0}', program));
|
||||
|
||||
proc.kill();
|
||||
});
|
||||
|
||||
/** Cleans up resources associated with the process.
|
||||
* Removes all event listeners and disposes the cancellation token listener.
|
||||
*/
|
||||
const clean = () => {
|
||||
proc.removeAllListeners();
|
||||
if (cancellationTokenListener) {
|
||||
cancellationTokenListener.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
let stdout: string = '';
|
||||
let stderr: string = '';
|
||||
if (proc.stdout) {
|
||||
proc.stdout.on('data', data => {
|
||||
const str: string = data.toString();
|
||||
if (skipLogging === undefined || !skipLogging) {
|
||||
appendLineAtLevel(1, str);
|
||||
}
|
||||
stdout += str;
|
||||
if (continueOn) {
|
||||
const continueOnReg: string = escapeStringForRegex(continueOn);
|
||||
if (stdout.search(continueOnReg)) {
|
||||
result.resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', data => stderr += data.toString());
|
||||
}
|
||||
proc.on('close', (code, signal) => {
|
||||
clean();
|
||||
result.resolve({ exitCode: code || signal || undefined, stdout: stdout.trim(), stderr: stderr.trim() });
|
||||
});
|
||||
proc.on('error', error => {
|
||||
clean();
|
||||
result.reject(error);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns true if the path is a folder.
|
||||
*
|
||||
* @param path The path to check.
|
||||
* @returns A promise that resolves to true if the path is a folder, false otherwise.
|
||||
*/
|
||||
export async function isFolder(path: string) {
|
||||
try {
|
||||
return (await stat(path)).isDirectory();
|
||||
} catch {
|
||||
// Ignore errors, if we can't access the path, it's not a folder.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function searchFolders(folders: string[], filename: string | RegExp, predicate?: (binary: string) => Promise<boolean>, maxDepth = 4, options: { result?: string; visited?: Set<string>; topDepth?: number } = {}): Promise<string | undefined> {
|
||||
options.topDepth ??= maxDepth;
|
||||
options.visited ??= new Set<string>();
|
||||
const nameMatches = is.string(filename) ? (item: string) => item === filename : (item: string) => filename.test(item);
|
||||
|
||||
for (let folder of folders) {
|
||||
// If the result was reached from anything going on asynchronously, we can stop searching.
|
||||
if (options.result) {
|
||||
return options.result;
|
||||
}
|
||||
|
||||
// Ensure that the folder is normalized and absolute.
|
||||
folder = normalize(folder);
|
||||
if (!isAbsolute(folder)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we've been here before, skip this folder.
|
||||
if (options.visited.has(folder) || !await isFolder(folder)) {
|
||||
continue;
|
||||
}
|
||||
// Mark the folder as visited to avoid infinite loops.
|
||||
options.visited.add(folder);
|
||||
|
||||
// We can do a quick check in the folder when the filename is a string.
|
||||
if (is.string(filename)) {
|
||||
const fullPath = resolve(folder, filename);
|
||||
if (predicate ? await predicate(fullPath) : true) {
|
||||
return options.result ??= fullPath;
|
||||
}
|
||||
|
||||
// And, if maxDepth is 0, we don't need to bother searching subfolders at all.
|
||||
if (maxDepth === 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const subfolders = new Array<string>();
|
||||
|
||||
// Parallelize the search for files in the folder.
|
||||
await Promise.all((await readdir(folder).catch(() => [])).map(async (item) => {
|
||||
|
||||
// If we already found a match, stop searching.
|
||||
if (options.result) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not going to search subfolders, we can skip this item if it doesn't match the filename.
|
||||
if (maxDepth === 0 && !nameMatches(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fullPath: string = resolve(folder, item);
|
||||
|
||||
const stats = await stat(fullPath).catch(() => undefined);
|
||||
if (!stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
// If anything else found anything, we can stop searching.
|
||||
case !!options.result:
|
||||
return;
|
||||
|
||||
// If the path is a symlink, skip it entirely.
|
||||
case stats.isSymbolicLink():
|
||||
// If it's a symlink, we can't follow it, so skip it.
|
||||
log(`Skipping symlink: ${fullPath}`);
|
||||
return;
|
||||
|
||||
// If it is a file, check for a match.
|
||||
case stats.isFile():
|
||||
if (nameMatches(item) && (predicate ? await predicate(fullPath) : true)) {
|
||||
return options.result ??= fullPath;
|
||||
}
|
||||
break;
|
||||
|
||||
// If it's a folder, and we're not at the max depth yet, add it to the list of subfolders to search.
|
||||
case maxDepth && stats.isDirectory():
|
||||
subfolders.push(fullPath);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
if (subfolders.length) {
|
||||
await searchFolders(subfolders, filename, predicate, maxDepth - 1, options);
|
||||
}
|
||||
} catch {
|
||||
// Skip folders that can't be accessed.
|
||||
}
|
||||
}
|
||||
|
||||
return options.result;
|
||||
}
|
||||
+1
-118
@@ -15,7 +15,7 @@ import { DocumentFilter, Range } from 'vscode-languageclient';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { TargetPopulation } from 'vscode-tas-client';
|
||||
import * as which from "which";
|
||||
import { ManualPromise } from './Utility/Async/manualPromise';
|
||||
import { isExecutable } from './common-remote-safe';
|
||||
import { isWindows } from './constants';
|
||||
import { getOutputChannelLogger, showOutputChannel } from './logger';
|
||||
import { PlatformInformation } from './platform';
|
||||
@@ -749,105 +749,6 @@ export function execChildProcess(process: string, workingDirectory?: string, cha
|
||||
});
|
||||
}
|
||||
|
||||
export interface ProcessReturnType {
|
||||
succeeded: boolean;
|
||||
exitCode?: number | NodeJS.Signals;
|
||||
output: string;
|
||||
outputError: string;
|
||||
}
|
||||
|
||||
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
|
||||
// Do not use CppSettings to avoid circular require()
|
||||
if (skipLogging === undefined || !skipLogging) {
|
||||
getOutputChannelLogger().appendLineAtLevel(5, `$ ${program} ${args.join(' ')}`);
|
||||
}
|
||||
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, skipLogging, cancellationToken);
|
||||
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
|
||||
if (programOutput.exitCode) {
|
||||
return { succeeded: false, exitCode, outputError: programOutput.stderr, 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, outputError: programOutput.stderr, output: stdout };
|
||||
}
|
||||
}
|
||||
|
||||
interface ProcessOutput {
|
||||
exitCode?: number | NodeJS.Signals;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, skipLogging?: boolean, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
|
||||
const result = new ManualPromise<ProcessOutput>();
|
||||
|
||||
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 => {
|
||||
const str: string = data.toString();
|
||||
if (skipLogging === undefined || !skipLogging) {
|
||||
getOutputChannelLogger().appendAtLevel(1, str);
|
||||
}
|
||||
stdout += str;
|
||||
if (continueOn) {
|
||||
const continueOnReg: string = escapeStringForRegex(continueOn);
|
||||
if (stdout.search(continueOnReg)) {
|
||||
result.resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', data => stderr += data.toString());
|
||||
}
|
||||
proc.on('close', (code, signal) => {
|
||||
clean();
|
||||
result.resolve({ exitCode: code || signal || undefined, stdout: stdout.trim(), stderr: stderr.trim() });
|
||||
});
|
||||
proc.on('error', error => {
|
||||
clean();
|
||||
result.reject(error);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permission fs file access constants: https://nodejs.org/api/fs.html#file-access-constants
|
||||
*/
|
||||
export function pathAccessible(filePath: string, permission: number = fs.constants.F_OK): Promise<boolean> {
|
||||
if (!filePath) { return Promise.resolve(false); }
|
||||
return new Promise(resolve => fs.access(filePath, permission, err => resolve(!err)));
|
||||
}
|
||||
|
||||
export function isExecutable(file: string): Promise<boolean> {
|
||||
return pathAccessible(file, fs.constants.X_OK);
|
||||
}
|
||||
|
||||
export async function allowExecution(file: string): Promise<void> {
|
||||
if (process.platform !== 'win32') {
|
||||
const exists: boolean = await checkFileExists(file);
|
||||
@@ -1810,21 +1711,3 @@ export function findExePathInArgs(args: CommandString[]): string | undefined {
|
||||
export function getVsCodeVersion(): number[] {
|
||||
return vscode.version.split('.').map(num => parseInt(num, undefined));
|
||||
}
|
||||
|
||||
export function equals(array1: string[] | undefined, array2: string[] | undefined): boolean {
|
||||
if (array1 === undefined && array2 === undefined) {
|
||||
return true;
|
||||
}
|
||||
if (array1 === undefined || array2 === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (array1.length !== array2.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i: number = 0; i < array1.length; ++i) {
|
||||
if (array1[i] !== array2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
// Centralized https links that are used by the extension.
|
||||
|
||||
/** Link to documentation on how to troubleshoot LLDB-DAP. */
|
||||
export const TroubleshootingLldbDap = "https://aka.ms/vscode-cpptools/TroubleshootingLldbDap";
|
||||
@@ -0,0 +1,8 @@
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All Rights Reserved.
|
||||
* See 'LICENSE' in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
|
||||
export const localize: nls.LocalizeFunc = nls.loadMessageBundle();
|
||||
@@ -193,3 +193,8 @@ export function disposeOutputChannels(): void {
|
||||
warningChannel.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets a transient message in the vscode status bar. */
|
||||
export function note(message: string) {
|
||||
vscode.window.setStatusBarMessage(message, 5000);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
import * as assert from 'assert';
|
||||
import { suite } from 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { DebuggerType } from '../../../../src/Debugger/configurations';
|
||||
|
||||
suite(`Debug Integration Test: `, function(): void {
|
||||
suite(`Debug Integration Test: `, function (): void {
|
||||
|
||||
suiteSetup(async function(): Promise<void> {
|
||||
suiteSetup(async function (): Promise<void> {
|
||||
const extension: vscode.Extension<any> = vscode.extensions.getExtension("ms-vscode.cpptools") || assert.fail("Extension not found");
|
||||
if (!extension.isActive) {
|
||||
await extension.activate();
|
||||
@@ -27,7 +28,7 @@ suite(`Debug Integration Test: `, function(): void {
|
||||
});
|
||||
|
||||
try {
|
||||
assert.equal(vscode.debug.activeDebugSession?.type, "cppdbg");
|
||||
assert.equal(vscode.debug.activeDebugSession?.type, DebuggerType.cppdbg);
|
||||
} catch (e) {
|
||||
assert.fail("Debugger failed to launch. Did the extension activate correctly?");
|
||||
}
|
||||
|
||||
@@ -12,40 +12,40 @@ import { LinuxDistribution } from '../../../../src/linuxDistribution';
|
||||
suite("LinuxDistro Tests", () => {
|
||||
test("Parse valid os-release file", () => {
|
||||
const dataUbuntu1404: string = 'NAME="Ubuntu"' + os.EOL +
|
||||
'VERSION="14.04.4 LTS, Trusty Tahr"' + os.EOL +
|
||||
'ID=ubuntu' + os.EOL +
|
||||
'ID_LIKE=debian' + os.EOL +
|
||||
'PRETTY_NAME="Ubuntu 14.04.4 LTS"' + os.EOL +
|
||||
'VERSION_ID="14.04"' + os.EOL +
|
||||
'HOME_URL="http://www.ubuntu.com/"' + os.EOL +
|
||||
'SUPPORT_URL="http://help.ubuntu.com/"' + os.EOL +
|
||||
'BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"';
|
||||
'VERSION="14.04.4 LTS, Trusty Tahr"' + os.EOL +
|
||||
'ID=ubuntu' + os.EOL +
|
||||
'ID_LIKE=debian' + os.EOL +
|
||||
'PRETTY_NAME="Ubuntu 14.04.4 LTS"' + os.EOL +
|
||||
'VERSION_ID="14.04"' + os.EOL +
|
||||
'HOME_URL="http://www.ubuntu.com/"' + os.EOL +
|
||||
'SUPPORT_URL="http://help.ubuntu.com/"' + os.EOL +
|
||||
'BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"';
|
||||
|
||||
const dataUbuntu1510: string = 'NAME="Ubuntu"' + os.EOL +
|
||||
'VERSION="15.10 (Wily Werewolf)"' + os.EOL +
|
||||
'ID=ubuntu' + os.EOL +
|
||||
'ID_LIKE=debian' + os.EOL +
|
||||
'PRETTY_NAME="Ubuntu 15.10"' + os.EOL +
|
||||
'VERSION_ID="15.10"' + os.EOL +
|
||||
'HOME_URL="http://www.ubuntu.com/"' + os.EOL +
|
||||
'SUPPORT_URL="http://help.ubuntu.com/"' + os.EOL +
|
||||
'BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"';
|
||||
'VERSION="15.10 (Wily Werewolf)"' + os.EOL +
|
||||
'ID=ubuntu' + os.EOL +
|
||||
'ID_LIKE=debian' + os.EOL +
|
||||
'PRETTY_NAME="Ubuntu 15.10"' + os.EOL +
|
||||
'VERSION_ID="15.10"' + os.EOL +
|
||||
'HOME_URL="http://www.ubuntu.com/"' + os.EOL +
|
||||
'SUPPORT_URL="http://help.ubuntu.com/"' + os.EOL +
|
||||
'BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"';
|
||||
|
||||
const dataCentos73: string = 'NAME="CentOS Linux"' + os.EOL +
|
||||
'VERSION="7 (Core)"' + os.EOL +
|
||||
'ID="centos"' + os.EOL +
|
||||
'ID_LIKE="rhel fedora"' + os.EOL +
|
||||
'VERSION_ID="7"' + os.EOL +
|
||||
'PRETTY_NAME="CentOS Linux 7 (Core)"' + os.EOL +
|
||||
'ANSI_COLOR="0;31"' + os.EOL +
|
||||
'CPE_NAME="cpe:/o:centos:centos:7"' + os.EOL +
|
||||
'HOME_URL="https://www.centos.org/"' + os.EOL +
|
||||
'BUG_REPORT_URL="https://bugs.centos.org/"' + os.EOL +
|
||||
os.EOL +
|
||||
'CENTOS_MANTISBT_PROJECT="CentOS-7"' + os.EOL +
|
||||
'CENTOS_MANTISBT_PROJECT_VERSION="7"' + os.EOL +
|
||||
'REDHAT_SUPPORT_PRODUCT="centos"' + os.EOL +
|
||||
'REDHAT_SUPPORT_PRODUCT_VERSION="7"';
|
||||
'VERSION="7 (Core)"' + os.EOL +
|
||||
'ID="centos"' + os.EOL +
|
||||
'ID_LIKE="rhel fedora"' + os.EOL +
|
||||
'VERSION_ID="7"' + os.EOL +
|
||||
'PRETTY_NAME="CentOS Linux 7 (Core)"' + os.EOL +
|
||||
'ANSI_COLOR="0;31"' + os.EOL +
|
||||
'CPE_NAME="cpe:/o:centos:centos:7"' + os.EOL +
|
||||
'HOME_URL="https://www.centos.org/"' + os.EOL +
|
||||
'BUG_REPORT_URL="https://bugs.centos.org/"' + os.EOL +
|
||||
os.EOL +
|
||||
'CENTOS_MANTISBT_PROJECT="CentOS-7"' + os.EOL +
|
||||
'CENTOS_MANTISBT_PROJECT_VERSION="7"' + os.EOL +
|
||||
'REDHAT_SUPPORT_PRODUCT="centos"' + os.EOL +
|
||||
'REDHAT_SUPPORT_PRODUCT_VERSION="7"';
|
||||
|
||||
const ubuntu1404: LinuxDistribution = LinuxDistribution.getDistroInformation(dataUbuntu1404);
|
||||
const ubuntu1510: LinuxDistribution = LinuxDistribution.getDistroInformation(dataUbuntu1510);
|
||||
@@ -74,18 +74,18 @@ suite("Pick Process Tests", () => {
|
||||
test("Parse valid wmic output", () => {
|
||||
// output from the command used in WmicAttachItemsProvider
|
||||
const wmicOutput: string = 'CommandLine=' + os.EOL +
|
||||
'Name=System Idle Process' + os.EOL +
|
||||
'ProcessId=0' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'CommandLine="C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\ONENOTE.EXE"' + os.EOL +
|
||||
'Name=ONENOTE.EXE' + os.EOL +
|
||||
'ProcessId=6540' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'' + os.EOL +
|
||||
`CommandLine=\\??\\C:\\windows\\system32\\conhost.exe 0x4` + os.EOL +
|
||||
'Name=conhost.exe' + os.EOL +
|
||||
'ProcessId=59148' + os.EOL;
|
||||
'Name=System Idle Process' + os.EOL +
|
||||
'ProcessId=0' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'CommandLine="C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\ONENOTE.EXE"' + os.EOL +
|
||||
'Name=ONENOTE.EXE' + os.EOL +
|
||||
'ProcessId=6540' + os.EOL +
|
||||
'' + os.EOL +
|
||||
'' + os.EOL +
|
||||
`CommandLine=\\??\\C:\\windows\\system32\\conhost.exe 0x4` + os.EOL +
|
||||
'Name=conhost.exe' + os.EOL +
|
||||
'ProcessId=59148' + os.EOL;
|
||||
|
||||
const parsedOutput: Process[] = WmicProcessParser.ParseProcessFromWmic(wmicOutput);
|
||||
|
||||
@@ -108,9 +108,9 @@ suite("Pick Process Tests", () => {
|
||||
|
||||
test("Parse valid ps output", () => {
|
||||
// output from the command used in PsAttachItemsProvider
|
||||
const psOutput: string = ' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + os.EOL +
|
||||
'15470 ScopedBookmarkAgent ScopedBookmarkAgent' + os.EOL +
|
||||
'15220 mdworker mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.shared' + os.EOL;
|
||||
const psOutput: string = ' ' + PsProcessParser.fixedWidth + os.EOL +
|
||||
'15470 ' + "ScopedBookmarkAgent".padEnd(512, ' ') + 'ScopedBookmarkAgent' + os.EOL +
|
||||
'15220 ' + "mdworker".padEnd(512, ' ') + 'mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.shared' + os.EOL;
|
||||
|
||||
const parsedOutput: Process[] = PsProcessParser.ParseProcessFromPs(psOutput);
|
||||
|
||||
|
||||
@@ -47,11 +47,9 @@
|
||||
"default": {}
|
||||
},
|
||||
"quoteArgs": {
|
||||
"exceptions": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.pipeTransport.quoteArgs.description%",
|
||||
"default": true
|
||||
}
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.pipeTransport.quoteArgs.description%",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -604,7 +602,7 @@
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceRoot}/a.out"
|
||||
"default": "${workspaceFolder}/a.out"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
@@ -839,7 +837,7 @@
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceRoot}/a.out"
|
||||
"default": "${workspaceFolder}/a.out"
|
||||
},
|
||||
"targetArchitecture": {
|
||||
"type": "string",
|
||||
@@ -951,17 +949,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"CppvsdbgLaunchOptions": {
|
||||
"CpplldbLaunchOptions": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"program",
|
||||
"cwd"
|
||||
"program"
|
||||
],
|
||||
"properties": {
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceRoot}/program.exe"
|
||||
"default": "${workspaceFolder}/a.out"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
@@ -974,7 +971,401 @@
|
||||
"cwd": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cwd.description%",
|
||||
"default": "${workspaceRoot}"
|
||||
"default": "."
|
||||
},
|
||||
"debuggerPath": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.debuggerPath.description%",
|
||||
"default": "lldb-dap"
|
||||
},
|
||||
"debuggerArgs": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.debuggerArgs.description%",
|
||||
"default": ""
|
||||
},
|
||||
"environment": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.environment.description%",
|
||||
"items": {
|
||||
"$ref": "#/definitions/KeyValuePair"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"envFile": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.envFile.description%",
|
||||
"default": "${workspaceFolder}/.env"
|
||||
},
|
||||
"stopAtEntry": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "%c_cpp.debuggers.stopAtEntry.markdownDescription%",
|
||||
"default": false
|
||||
},
|
||||
"serverLaunchTimeout": {
|
||||
"type": "integer",
|
||||
"description": "%c_cpp.debuggers.serverLaunchTimeout.description%",
|
||||
"default": "10000"
|
||||
},
|
||||
"externalConsole": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.externalConsole.description%",
|
||||
"default": false
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"markdownDescription": "%c_cpp.debuggers.sourceFileMap.markdownDescription%",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"default": {
|
||||
"<source-path>": "<target-path>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SourceFileMapEntry"
|
||||
}
|
||||
]
|
||||
},
|
||||
"deploySteps": {
|
||||
"$ref": "#/definitions/DeploySteps"
|
||||
},
|
||||
"disableASLR": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.disableAslr.description%",
|
||||
"default": true
|
||||
},
|
||||
"disableSTDIO": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.disableStdio.description%",
|
||||
"default": false
|
||||
},
|
||||
"shellExpandArguments": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.expandShellArguments.description%",
|
||||
"default": false
|
||||
},
|
||||
"detachOnError": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.detachOnError.description%",
|
||||
"default": false
|
||||
},
|
||||
"debuggerRoot": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.debuggerRoot.description%"
|
||||
},
|
||||
"targetTriple": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.targetTriple.description%"
|
||||
},
|
||||
"platformName": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.platformName.description%"
|
||||
},
|
||||
"initCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.initCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"preRunCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.preRunCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"postRunCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.postRunCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"launchCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.launchCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"stopCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.stopCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"exitCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.exitCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"terminateCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.terminateCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"enableAutoVariableSummaries": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.enableAutoVariableSummaries.description%",
|
||||
"default": false
|
||||
},
|
||||
"displayExtendedBacktrace": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.displayExtendedBacktrace.description%",
|
||||
"default": false
|
||||
},
|
||||
"enableSyntheticChildDebugging": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.enableSyntheticChildDebugging.description%",
|
||||
"default": false
|
||||
},
|
||||
"commandEscapePrefix": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.commandEscapePrefix.description%",
|
||||
"default": "`"
|
||||
},
|
||||
"customFrameFormat": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.customFrameFormat.markdownDescription%",
|
||||
"default": ""
|
||||
},
|
||||
"customThreadFormat": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.customThreadFormat.markdownDescription%",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"CpplldbAttachOptions": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"properties": {
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceFolder}/a.out"
|
||||
},
|
||||
"debuggerPath": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldbdebuggerPath.description%",
|
||||
"default": "lldb-dap"
|
||||
},
|
||||
"debuggerArgs": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.debuggerArgs.description%",
|
||||
"default": ""
|
||||
},
|
||||
"processId": {
|
||||
"markdownDescription": "%c_cpp.debuggers.processId.anyOf.markdownDescription%",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "${command:pickProcess}"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"default": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"markdownDescription": "%c_cpp.debuggers.sourceFileMap.markdownDescription%",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"default": {
|
||||
"<source-path>": "<target-path>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SourceFileMapEntry"
|
||||
}
|
||||
]
|
||||
},
|
||||
"serverLaunchTimeout": {
|
||||
"type": "integer",
|
||||
"description": "%c_cpp.debuggers.serverLaunchTimeout.description%",
|
||||
"default": "10000"
|
||||
},
|
||||
"waitFor": {
|
||||
"type": "boolean",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.waitFor.markdownDescription%",
|
||||
"default": true
|
||||
},
|
||||
"deploySteps": {
|
||||
"$ref": "#/definitions/DeploySteps"
|
||||
},
|
||||
"disableASLR": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.disableAslr.description%",
|
||||
"default": true
|
||||
},
|
||||
"disableSTDIO": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.disableStdio.description%",
|
||||
"default": false
|
||||
},
|
||||
"shellExpandArguments": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.expandShellArguments.description%",
|
||||
"default": false
|
||||
},
|
||||
"detachOnError": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.detachOnError.description%",
|
||||
"default": false
|
||||
},
|
||||
"debuggerRoot": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.debuggerRoot.description%"
|
||||
},
|
||||
"targetTriple": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.targetTriple.description%"
|
||||
},
|
||||
"platformName": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.platformName.description%"
|
||||
},
|
||||
"attachCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.platformName.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"initCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.initCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"preRunCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.preRunCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"postRunCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.postRunCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"stopCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.stopCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"exitCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.exitCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"terminateCommands": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.cpplldb.terminateCommands.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"coreFile": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.coreFile.description%"
|
||||
},
|
||||
"gdb-remote-port": {
|
||||
"type": [
|
||||
"number",
|
||||
"string"
|
||||
],
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.gdbRemotePort.markdownDescription%"
|
||||
},
|
||||
"gdb-remote-hostname": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.gdbRemoteHost.markdownDescription%"
|
||||
},
|
||||
"enableAutoVariableSummaries": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.enableAutoVariableSummaries.description%",
|
||||
"default": false
|
||||
},
|
||||
"displayExtendedBacktrace": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.displayExtendedBacktrace.description%",
|
||||
"default": false
|
||||
},
|
||||
"enableSyntheticChildDebugging": {
|
||||
"type": "boolean",
|
||||
"description": "%c_cpp.debuggers.cpplldb.enableSyntheticChildDebugging.description%",
|
||||
"default": false
|
||||
},
|
||||
"commandEscapePrefix": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cpplldb.commandEscapePrefix.description%",
|
||||
"default": "`"
|
||||
},
|
||||
"customFrameFormat": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.customFrameFormat.markdownDescription%",
|
||||
"default": ""
|
||||
},
|
||||
"customThreadFormat": {
|
||||
"type": "string",
|
||||
"markdownDescription": "%c_cpp.debuggers.cpplldb.customThreadFormat.markdownDescription%",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"CppvsdbgLaunchOptions": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"program",
|
||||
"cwd"
|
||||
],
|
||||
"properties": {
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceFolder}/program.exe"
|
||||
},
|
||||
"args": {
|
||||
"type": "array",
|
||||
"description": "%c_cpp.debuggers.args.description%",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.cwd.description%",
|
||||
"default": "${workspaceFolder}"
|
||||
},
|
||||
"environment": {
|
||||
"type": "array",
|
||||
@@ -1102,6 +1493,11 @@
|
||||
"processId"
|
||||
],
|
||||
"properties": {
|
||||
"program": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.program.description%",
|
||||
"default": "${workspaceFolder}/program.exe"
|
||||
},
|
||||
"symbolSearchPath": {
|
||||
"type": "string",
|
||||
"description": "%c_cpp.debuggers.symbolSearchPath.description%",
|
||||
|
||||
@@ -687,7 +687,7 @@
|
||||
<div class="section-title" data-loc-id="merge.configurations">Merge configurations</div>
|
||||
<div>
|
||||
<input type="checkbox" id="mergeConfigurations" style="vertical-align: middle; transform: scale(1.5)">
|
||||
<span data-loc-id="merge.configurations.description">When <code>true</code> (or checked), merge <code>includePath</code>, <code>defines</code>, <code>forcedInclude</code>, and <code>browse.path</code> with those received from the configuration provider.</span>
|
||||
<span data-loc-id="merge.configurations.description">When <code>true</code> (or checked), merge include paths, defines, and forced includes with those from a configuration provider.</span>
|
||||
</input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+6
-6
@@ -1196,17 +1196,17 @@ bl@^5.0.0:
|
||||
readable-stream "^3.4.0"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.12"
|
||||
resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
|
||||
integrity sha1-q5tFRGblqMw6GHvqrVgEEqnFuEM=
|
||||
version "1.1.11"
|
||||
resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
brace-expansion@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7"
|
||||
integrity sha1-VPxTI3phPYVMe9N0Y6rRffhyFOc=
|
||||
version "2.0.1"
|
||||
resolved "https://pkgs.dev.azure.com/azure-public/VisualCpp/_packaging/cpp_PublicPackages/npm/registry/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
|
||||
integrity sha1-HtxFng8MVISG7Pn8mfIiE2S5oK4=
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user