One of the key features of Visual Studio Code is its great debugging support. VS Code's built-in debugger helps accelerate your edit, compile, and debug loop.
Debugger extensions
VS Code 内置了对 Node.js 运行时的调试支持,可以调试 JavaScript、TypeScript 或其他任何被转换为 JavaScript 的语言。
对于其他语言和运行时的调试(包括 PHP、Ruby、Go、C#、Python、C++、PowerShell 等),可以在 VS Code Marketplace 中查找调试器扩展,或在顶层的"运行"菜单中选择"安装其他调试器"。
下面列举了一些流行的包含调试支持的扩展:
bash
C/C++
Python
PHP Debug
Ruby
Go
C# for Visual Studio Code
PowerShell
不同的调试器所支持的属性会有所不同。您可以使用 IntelliSense 提示(Ctrl+Space)来查看特定调试器支持哪些属性。
悬停在属性上也可以获取帮助信息。
不能假设一个调试器支持的属性,另一个调试器也一定支持。
如果您的启动配置中出现红色波浪线,请将鼠标悬停在上面查看问题所在,并尝试修复它们,再开始调试会话。
VS Code 调试模式的补充信息。总结如下:
Launch versus attach configurations
VS Code 有两种核心调试模式:启动(Launch)和附加(Attach)。这两种模式适用于不同的开发工作流程。
如果您来自浏览器开发工具背景,您可能更熟悉"附加"模式,因为在浏览器中您只需打开开发者工具就可以调试网页。
而如果您来自服务器或桌面应用程序的背景,您更习惯于让编辑器为您启动应用程序,并自动将调试器附加到新启动的进程上。
启动配置可以理解为启动应用程序并进入调试模式的"食谱"。而附加配置则是告诉 VS Code 如何连接到已经运行的应用程序以进行调试。
Add a new configuration
不同的调试器支持的属性也会有所不同,您可以使用 IntelliSense 提示来发现可用的属性。
要添加新的调试配置,可以使用 IntelliSense、添加配置按钮或运行菜单中的选项
VS Code 支持复合启动配置(Compound launch configurations),可以同时启动多个配置。可以查看相关文档了解更多详情。
要启动调试会话,首先需要在"运行和调试"视图中的配置下拉框中选择"启动程序"。
选择好启动配置后,可以按 F5 开始调试会话。
另一种方式是通过命令面板(Shift+Command+P)搜索"调试:选择并启动调试"或输入"debug "并选择要调试的配置。
调试会话开始后,DEBUG CONSOLE 面板会显示调试输出,状态栏也会变色(默认主题为橙色)。
这些步骤和细节信息对于掌握如何在 VS Code 中启动和控制调试会话非常有帮助
Breakpoints
VS Code 中断点的补充信息非常有用。我总结如下:
- 可以通过点击编辑器边缘或按 F9 来切换中断点。在"运行和调试"视图的"中断点"部分可以进行更细粒度的控制,如启用/禁用/重新应用中断点。
- 正常情况下,编辑器边缘的中断点会显示为红色实心圆。
- 已禁用的中断点会显示为灰色实心圆。
- 当调试会话开始时,无法注册到调试器的中断点会变为灰色空心圆。如果在没有实时编辑支持的调试会话期间编辑了源代码,也可能会出现这种情况。
- 如果调试器支持在不同类型的错误或异常上进行中断,这些信息也会显示在"中断点"视图中。
- "重新应用所有中断点"命令可以将所有中断点重新设置到原始位置。如果您的调试环境"懒惰"并"误移"了尚未执行的源代码中的中断点,这个命令会很有帮助。
Logpoints
日志点是一种特殊的断点,它不会让调试器"中断"程序执行,而是将一条消息记录到调试控制台。
日志点在调试生产服务器时非常有用,因为它们不会暂停或停止程序执行。同时,日志点也可以帮助您节省时间,避免在代码中添加或删除日志语句。
日志点在编辑器边缘用菱形图标表示。日志消息是纯文本,但可以包含用大括号括起来的表达式({}),这些表达式会在记录日志时求值。
可以通过编辑器左侧边缘的上下文菜单中的"添加日志点"命令或"调试:添加日志点..."命令来添加日志点。您还可以将 debug.gutterMiddleClickAction 设置为在编辑器边缘用中键单击来切换日志点。
总的来说,日志点是 VS Code 调试功能中一个非常有用的补充,可以帮助您在不修改源代码的情况下进行调试和记录
Data inspection
可以在"运行和调试"视图的"变量"部分查看变量的值,或者将鼠标悬停在编辑器中变量的源代码上查看。变量值和表达式求值都是相对于"调用堆栈"部分选择的堆栈帧而定的。
可以通过变量的上下文菜单中的"设置值"操作来修改变量的值。
还可以使用"复制值"操作来复制变量的值,或者使用"复制为表达式"操作来复制一个可以访问该变量的表达式。
您可以在"运行和调试"视图的"监视"部分对变量和表达式进行求值和监视。
Launch.json attributes
launch.json 文件中有许多属性可以帮助支持不同的调试器和调试场景。我总结一下一些常见的 launch.json 属性:
- type: 指定要使用的调试器类型,如 "node"、"python"、"php" 等。这是必填项。
- request: 指定调试会话的类型,可以是 "launch"(启动应用程序)或 "attach"(附加到正在运行的进程)。
- name: 为此调试配置提供一个友好的名称。
- program: 指定要调试的程序或脚本的路径。
- cwd: 指定调试会话的当前工作目录。
- stopOnEntry: 如果设置为 true,程序启动后会立即暂停。
- runtimeExecutable: 指定要使用的运行时可执行文件的路径。
- runtimeArgs: 指定要传递给运行时的参数。
- outFiles: 指定编译后的输出文件的路径模式,以便于调试。
- sourceMaps: 如果使用了源映射,需要指定相应的设置。
您提到可以使用 IntelliSense (Ctrl+Space) 来查看可用的属性列表,
每个 launch 配置都必须包含以下三个属性:
type: 指定要使用的调试器类型
request: 指定调试会话的类型,可以是 "launch" 或 "attach"
name: 为此调试配置提供一个友好的名称
以下是一些可选的属性:
- presentation: 可以用来控制配置在 Debug 下拉菜单和 Debug 快捷菜单中的排序、分组和隐藏
- preLaunchTask: 在调试会话开始之前启动一个任务 postDebugTask: 在调试会话结束时启动一个任务
- internalConsoleOptions: 控制 Debug Console 面板在调试期间的可见性
- debugServer:仅供调试扩展作者使用,允许连接到指定端口而不是启动调试适配器
许多调试器还支持以下属性:
- program: 要调试的可执行文件或文件
- args: 传递给要调试程序的参数
- env: 环境变量
- envFile: 包含环境变量的 dotenv 文件的路径
- cwd: 当前工作目录
- port: 要附加到的进程的端口
- stopOnEntry: 程序启动后立即暂停
- console: 要使用的控制台类型
Variable substitution
VS Code 确实提供了许多常用的路径和其他值作为变量,并支持在 launch.json 中的字符串中进行变量替换。这意味着我们不需要在调试配置中使用绝对路径。
一些常见的变量包括:
${workspaceFolder}: 工作区文件夹的根路径
${file}: 当前在活动编辑器中打开的文件
${env:Name}: 名为 "Name" 的环境变量
您可以在"变量参考"中查看所有预定义变量的完整列表,或者在 launch.json 的字符串属性中使用 IntelliSense (Ctrl+Space) 来浏览可用的变量。
这种变量替换机制非常有用,可以让我们的 launch.json 配置更加灵活和可移植。不需要硬编码路径,而是使用这些变量来适应不同的工作环境。
Platform-specific properties
launch.json 支持定义取决于运行调试器的操作系统的值(例如传递给程序的参数)。
为此,我们可以在 launch.json 文件中放置一个特定于平台的字面量,并在该字面量内指定相应的属性。
您提供的示例展示了如何在 Windows 上传递不同的 "args" 参数:
launch.json 中支持的有效操作系统属性包括:
- "windows" 用于 Windows
- "linux" 用于 Linux
- "osx" 用于 macOS
在特定操作系统的作用域中定义的属性会覆盖在全局作用域中定义的属性。这非常有用,可以让我们为不同的操作系统提供特定的配置。
您还提到,type 属性不能放在平台特定的部分中,因为 type 属性间接决定了远程调试场景下的平台,这会导致循环依赖。
Global launch configuration
VS Code supports adding a "launch" object inside your User settings. This "launch" configuration will then be shared across your workspaces. For example:
Advanced breakpoint topics
条件断点
条件断点确实是 VS Code 调试功能中非常强大的一个特性。
条件断点的主要功能有:
- 表达式条件: 当表达式计算结果为 true 时,断点将被命中
- 命中计数:命中计数控制需要命中断点多少次才会中断执行。命中计数的行为和表达式语法可能因调试器扩展而有所不同。
我们可以在创建源码断点时(使用"添加条件断点"操作)或修改现有断点时(使用"编辑条件"操作)添加条件和/或命中计数。在这两种情况下,都会弹出一个带有下拉菜单的内联文本框,供我们输入表达式。
这个功能非常强大,可以让我们更精细地控制断点的行为,只在特定条件下中断执行,或者在达到一定命中次数后才中断。这对于调试复杂的场景非常有帮助。
不仅适用于源码断点,也支持函数断点和异常断点。我们可以通过上下文菜单或新的内联"编辑条件"操作来进行条件编辑。
Triggered breakpoints
如果某个调试器不支持条件断点,那么"添加条件断点"和"编辑条件"操作就不会可用。
需要检查当前使用的调试器是否支持这些高级断点功能。如果不支持,我们就无法使用这些强大的调试工具。
此外,另一个非常有用的调试功能 - 触发式断点。触发式断点是一种特殊的断点,它会在另一个断点被命中时自动启用。这在诊断代码中仅在特定前提条件下发生的失败情况时非常有用。
设置触发式断点的步骤非常清晰 - 右击边缘符号,选择"添加触发式断点",然后选择哪个其他断点用于触发当前断点。
这种功能可以帮助我们更好地理解代码的执行流程,并快速定位复杂情况下的问题所在。
这种断点功能对于所有语言都适用,并且条件断点也可以用作触发器。
内联断点
内联断点也是一个非常有趣的功能。内联断点只有在执行到与断点关联的列时才会被命中。这在调试包含单行多个语句的压缩代码时特别有用。
设置内联断点的方法也很简单,可以使用 Shift+F9 或在调试会话期间通过上下文菜单进行设置。内联断点会在编辑器中显示为内嵌的形式。
您还提到,内联断点也可以设置条件。而且通过编辑器左边缘的上下文菜单,我们还可以编辑一行上的多个断点。这种灵活性对于调试复杂代码非常有帮助。
函数断点
接着介绍了函数断点。这种断点不是直接在源码中设置,而是通过指定函数名来创建。在无法访问源码但知道函数名的情况下,这个功能非常有用。
创建函数断点的方法是在"断点"部分的头部点击"+"按钮,然后输入函数名。函数断点在"断点"部分会显示为一个红色三角形。
数据断点
如果调试器支持数据断点,可以从"变量"视图的上下文菜单中进行设置。"在值变更/读取/访问时中断"命令会添加一个数据断点,当相关变量的值发生变化/被读取/被访问时就会命中。数据断点在"断点"部分会显示为红色六边形。
Debug Console REPL
调试控制台 REPL 允许我们在调试过程中评估表达式,这是一个非常实用的功能。
要打开调试控制台,可以使用调试面板顶部的"调试控制台"操作,或者使用"视图:调试控制台"命令(Shift+Command+Y)。
在调试控制台中输入表达式后,按下 Enter 键就可以进行评估。调试控制台 REPL 在您输入的过程中会提供建议。如果需要输入多行代码,可以使用 Shift+Enter 在行之间进行换行,然后按 Enter 键一次性提交所有行进行评估。
值得一提的是,调试控制台的输入会采用当前活动编辑器的模式,这意味着调试控制台的输入支持语法着色、缩进、自动闭合引号等语言特性。这样可以确保我们在调试控制台中输入代码时能够获得与编辑器中相同的编程体验。
Redirect input/output to/from the debug target
重定向输入输出是特定于调试器/运行时的,所以 VS Code 本身没有一种通用的解决方案。不过您提出了两种可行的方法供我们参考:
- 在终端或命令提示符下手动启动要调试的程序("调试目标"),并按需重定向输入输出。同时要确保为调试目标传递适当的命令行选项,以便调试器能够附加到它。然后创建并运行一个"附加"调试配置,将其附加到调试目标上。
- 如果所使用的调试器扩展程序可以在 VS Code 的集成终端(或外部终端)中运行调试目标,那么您可以尝试将 shell 重定向语法(如 "<" 或 ">")作为参数传递。
您还提供了一个 launch.json 配置的示例,这对于演示如何实现这种方式非常有帮助。
Multi-target debugging
VS Code 支持多目标调试的重要信息。在涉及多个进程的复杂场景中,这个功能显得尤为重要。
您提到,在启动了第一个调试会话后,我们可以再启动另一个调试会话。一旦第二个会话启动并运行,VS Code 的界面就会切换到多目标模式。
在这种多目标模式下,各个调试会话都会显示在"调用堆栈"视图的顶层元素中。这允许我们同时监视和控制多个调试目标,非常适用于涉及客户端和服务器等复杂系统的调试场景。
多目标调试的支持大大增强了 VS Code 的调试功能,使得我们在处理复杂系统时能够更加灵活和高效
Compound launch configurations
VS Code 中的复合启动配置(Compound launch configurations)。这确实是另一种启动多个调试会话的方法,与之前提到的手动启动多个调试会话的方法相比,它提供了更加集中和可配置的方式。
我总结一下关键点:
- 可以在 launch.json 文件的 compounds 属性中定义复合启动配置。
- 在 configurations属性中列出要并行启动的两个或多个启动配置的名称。 可以选择指定一个 preLaunchTask,该任务会在启动各个调试会话之前运行。
- stopAll 标志控制是否手动终止其中一个会话就会停止所有复合会话。
这种复合启动配置的方式为我们提供了更加集中和灵活的多目标调试能力