1. VSCode reStructuredText 绿色波浪线 D002/D004 报错到底怎么回事
如果你在 Windows 上写.rst文档,打开 VSCode 看到满屏绿色波浪线,鼠标悬停提示D002 Trailing whitespace和D004 Found literal carriage return,那你遇到的是 reStructuredText 插件里一个相当经典的误报场景。这两个提示本身不是语法错误,而是 doc8 这个文档风格检查器对行尾字符的判定规则,和 Windows 默认换行符之间产生了冲突。
先说清楚这三个东西分别是什么。reStructuredText 是一种轻量级标记语言,Python 官方文档、Sphinx 文档站大量使用它,文件后缀是.rst。VSCode 里的reStructuredText插件(发布者是 LeXtudio)负责语法高亮、预览和 lint 检查。而 doc8 是插件内部调用的检查引擎,它遵循一套文档规范编号,D002 表示行尾有多余空白,D004 表示检测到了字面量回车符\r。
问题就出在这里:Windows 系统默认换行是\r\n(CRLF),而 doc8 期望的是\n(LF)。于是每一行结尾的那个\r都被判定成 D004,行尾如果还有空格就叠加 D002。整篇文档每一行都中招,绿色波浪线自然铺满屏幕。这个现象在 2019 年前后就被大量用户确认,doc8 团队也把相关 issue 标记为 Confirmed,但插件侧和引擎侧的修复节奏并不同步,所以直到现在仍有不少人在新环境里踩到。
需要区分的是:这属于插件规则误报,不是你的文档写错了,也不是语言服务崩了。判断依据很简单——同样的.rst文件放到 Linux 或 macOS 上打开,波浪线立刻消失,因为那些系统的换行就是\n。所以排查方向应该锁定在「插件配置」和「语言服务链路」两层,而不是去改文档内容。
我试过在几个不同项目里复现,结论一致:只要文件是 CRLF 保存的,D002/D004 必然出现。下面我会从插件配置入手,给出可复制的settings.json片段,再顺着语言服务链路逐项验证,帮你定位到底是插件规则在报,还是外部服务配置在干扰。如果你后续要把这套检查接到远程模型或统一的服务端做批量校验,配置项的写法会更讲究,这也是本文后半段要展开的部分。
2. TaoToken 前置准备:让 reStructuredText 检查链路可复现
在动手改配置之前,先把「检查链路」这个概念理清楚,否则你改了settings.json也不知道是哪一层生效了。reStructuredText 插件的 lint 流程大致是:VSCode 编辑器捕获文件内容 → 插件调用 doc8(可能是内置的 Python 环境,也可能是你系统里的 Python)→ doc8 返回诊断信息 → 插件把 D002/D004 渲染成绿色波浪线。任何一层出问题,表现都可能类似,但解法完全不同。
这里引入 TaoToken 的意义在于:当你需要把文档检查、模型润色、批量校验放到统一的服务端时,本地插件的规则误报和远程服务的配置会互相干扰。TaoToken 提供的是统一的模型接入入口,Base URL 是https://taotoken.net/api,你可以在一个地方管理 Key、模型 ID 和调用参数。对于 reStructuredText 这种「本地 lint + 远程模型辅助」的组合场景,把服务端配置固定下来,能避免「到底是插件报错还是服务返回异常」这种扯皮。
前置准备分三步。第一步,确认你的 Python 环境。doc8 是 Python 包,插件可能用它自带的,也可能用你配置的解释器。在终端执行:
python --version pip show doc8如果pip show doc8没有输出,说明 doc8 没装在当前环境,插件可能用的是内置版本。第二步,拿到 TaoToken 的 API Key。访问https://taotoken.net/api-keys,登录后创建一个 Key,复制保存。注意 Key 只在创建时完整显示一次,丢了就重新建。第三步,确认你要用的模型 ID。如果你只是做文档检查,不一定需要模型;但如果你打算让模型帮忙改写.rst或做语义校验,就需要一个稳定的模型入口。模型列表可以在https://taotoken.net/models查看,选一个你熟悉的即可。
把这三样东西准备好:Python 环境、API Key、Model ID。后面配置settings.json时,本地 lint 部分和远程服务部分是分开写的,互不覆盖。很多人误报排查失败,就是因为把两套配置混在一个字段里,改了一处另一处被覆盖,表现就是「改了没用」。所以先把边界划清楚,再往下走。
3. 可复制配置:settings.json 片段与 doc8 忽略规则
现在进入实操。打开 VSCode,按Ctrl + ,打开设置界面,搜索reStructuredText,找到任意一项后点击右上角的「在 settings.json 中编辑」图标,或者直接用Ctrl + Shift + P输入Open User Settings (JSON)。你要改的是用户级或工作区级的settings.json,两者区别是:用户级对所有项目生效,工作区级只对当前文件夹生效。建议先在工作区级试,确认有效再提到用户级。
针对 D002/D004 误报,核心配置是给 doc8 传忽略参数。可复制的片段如下:
{ "restructuredtext.linter.extraArgs": [ "--ignore D002", "--ignore D004" ], "restructuredtext.linter.doc8.extraArgs": [ "--ignore D002", "--ignore D004" ], "restructuredtext.linter.disabled": false, "files.eol": "\n" }逐项说明。restructuredtext.linter.extraArgs是旧版插件字段,restructuredtext.linter.doc8.extraArgs是较新版本的字段,两个都写上是为了兼容不同插件版本,避免你升级插件后配置失效。restructuredtext.linter.disabled设为false表示保留 lint 功能,只是忽略这两个规则,而不是整个关掉检查——这点很重要,直接关 lint 会丢掉其他有价值的提示。files.eol设为\n是让 VSCode 新建文件时用 LF 换行,从源头减少 CRLF 带来的问题,但注意它不会自动转换已有文件。
如果你还想把远程模型服务也纳入同一份配置,比如让模型辅助检查文档语义,可以追加一段。这里用 TaoToken 的 Base URL 和你的 Key:
{ "restructuredtext.linter.extraArgs": [ "--ignore D002", "--ignore D004" ], "taotoken.baseUrl": "https://taotoken.net/api", "taotoken.apiKey": "你的_API_Key", "taotoken.model": "你的_Model_ID" }注意taotoken.*这几个字段不是 reStructuredText 插件原生支持的,它只是我用来演示「本地 lint 配置」和「远程服务配置」如何共存的一种写法。实际使用时,如果你的插件或扩展不认这些字段,VSCode 会在设置里标黄提示未知配置项,但不影响restructuredtext.linter.extraArgs生效。关键原则是:本地规则用插件自己的字段,远程服务用服务方约定的字段,两者不要互相覆盖。
保存settings.json后,回到.rst文件,绿色波浪线应该立刻消失。如果没消失,先执行Ctrl + Shift + P→Developer: Reload Window重载窗口,让插件重新读取配置。还不行就检查是否有工作区级settings.json覆盖了用户级配置,VSCode 的优先级是工作区 > 用户,容易漏看。
4. 验证请求与成功结果:确认误报真的被消除
配置写完不代表问题解决,必须做验证。验证分两层:本地 lint 是否还报 D002/D004,以及远程服务链路是否正常。先做本地验证。新建一个测试文件test.rst,内容故意写成 CRLF 加行尾空格:
标题 ==== 这是一行带尾随空格的文本。 这是第二行。保存后观察。如果配置生效,绿色波浪线不应该出现。为了确认不是「碰巧没触发」,把鼠标悬停在原本会报错的行上,正常情况下不会弹出 D002/D004 提示。再打开「问题」面板(Ctrl + Shift + M),过滤rst,应该看不到 D002/D004 条目。这一步是判断「插件规则是否被正确忽略」的关键。
接着验证远程服务链路。如果你配置了 TaoToken 的模型入口,可以用一个最小请求确认服务可达。在终端执行:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer 你的_API_Key" \ -H "Content-Type: application/json" \ -d '{ "model": "你的_Model_ID", "messages": [ {"role": "user", "content": "回复 OK 两个字母即可"} ] }'预期返回里包含choices数组,message.content是OK或类似内容。如果返回 401,说明 Key 不对或没带上;如果返回模型不存在,说明 Model ID 写错了。这一步能帮你区分:绿色波浪线消失是本地配置的功劳,还是远程服务根本没参与。很多人把两者混在一起,结果服务挂了以为是插件问题,白白排查半天。
成功结果应该是:.rst文件无绿色波浪线,问题面板无 D002/D004,curl 请求返回正常 JSON。三者都满足,说明本地规则忽略和远程服务接入都到位了。如果只想解决波浪线,前两项满足即可,第三项按需。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
排查误报时,最容易卡在几个典型报错上。下面按真实报错逐条对照,帮你快速定位。
401 Unauthorized。出现在 curl 或插件调用远程服务时。原因通常是 Key 没带、带错、或带了多余空格。检查Authorization: Bearer后面是否紧跟 Key,中间只有一个空格。如果你把 Key 写进settings.json,注意 JSON 字符串里不要有多余换行。401 和 D002/D004 无关,它属于服务鉴权层,别混为一谈。
local proxy failed。这个报错通常出现在插件尝试通过本地网络配置访问外部服务时。注意,这里说的不是让你去配置任何网络工具,而是检查你的系统环境变量里是否有残留的HTTP_PROXY、HTTPS_PROXY指向了一个已经失效的地址。在终端执行echo $HTTPS_PROXY(Windows 用echo %HTTPS_PROXY%),如果有输出且地址不可用,清掉它再重试。这个报错和 reStructuredText 的 lint 无关,但会干扰你验证远程链路。
reading choices 相关报错。典型形式是Cannot read properties of undefined (reading 'choices')。这说明代码在解析服务返回时,期望拿到choices字段,但实际返回结构不对。常见原因是:请求发到了错误的路径(比如漏了/v1/chat/completions),或者服务返回的是错误对象而不是正常响应。先用第 4 节的 curl 确认原始返回,再检查插件或脚本里拼接的 URL 是否完整。
OAuth 相关报错。如果你用的是需要 OAuth 授权的客户端(比如某些 CLI 工具),报错可能提示 token 过期或 scope 不足。这类问题要回到授权流程重新走一遍,确认回调地址和权限范围。它和 D002/D004 完全是两个层面,排查时先确认报错来源,别在插件配置里瞎改。
对照表如下,方便你快速判断:
| 报错 | 所属层 | 首要检查 |
|---|---|---|
| D002/D004 | 插件 lint 规则 | extraArgs 忽略配置 |
| 401 | 服务鉴权 | API Key 与请求头 |
| local proxy failed | 系统网络环境 | 代理环境变量残留 |
| reading choices | 响应解析 | 请求 URL 与返回结构 |
| OAuth | 授权流程 | token 与 scope |
排查顺序建议:先确认波浪线是否消失(本地层),再确认服务是否可达(远程层),最后才看具体报错。顺序反了容易在无关层浪费时间。
6. 语义一致 CTA:把配置固定下来,后续接入更省心
把settings.json里的忽略规则固定下来之后,D002/D004 误报基本不会再打扰你。但如果你后续要把文档检查、模型润色、批量校验做成常规流程,建议把服务端配置也统一管理,避免每次换环境都重新填 Key 和 Model ID。
需要长期做编码和 Agent 类任务的,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=coding_plan。只是临时验证模型返回是否正常的,用模型对话入口更快:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=model_chat。要管理 Key 和查看接入文档的,直接去 API Keys 页:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=api_keys,文档在https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=doc。
最后留一个实用技巧:如果你团队里多人写.rst,把忽略 D002/D004 的配置放进工作区的.vscode/settings.json并提交到仓库,比每个人手动改用户级配置靠谱得多。这样新同事拉下代码,打开文件就不会被满屏绿色波浪线吓到,也不用再问「这报错是不是我写错了」。配置一次,长期省事。