✨ feat(vscode): 代码阅读的注释挂到它讲的代码块上成「注释」一行,重写注释改用技能一句话加结构化结果
- 普通注释不再单独成卡片:同一层挂到后面最近的块(隔空行也算),后面没有挂到前面那块,整层没代码挂到父块;只有文件开头隔着空行的注释、模块 docstring、//!、@file 单独成「文件开头的说明」 - 各语言(Python、TypeScript、Rust、Shell、Dockerfile)建好树后统一调 attachComments;块的编辑范围连着挂上的注释,差异、跳转、钉住卡片都按它 - 宿主统一给每张卡片(语言卡片、翻译插件的属性表、库规则卡片、一行译文的语句卡片)插「注释」一行,排在名称、说明后面 - TypeScript 的 JSDoc 也能当常量、变量的说明;sqlx、React 不再单独处理前面的注释 - 「重写注释」每块都有:提示只发 /ecc:writing-code-comments 路径:起-止,模型只读、按 --json-schema 交 body,没交结构化正文就失败不写;扩展换掉块前面的注释或在块上面新写一段
This commit is contained in:
1 parent
335cf9ca9f
commit
582ac4c987
49 files changed
+1730
-757
No files matched your search
@@ -25,7 +25,8 @@
|
||||
| 折叠 | 有子块的块、属性表里带子行的行、带下一层的子行(字典 / 对象里嵌套的字典 / 对象)能折叠;函数块(含方法、嵌套函数)、类块、枚举块、异常块和库规则的卡片默认收起主体、属性表照常显示,其余块、属性行和子行默认展开;用户点过的按他点的记住 |
|
||||
| 函数、类的说明 | TypeScript 紧贴在函数、类前面的 JSDoc,Python 函数、类主体开头的 docstring 是它自己的说明:进属性表「说明」一行,不再单独成一块注释;它的源码行算在函数、类块的头部里,「编辑」时和签名一起改 |
|
||||
| 变量、字段的说明 | Python 模块、类主体里紧跟在一条赋值后面的字符串(属性 docstring,PEP 257 / Sphinx 的写法)是这个变量的说明:常量、变量块进属性表「说明」一行(紧跟名称),字段块排在一行译文下面;不再单独成块,它的源码行算在这一块里,「编辑」时和赋值一起改 |
|
||||
| 注释按 Markdown 显示 | 注释块和函数、类、变量、字段的「说明」按 Markdown 渲染,像 Kotlin 的 KDoc:去掉注释符号、引号和共同缩进后的原文原样交给 Markdown,不按语言转换(reStructuredText 的 `:func:`、JSDoc 的 `@param` 都照抄,注释以后慢慢改成 Markdown 写法);段内单个换行是软换行,空行分段;仓库内图片按原图比例显示,点了打开原图,没有就写「找不到图片」 |
|
||||
| 注释挂在它讲的块上 | 注释一定是讲某块代码的:普通注释(`#`、`//`、`/* */`、没挂成说明的文档注释、Python 当注释用的字符串)不单独成块,挂到它讲的那块上,是那张卡片的「注释」一行(排在名称、说明后面);同一层里挂到后面最近的那块(中间隔空行也算),后面没有就挂到前面那块,这一层一块代码都没有就挂到父块。单独成块的只有文件开头的说明:第一块代码之前、和它隔着空行的注释,以及本来就讲整个文件的(Python 模块开头的 docstring、Rust 的 `//!`、JSDoc 的 `@file`)。块的编辑范围连同挂在它上面的注释。见「注释挂到它讲的块上」 |
|
||||
| 注释按 Markdown 显示 | 卡片的「注释」一行、文件开头的说明和函数、类、变量、字段的「说明」按 Markdown 渲染,像 Kotlin 的 KDoc:去掉注释符号、引号和共同缩进后的原文原样交给 Markdown,不按语言转换(reStructuredText 的 `:func:`、JSDoc 的 `@param` 都照抄,注释以后慢慢改成 Markdown 写法);段内单个换行是软换行,空行分段;仓库内图片按原图比例显示,点了打开原图,没有就写「找不到图片」 |
|
||||
| 跳到定义 | 和普通编辑器一样 ⌘ / Ctrl + 点击名字跳到定义,定义由 VS Code 装的语言扩展(Pylance、TypeScript 语言服务……)查;目标语言有代码阅读就在预览里打开 |
|
||||
| 悬停看定义 | 和普通编辑器里的悬停一样:鼠标停在名字、注释里指到符号的链接上一会儿(VS Code 的 `editor.hover.delay`),弹出定义所在那块的卡片(别的文件的也行,和那个文件的预览画的是同一张),点卡片标题跳过去 |
|
||||
| 高亮名字的各处出现 | 和普通编辑器一样单击名字就高亮它在这个文件里的各处出现,由语言扩展按语义认(同名的别的东西不算),颜色用 VS Code 的单词高亮色,再用 focusBorder 色补一笔(当前那一处描框、别的画细线);看不见的(折叠、筛掉的)点的时候不自动展开,筛选栏上写「名字 · 2/5」;⌘↓ / ⌘↑(可改绑的命令)在各处之间跳,跳到折叠着的地方会展开 |
|
||||
@@ -152,7 +153,7 @@
|
||||
|
||||
### 预览(代码块树)
|
||||
|
||||
- 每一句是一块:导入、函数、类、枚举、异常、类型、字段、常量、变量、条件、否则、循环、尝试、捕获、最终、返回、语句、注释;Shell 脚本另有解释器、选项、分情况、命令、管道(见「Shell 脚本」);Dockerfile 另有解析指令、阶段、执行、复制、设置、标签、健康检查、启动(见「Dockerfile」)。
|
||||
- 每一句是一块:导入、函数、类、枚举、异常、类型、字段、常量、变量、条件、否则、循环、尝试、捕获、最终、返回、语句、文件开头的说明(种类「注释」);Shell 脚本另有解释器、选项、分情况、命令、管道(见「Shell 脚本」);Dockerfile 另有解析指令、阶段、执行、复制、设置、标签、健康检查、启动(见「Dockerfile」)。
|
||||
- 嵌套的块放在父块下面、往右缩进;每一层左边一条竖线(颜色 `--vscode-editorIndentGuide-background`)。
|
||||
- 块的组成(从左到右):折叠箭头(只有有子块的块才显示,其余占位对齐)、概念图标、内容、右上角一排图标按钮。
|
||||
- 概念图标(原型 `kindBadge`、画板「Prototype / 块种类图标」):块左边横排这块认出来的概念,各一个图标、不带字,和一行字等高(20px 的框,图形 16px,lucide 的线宽 2.2),间距紧。每个图标悬停自己的名字(`data-tooltip`,见下「悬停提示」);整排是一个 `role="img"`,读屏把名字用顿号连起来念。和折叠箭头、内容同一行顶对齐。webview 不自己用种类查图标:图标名由宿主放进预览数据的概念列表(`BlockView.concepts`),webview 只按名字画(`kindIcons.tsx` 的 `KIND_ICON_COMPONENTS`)。
|
||||
@@ -185,13 +186,14 @@
|
||||
这组图标由插件自己定义,是一个封闭的集合:契约里的 `KIND_ICON_NAMES`(上表 26 个——命令、管道、执行共用一个,解释器、解析指令共用一个,选项、设置、编译属性共用一个,字段、标签共用一个——加库规则用的 14 个(React 的组件、状态、引用、数据源、派生值、副作用、事件处理函数、渲染输出的 8 个也在里面),lucide 的 kebab-case 名字),类型 `KindIconName` 是它们的联合,概念的 `icon` 只能写其中一个,写别的是类型错误。内置种类 → 图标名在 `contract.ts` 的 `KIND_ICONS`(宿主写进概念列表)。webview 给每个名字配一个逐个 import 的 lucide 图标组件(`kindIcons.tsx` 的 `KIND_ICON_COMPONENTS`,打包只带这些,预览脚本约 157 kB);webview 的 `KindIconName` 照契约手抄,`kindIconNames.test.ts` 核对两边一样。规则要新图标就把名字加进这组、在 webview 配上图标,没有按任意名字找图标的路。
|
||||
- 右上角的图标按钮(原型组件 `Reader / BlockTools`,普通块、属性表块、库规则的卡片共用):只有图标、不带字,名字写在悬停提示和 `aria-label` 里;整排是 `role="group"`(`aria-label="块操作"`)。先是「问 AI」(sparkles 图标,点开 / 收起块下面的问答区,展开时带按下的底色、`aria-expanded`;文件不在工作区文件夹里时没有,见「问 AI」),再是「编辑 / 预览」切换:预览时铅笔「编辑」,编辑时眼睛「预览」、带按下的底色(`--vscode-toolbar-activeBackground`)。按钮宽 24px、高 20px(和种类图标同高),图标 14px、`descriptionForeground` 色;悬停 `--vscode-toolbar-hoverBackground`,键盘聚焦描 1px `--vscode-focusBorder`;Tab 能走到,回车 / 空格切换。
|
||||
- 悬停提示(整个插件的网页只走这一条路,预览和看板共用同一个组件):带提示的元素只写 `data-tooltip="提示"`(名字照旧写在 `aria-label` 里,只有图标的按钮必须有 `aria-label`),页面根上挂一个 `TooltipHost`(`webview-ui/src/components/ui/tooltip.tsx`)统一弹,不用原生 `title`;提示里的换行照样换行(看板摘修复弹框里「迁移」列出的几个文件一行一个);注释、回答里 Markdown 链接的标题(`[文字](网址 "标题")`)也写成 `data-tooltip`。网页的 TSX 里写原生 `title` 属性是 lint 错误(`vscode/eslint.config.mjs`),只有 `iframe` 这种必须带标题的元素例外,组件自己叫 `title` 的属性不算。原因:macOS 上 VS Code 带的 Electron(1.139 是 Electron 43)只在鼠标压着带 `title` 的元素自身边缘时才弹原生提示,停在它里面的图标、文字上不弹(electron/electron#49843,Electron 38 起),种类图标 20px 的框几乎被 16px 的图形占满,基本弹不出来;样子也是系统的。样子照 VS Code 的悬停框:`--vscode-editorHoverWidget-background` 底、`--vscode-editorHoverWidget-border` 边框、`--vscode-editorHoverWidget-foreground` 字、`0 2px 8px --vscode-widget-shadow` 阴影,11px 字,圆角 4px,最宽 22rem;优先在元素上方,上方放不下翻到下方,水平对着元素中间,贴边留 8px,不接鼠标。鼠标停 500ms 才弹,在同一个元素里移动不重新计时,已经弹着时移到另一个带提示的元素上立刻换;移开、移出页面、按下鼠标、按任意键(含 Esc)、滚动就收,收了之后鼠标不离开这个元素不再弹。键盘把焦点移到带提示的元素上(`:focus-visible`)立刻弹,焦点离开就收;提示不是元素自己的名字(`aria-label` 或它的字)时用 `aria-describedby` 挂到元素上,读屏当描述念。
|
||||
- 种类图标和底色按种类区分(颜色见「颜色」);注释块虚线框。
|
||||
- 种类图标和底色按种类区分(颜色见「颜色」);文件开头的说明(种类「注释」)虚线框。
|
||||
- 「注释」一行:讲这块的普通注释不单独成块,是这张卡片上的一行(见「注释挂到它讲的块上」)。属性表卡片(语言的、翻译插件排的、库规则的卡片都一样,宿主统一插,规则、翻译插件不用管)插在第一行(名称这类讲它是谁的一行)后面,有说明(值是 Markdown 的那一行)时插在说明后面,所以是「名称、说明、注释、别的」;一行译文的卡片(条件、循环、语句、调用、返回……)排在译文、摊开实参的表、说明的下面,同属性表的一行(左边「注释」、右边 Markdown)。名字是翻译插件给种类 comment 起的名字(中文直译「注释」)。几段注释(中间隔着空行、或前后两处)各是一段 Markdown,照源码顺序,空行隔开。按「注释的 Markdown 排版」显示(仓库路径链接、不带路径的引用、仓库图片都照常能点),标差异时同属性表的行逐词标。行上右边是「按注释规范重写」按钮(见「重写注释」)。
|
||||
- 内容两种状态,每块单独切:
|
||||
- 预览:函数、类、枚举、异常、导入、常量、变量、解释器、选项、解析指令、阶段、健康检查、启动块是属性表(见下节),注释块是 Markdown 说明(见「注释的 Markdown 排版」),其余块是一行译文;按词着色,等宽字体(中文部分用系统中文字体回退)。一行译文里有跨几行写的调用时,摊开实参的表排在译文下面(见「调用与构造」);块带说明(Python 字段的属性 docstring)时,说明按 Markdown 再排在下面。
|
||||
- 编辑:这一块在源码里的完整代码(按语法树着色):头部连同各子孙块、收尾括号,可以直接改,改完按这整段写回;蓝色边框。按钮换成眼睛「预览」;Esc 也回到预览。
|
||||
- 复合语句(函数、条件、循环……)块的预览只讲它自己的头部那几行(主体交给子块);收尾括号、空行不成块。函数、类的说明(JSDoc / docstring)也算在函数、类块的头部里;Python 常量、变量、字段的属性 docstring 算在它那一块里(中间隔着的空行也是)。
|
||||
- 编辑范围是块的完整范围(`blockView.ts` 的 `blockSpans`,和语言无关):从头部开头,到头部、整条语句、各子孙块里最靠后的那个字符。else、elif、catch 这类展平成兄弟块的子句,整条 if / try 按各块的开头切开:每块到下一块开头之前,最后一块到语句结尾(Shell 的 `fi` 归它);`} else {` 写在一行时两块都含这一行。
|
||||
- 库规则认领的块(数据表卡片等,见「库规则」):种类的图标、颜色和名字由规则给,内容是规则给的属性表;编辑范围同别的块,是原块整条语句(类就是整个类),「编辑」时整段一起改。规则没并进卡片的子块(方法、别的成员)不管写在类主体哪儿(两个字段中间也算),都照源码顺序是卡片的子块,点它们的「编辑」只改它们自己连同子孙那几行。
|
||||
- 预览:函数、类、枚举、异常、导入、常量、变量、解释器、选项、解析指令、阶段、健康检查、启动块是属性表(见下节),文件开头的说明是 Markdown(见「注释的 Markdown 排版」),其余块是一行译文;按词着色,等宽字体(中文部分用系统中文字体回退)。一行译文里有跨几行写的调用时,摊开实参的表排在译文下面(见「调用与构造」);块带说明(Python 字段的属性 docstring)时,说明按 Markdown 再排在下面;块挂着注释时「注释」一行排在最下面。
|
||||
- 编辑:这一块在源码里的完整代码(按语法树着色):挂在它上面的注释、头部连同各子孙块、收尾括号,可以直接改,改完按这整段写回;蓝色边框。按钮换成眼睛「预览」;Esc 也回到预览。
|
||||
- 复合语句(函数、条件、循环……)块的预览只讲它自己的头部那几行(主体交给子块);收尾括号、空行不成块。挂在块上的注释算在块的完整范围里(写在块上面的从注释开头算起,挂在这一层最后一块上的、子块交上来的到注释结尾):差异、跳过去、钉住卡片、总览条、「只看改动」、按行找块都按它,注释那几行改了标的是它挂着的那块。函数、类的说明(JSDoc / docstring)也算在函数、类块的头部里;Python 常量、变量、字段的属性 docstring 算在它那一块里(中间隔着的空行也是)。
|
||||
- 编辑范围是块的完整范围(`blockView.ts` 的 `blockSpans`,和语言无关):从头部和挂在它上面的注释里最靠前的开头,到头部、整条语句、挂在它上面的注释、各子孙块(连同它们的注释)里最靠后的那个字符。else、elif、catch 这类展平成兄弟块的子句,整条 if / try 按各块的开头(连同挂在它上面的注释)切开:每块到下一块开头之前,最后一块到语句结尾(Shell 的 `fi` 归它);`} else {` 写在一行时两块都含这一行。
|
||||
- 库规则认领的块(数据表卡片等,见「库规则」):种类的图标、颜色和名字由规则给,内容是规则给的属性表(宿主再插「注释」一行);编辑范围同别的块,是原块整条语句(类就是整个类)连同挂在它上面的注释,「编辑」时整段一起改。规则没并进卡片的子块(方法、别的成员)不管写在类主体哪儿(两个字段中间也算),都照源码顺序是卡片的子块,点它们的「编辑」只改它们自己连同子孙那几行。
|
||||
- 同一行不会同时在两处能改:一块在编辑时它的子孙都不画(代码都在它的编辑框里),回到预览就照原样出来;点一块的「编辑」时,编辑范围和它重叠的别的块(祖先、子孙、共用一行的兄弟块)退出编辑。跳到定义的目标块正被盖住时闪盖住它的那块。
|
||||
- 折叠:函数、类、枚举、异常块和库规则的卡片打开时默认收起子块(属性表照常显示),其余块默认展开;用户点过折叠箭头的块按他点的,记在视图状态里(见「预览数据与消息」)。
|
||||
- 顶部筛选栏:见「筛选」;翻译下拉框(多于一种翻译时才显示)也在栏里。
|
||||
@@ -207,6 +209,7 @@
|
||||
3. webview 只按属性 id / 值 id 筛,显示翻译插件给的名字。
|
||||
- 下拉框:这份文件里有两种以上值的属性各一个(只有一种值的不给——筛它等于按种类筛);只有一种值、但这个值正被去掉的也给,不然藏起来的块在栏上找不到原因。排列:通用属性按契约的顺序(种类、访问级别、异步、抽象、仅类型),语言自己的属性按在文件里第一次出现的先后排在后面。下拉菜单顶上一行「全选 · 取消全选」,分隔线下面是勾选列表,列出这份文件里出现的值(按第一次出现的先后)和各有几块(所有层的块都算,例如「私有 3 / 公共 3」)。
|
||||
- 全选 / 取消全选:把这份文件里这个属性出现的值一起勾上 / 去掉,和逐个勾一样记下来;别的文件才有的值记着的去掉状态不动(筛选整个工作区共用)。取消全选后有这个属性的块全藏起来,没有这个属性的照常显示;菜单不关,可以接着勾。
|
||||
- 种类「注释」只剩文件开头的说明:挂在块上的注释跟着它的块显示、藏起来,按种类去掉「注释」只藏文件开头的说明(文件里没有时这个值不出现)。
|
||||
- 规则:同一属性里勾着的值满足一个就显示,不同属性要同时满足;块没有某个属性就不受那个属性的筛选影响(条件、返回块没有访问级别,按访问级别筛时照常显示);块被筛掉,连同它的子块一起藏,不留空位,层级竖线跟着变短;子块都被筛掉的块不给折叠箭头。
|
||||
- 汇总:什么都没筛掉时右边写「共 N 块」(N 是整份文件所有层的块数);筛掉了写「已隐藏 N 块 · 清除」,N 只数直接被筛掉的块,跟着藏起来的子块不算;点「清除」整份筛选清空。页面上一块都不剩时写「所有块都被筛选隐藏了。」
|
||||
- 下拉框上的字:没去掉值时是属性名;去掉了(边框换 `--vscode-focusBorder`)勾着一种写「访问级别:公共」,几种写「种类:已选 11 种」,一种都不勾写「种类:未选」。
|
||||
@@ -286,9 +289,9 @@
|
||||
- TypeScript / JavaScript:`extends` 后面的类名(`X`、`ns.X` 取 X,泛型实参不看;`Mixin(Base)` 这类调用不看)以 `Error` 或 `Exception` 结尾。自带的 `Error`、`TypeError`、`RangeError`、`AggregateError`……都以 Error 结尾,`DOMException` 以 Exception 结尾,不用另列。
|
||||
- 两种语言都算:父类是同一文件里认出来的异常类,按名字认,不论写在前面还是后面、嵌套在哪,一层层往下传(`class Deeper(Late)`、`class Late(Base)`、`class Base(Exception)` 三个都是)。
|
||||
- 按命名习惯认的部分和它的限制:父类从别的文件导入时语言插件看不到那个文件,只能按名字认(PEP 8 要求异常类名以 Error 结尾,`AppException` 这种以 Exception 结尾的也常见)。所以父类名不合习惯(从别处导入的 `NotFound`、`Forbidden` 当父类)的认不出来,照常是类块;名字合习惯却不是异常的父类(普通类起名 `RenderError`)会被当成异常。同一文件里按名字认,不看作用域(同名的两个类当成一个)。
|
||||
- 类属性(进「属性」表):Python 是类主体里给一个名字赋值的语句(`x = 1`、`x: int = 1`、只写注解的 `x: int`),连着赋值(`a = b = 1`)、解构赋值不算;TypeScript / JavaScript 是类字段(`public_field_definition` / `field_definition`,含 static;值是带语句块主体的函数、类表达式的照常是方法、类块)。说明同枚举成员:紧挨在上面的注释块、这一行行尾的注释、Python 紧跟在后面的属性 docstring,原文用空格连起来。类 docstring 里谷歌写法的 `Attributes:` 一节照原文留在「说明」里,不拆到各属性的说明格子。
|
||||
- 类属性(进「属性」表):Python 是类主体里给一个名字赋值的语句(`x = 1`、`x: int = 1`、只写注解的 `x: int`),连着赋值(`a = b = 1`)、解构赋值不算;TypeScript / JavaScript 是类字段(`public_field_definition` / `field_definition`,含 static;值是带语句块主体的函数、类表达式的照常是方法、类块)。说明同枚举成员:讲它的注释(挂在它上面的)、这一行行尾的注释、Python 紧跟在后面的属性 docstring,原文用空格连起来。类 docstring 里谷歌写法的 `Attributes:` 一节照原文留在「说明」里,不拆到各属性的说明格子。
|
||||
- 构造参数:Python 是 `__init__` 的参数去掉第一个(self;第一个是 `*args` 这类时不去),TypeScript / JavaScript 是 `constructor(...)` 的参数(参数属性 `public code?: string` 也是一个参数);写了几个取最后一个(重载的实现写在最后)。`*`、`/` 分隔符同函数的输入参数,不算参数。类里没写构造函数(继承父类的)时没有这一行。
|
||||
- 并进属性表的子块:各个类属性连同紧挨在它前面的注释块;构造函数、方法、别的语句、讲方法的注释、最后面的注释照常是子块(不管写在哪),默认收起。异常块的头部(编辑范围)是整个类:从说明、装饰器开始,到类连同各子块的最后一行,「编辑」时整段一起改,盖住留下的子块(同库规则的卡片)。
|
||||
- 并进属性表的子块:各个类属性(讲它的注释挂在它上面,跟着并进来,是这个属性的说明);构造函数、方法、别的语句照常是子块(不管写在哪,讲它们的注释是它们卡片的「注释」一行),默认收起。异常块的头部(编辑范围)是整个类:从说明、装饰器开始,到类连同各子块的最后一行,「编辑」时整段一起改,盖住留下的子块(同库规则的卡片)。
|
||||
- 语言插件报的已经是异常块,库规则只认类块,所以异常类不交给库规则:`@dataclass` 装饰的异常类照样是异常卡片,`@dataclass` 写在「装饰器」一行,注解的字段在「属性」表里。
|
||||
- 跳到定义:类名是块自己的名字(闪整块),属性名只闪「属性」表里那一行,构造函数的参数只闪「构造参数」表里那一行(构造函数自己的「输入参数」也标了同一个参数,页面上先找到的是卡片里这一行);中文名(`Annotated[…, Comment("…")]`、行尾 `# @Comment …`)照常换属性格子里的名字,行尾记号不进说明。
|
||||
|
||||
@@ -470,9 +473,9 @@
|
||||
|
||||
### 注释的 Markdown 排版
|
||||
|
||||
- 用在:注释块(`#`、`//`、`/* */`、不挂在函数、类上的 JSDoc、Python 模块开头的 docstring 和别的当注释用的单独字符串)的预览,函数、类、常量、变量属性表的「说明」,参数表的「说明」列、「异常」表、输出参数后面的 `@return`,字段译文下面的说明。视图数据里它们是 `{ markdown }`(见「通用契约」的 `Markdown`),webview 按数据决定怎么渲染,不猜。
|
||||
- 用在:卡片的「注释」一行(`#`、`//`、`/* */`、没挂成说明的 JSDoc、Python 当注释用的单独字符串)、文件开头的说明(同样的注释,和 Python 模块开头的 docstring、Rust 的 `//!`)的预览,函数、类、常量、变量属性表的「说明」,参数表的「说明」列、「异常」表、输出参数后面的 `@return`,字段译文下面的说明。视图数据里它们是 `{ markdown }`(见「通用契约」的 `Markdown`),webview 按数据决定怎么渲染,不猜。
|
||||
- 原文:翻译插件去掉注释符号(`#`、`//`、`/*` `*/` 和每行开头的 `*`)、引号和中文名记号(`SourceDocument.markers`,见「中文名」),再去掉行尾空白、首尾空行和共同缩进,保留换行,不做别的转换。一个注释节点(块注释、docstring)的第一行紧跟在注释符号 / 引号后面,不参与算共同缩进(同 PEP 257);几条行注释连成的一块每行地位相同,第一行也算,缩进四格的代码块才留得住。
|
||||
- 块标签:说明(`Translator.doc` 读的:函数、类这些定义的说明,字段、成员的说明,库规则取的说明)的原文按 KDoc 拆成正文和块标签(`Doc`,解析在 `docTags.ts`,各卡片共用);单独成块的注释照原文显示,不拆。
|
||||
- 块标签:说明(`Translator.doc` 读的:函数、类这些定义的说明,字段、成员的说明,库规则取的说明)的原文按 KDoc 拆成正文和块标签(`Doc`,解析在 `docTags.ts`,各卡片共用);「注释」一行和文件开头的说明照原文显示,不拆。
|
||||
- 认 `@param`、`@return`(`@returns` 同义)、`@throws`(`@exception` 同义)。一行(去掉开头空白)以标签开头算一条;后面接着的行(不是空行、不以 `@` 开头)续在这条后面(去掉开头空白、换行留着);空行结束这条,以 `@` 开头的行也结束上一条。围栏代码块里的行不认标签。
|
||||
- `@param 名字 说明`;JSDoc 的 `@param {类型} 名字 - 说明`、`@param [名字] 说明`、`@param [名字=默认值] 说明` 也认(类型、横杠、默认值去掉)。`@return 说明`、`@returns {类型} 说明` 同样去掉类型。`@throws 异常 触发条件`:异常是一个名字、`[Foo]`、`[说法](路径#Foo)` 或 JSDoc 的 `{Foo}`,只是名字的写成不带路径的引用 `[Foo]`。几条 `@return` 用空行连成一段。
|
||||
- 正文是拿掉这几种标签后剩下的行(标签前后的正文都留着),去掉首尾空行,连着的几个空行并成一个;只写了标签时没有正文。别的标签(`@see`、`@since`)留在正文里。
|
||||
@@ -482,7 +485,7 @@
|
||||
- 安全:源码里的 HTML 当文字显示;链接认 http / https / mailto,带协议的网址和邮箱自动成链接(`sample.py` 这种不带协议的不算),别的写法(`javascript:`、`command:`、`./`、`..`、绝对路径、盘符)照原文显示。http / https / mailto 由 VS Code 的 webview 自己拦下、交给宿主在外部打开,不用另发消息。http / https 图片不渲染(webview 的 CSP 不放行外部图片),`` 显示成 `!` 加链接。仓库内图片按原图比例显示,点了打开原图,没有就写「找不到图片」和路径。
|
||||
- 仓库路径链接(`[名字](从仓库根起的路径)`,可带 `#类名` 或 `#类名.成员`)能点,点了打开文件并跳到符号,和 ⌘ / Ctrl + 点击跳到别的文件里的定义是同一条路(`editor/openTarget.ts` 的 `openingFor`,见「跳到定义」):语言有代码阅读的在预览所在的编辑器组用预览打开、滚过去、闪符号那处(不带符号的只打开预览),没有代码阅读的用 VS Code 默认的打开方式(普通编辑器选中符号的名字,图片看图);指到这份文件里的符号时在本预览里滚过去、闪一下(同下面的引用)。指到目录的在代码阅读侧栏的树上定位(展开并选中,和侧栏跟着当前文件走是同一个定位;侧栏没露着时亮出来),不切到 VS Code 资源管理器;树上没有(开着筛选时没摆它)时提示「侧栏的树上没有 …」,不退出筛选。
|
||||
- 不带路径的引用(KDoc 的 `[Name]`、`[Class.member]`)能点:
|
||||
- 认哪些:只在注释的 Markdown 里认(说明正文、参数说明、`@return`、「异常」表、单独成块的注释,连带增删的;问 AI 的回答不认)。方括号里是标识符(ASCII 字母、数字、下划线、`$`,点分开的几段);中文这类不是标识符的(`[会话进展]`)照原样是文字。反引号里的是代码;紧跟在名字、`]`、`)` 后面的方括号是下标(`items[i]`、`a[0][1]`、`f()[k]`);后面紧跟 `(…)` 的是完整链接、紧跟 `[` 的是参考式链接,都不算。webview 在 `markdown.ts` 加一条行内规则(排在 markdown-it 的 link 后面,渲染时 `env.symbolLinks` 为真才认),写成地址为 `symbol:名字` 的链接(作者写不出这种地址,`validateLink` 不放行)。
|
||||
- 认哪些:只在注释的 Markdown 里认(说明正文、参数说明、`@return`、「异常」表、「注释」一行、文件开头的说明,连带增删的;问 AI 的回答不认)。方括号里是标识符(ASCII 字母、数字、下划线、`$`,点分开的几段);中文这类不是标识符的(`[会话进展]`)照原样是文字。反引号里的是代码;紧跟在名字、`]`、`)` 后面的方括号是下标(`items[i]`、`a[0][1]`、`f()[k]`);后面紧跟 `(…)` 的是完整链接、紧跟 `[` 的是参考式链接,都不算。webview 在 `markdown.ts` 加一条行内规则(排在 markdown-it 的 link 后面,渲染时 `env.symbolLinks` 为真才认),写成地址为 `symbol:名字` 的链接(作者写不出这种地址,`validateLink` 不放行)。
|
||||
- 指到哪(扩展端,`symbolLinks.ts` 的 `resolveReference`,按 KDoc 的规矩):① 本文件定义的:文档符号(`vscode.executeDocumentSymbolProvider`,同仓库链接找符号那一套)顶层名字对上的(类、函数、常量、变量;落在导入语句里的名字不算),`Class.member` 在它底下找成员;② 本文件导入进来的:名字(`Class.member` 的第一段)是某条导入引进来的(预览已有的导入块 facts,`ImportFacts.items`:起了别名的按别名认,问原来那个名字;整模块导入按第一节认,起了别名的问最后一节),在导入语句里这个名字的位置上问语言扩展定义在哪(`vscode.executeDefinitionProvider`,同跳到定义,几处取第一处),`Class.member` 再在目标文件的文档符号里找:定义落在哪个符号里就在它底下找,落在文件开头(导入的是模块)就从顶层找;③ 都没有就找不到。本文件定义了这个名字、却没有这个成员时也算找不到,不再去导入里找。
|
||||
- 问答同仓库路径链接(`useRepoLinks`、`RepoLinks`):画出来后把页面上的仓库路径和引用一起发去问(`checkRepoLinks { paths, symbols }` → `repoLinksChecked { missing, unresolved }`),问到之前是普通链接,找不到的画成坏链接(红色波浪线,悬停「找不到」);文档换了版本(收到 `document`)再问一次,引用跟着源码变。点了发 `openRepoLink`(不带 `path`,只带 `symbol`):找到了同完整链接的后半段打开目标(语言有代码阅读的用预览、滚过去、闪,没有的用默认的打开方式选中名字),目标在这份文件里时在本预览里滚过去、闪一下(同跳到定义的闪);找不到就标坏。
|
||||
- 样子:正文用界面字体(`--vscode-font-family`、`--vscode-font-size`)、comment 色、行高 20px,一行注释和一行译文一样高;行内代码用编辑器字体、`--vscode-textCodeBlock-background` 底;围栏代码块用编辑器字体和字号、同样的底,长行折行;段落、列表、代码块、表格之间 6px;标题只比正文稍大(h1 1.15em、h2 1.08em,其余同正文,加粗);链接 `--vscode-textLink-foreground`;引用左边 3px `--vscode-textBlockQuote-border` 竖线、`--vscode-textBlockQuote-background` 底;表格 1px 细线。
|
||||
@@ -618,7 +621,7 @@
|
||||
|
||||
块的位置记号(`BlockView.anchor`,`qa/anchor.ts`):
|
||||
|
||||
- 扩展端生成视图数据时按源码先后逐块给:有名字的块(`defines` 的来源:函数名、类名、枚举名、单个变量名,库规则卡片取规则给的定义范围)是外层各个有名字的块加自己的「种类 名字」,例如 `class ReferralRelation > function display`;没名字的块(条件、语句、返回、注释、导入、多变量声明……)是外层最近的有名字的块加「种类 @源码哈希」,哈希是这块头部那几行(库规则认领的块是整条语句)去掉所有空白后的 SHA-1 前 8 位,改它的子块不影响它的记号,例如 `function display > if @3fa1c2d0`。同一层里记号相同的(同名的两个函数、一模一样的两行语句)按源码先后在后面补 `[1]`、`[2]`。
|
||||
- 扩展端生成视图数据时按源码先后逐块给:有名字的块(`defines` 的来源:函数名、类名、枚举名、单个变量名,库规则卡片取规则给的定义范围)是外层各个有名字的块加自己的「种类 名字」,例如 `class ReferralRelation > function display`;没名字的块(条件、语句、返回、文件开头的说明、导入、多变量声明……)是外层最近的有名字的块加「种类 @源码哈希」,哈希是这块头部那几行(库规则认领的块是整条语句)去掉所有空白后的 SHA-1 前 8 位,改它的子块不影响它的记号,例如 `function display > if @3fa1c2d0`。同一层里记号相同的(同名的两个函数、一模一样的两行语句)按源码先后在后面补 `[1]`、`[2]`。
|
||||
- 所以:上面插几行、改缩进空白、改别的函数的名字,记号都不变;有名字的块改了主体、签名还认得;没名字的块自己的源码改了,记号就变了,旧问答成了「找不到原来位置的」(不显示)。种类用视图数据的种类(库规则的卡片是规则的种类 id)。
|
||||
- webview 只拿记号比相等,不拆开看。
|
||||
|
||||
@@ -630,6 +633,17 @@
|
||||
- 预览要能读到 `.spx/code-qa/`:打开预览时把这份文件所在工作区文件夹的这个目录加进 webview 的 `localResourceRoots`,发给预览的问答里图片换成 `webview.asWebviewUri` 的地址。
|
||||
- 在 VS Code 里改名、挪位置、删除文件 / 目录时问答跟着走(同文件注释);外部改了 `code-qa.json`(git pull、手改)文件监听重读,开着的预览跟着变。
|
||||
|
||||
### 重写注释
|
||||
|
||||
按写注释的技能(`/ecc:writing-code-comments`)给一块代码重写讲它的普通注释,没有就新写一段。
|
||||
|
||||
- 按钮(`MessageSquareText` 图标,只有图标,悬停 / 读屏「按注释规范重写」,块还没有注释时是「按注释规范写注释」):每块代码都有。卡片有「注释」一行时画在这一行右边,没有时排在右上角那排按钮里(「问 AI」左边);文件开头的说明卡片排在右上角。正在重写时不能再点。定义卡片浮窗里、删掉的块没有;嵌着的代码里的块(Dockerfile RUN 里的 shell)、语言没给行注释记号(`LanguageAdapter.lineComment`)又还没有注释的块没有(`BlockView.commentTarget` 没有)。
|
||||
- 改哪儿(`BlockView.commentTarget`,扩展端 `blockView.ts` 算):块前面挂着普通注释时换掉它们(从第一段开头到最后一段结尾,几段中间隔着的空行一起换掉,写成一段);文件开头的说明卡片换掉它自己;块还没有前面的注释时新写一段,插在块的第一行(连同它的说明、装饰器)上面。说明(docstring、JSDoc、`///`)不动;挂在块后面、子块交上来的注释不动。
|
||||
- 问模型:同「问 AI」用 Claude Code 命令行、在这份文件所在的工作区文件夹里跑、用选的 profile、只读(`--tools Read,Grep,Glob`、`--allowedTools Read,Grep,Glob`、`--permission-mode dontAsk`、`--strict-mcp-config`:它能读那个文件,改不了,写回归扩展),从 stdin 发的只有一句:`/ecc:writing-code-comments <路径>:<起>-<止>`,路径相对 claude 的工作目录、用 `/` 分隔,行号 1 起,是这块代码的完整范围(连同挂在它上面的注释;文件开头的说明卡片是它自己那几行),别的不说(`commentRewrite.ts` 的 `commentRewritePrompt`)。文件有没保存的修改时不问(模型读的是磁盘上的文件),直接失败「先保存再重写注释」。
|
||||
- 结果按 JSON Schema 交(`--json-schema '{"type":"object","properties":{"body":{"type":"string"}},"required":["body"],"additionalProperties":false}'`):模型调 Claude Code 的 `StructuredOutput` 工具交结果,result 行的 `structured_output.body` 是注释正文(不带注释符号)。不读模型的自由文字:只回了一段话、`structured_output` 没有或 `body` 是空的,都算失败,文件不动。
|
||||
- 过程(`rewriteProgress`):问的那一句、正文逐字长出来(`--include-partial-messages` 时 `StructuredOutput` 的输入逐段来,按写到一半的 JSON 读出已经写出来的正文)、正在读什么(「读取 a.py」);块下面同问答区的样子显示(`RewriteThread`),能叫停。
|
||||
- 写回(扩展端,`WorkspaceEdit`,能撤销):换掉时套回原来那段注释的定界符和缩进(Python 三引号、`#` / `//` 行注释、`/* */` 块注释,`refillComment`;几段隔着空行的照第一段的写法);新写时用语言的行注释记号(`#`、`//`)一行一行写,缩进同块的第一行,空行写成只有记号的一行。写之前核对这块代码的那几行和问的时候一样,变了就不写(「这块代码在重写期间变了」);定界符认不出、编辑器没接受也不写。结束发 `rewriteEnd`(done / failed 带原因 / stopped),失败另弹一条错误提示。
|
||||
|
||||
## 通用契约
|
||||
|
||||
放在 `vscode/src/codeReader/contract.ts`,语法树类型用 `@vscode/tree-sitter-wasm` 自带的 web-tree-sitter 类型。
|
||||
@@ -839,6 +853,8 @@ export interface BlockShape {
|
||||
/** 块自己显示 / 编辑的那一段:复合语句只到主体开始之前,其余是整条语句;块自己的说明(facts.doc、TextBlock.doc)也算在里面。 */
|
||||
header: SourceSpan
|
||||
children: CodeBlock[]
|
||||
/** 讲这块的普通注释(不是说明),照源码顺序;由 attachComments(languages/shared.ts)挂上,预览排成卡片的「注释」一行,块的编辑范围连同它们。见「注释挂到它讲的块上」。 */
|
||||
comments?: CommentBlock[]
|
||||
/** 语言自己报的筛选属性:通用词表以外的(Rust unsafe: 'true'),或 facts 表达不了的通用属性值(Kotlin access: 'internal',盖过推出来的);kind 填了不算。 */
|
||||
attributes?: BlockAttributes
|
||||
}
|
||||
@@ -861,7 +877,7 @@ export type DocumentedBlock = FunctionBlock | ClassBlock | EnumBlock | Exception
|
||||
export type BlockFacts = FactBlock extends infer B ? B extends FactBlock ? Pick<B, 'kind' | 'facts'> : never : never
|
||||
|
||||
export type TextKind = Exclude<BlockKind, FactBlock['kind']>
|
||||
/** 预览成一行译文的块(注释块是 Markdown 说明)。 */
|
||||
/** 预览成一行译文的块(文件开头的说明是 Markdown)。 */
|
||||
export interface TextBlock extends BlockShape {
|
||||
kind: TextKind
|
||||
doc?: Node // 同 VariableFacts.doc:Python 字段后面紧跟的属性 docstring;预览在译文下面按 Markdown 显示(Translator.doc)
|
||||
@@ -871,6 +887,9 @@ export interface TextBlock extends BlockShape {
|
||||
|
||||
export type CodeBlock = TextBlock | FactBlock
|
||||
|
||||
/** 一段注释:相邻行同一写法的行注释合成的一段(node 是第一条,头部盖住全部)、一条块注释或 Python 当注释用的字符串。文件开头的说明单独成块,别的挂在讲的块上(BlockShape.comments)。 */
|
||||
export interface CommentBlock extends TextBlock { kind: 'comment' }
|
||||
|
||||
/** 着色用的词性,源码着色和译文着色共用。 */
|
||||
export type TokenRole =
|
||||
| 'keyword' // 流程关键字:import from export if else for return try catch await …
|
||||
@@ -927,7 +946,7 @@ export interface DocThrows { exception: Markdown, when: Markdown }
|
||||
*/
|
||||
export interface Doc { body?: Markdown, params: DocParam[], returns?: Markdown, throws: DocThrows[] }
|
||||
|
||||
/** 预览里显示的一段文字:着色的词(一行译文、属性值),或整段 Markdown 说明(注释块、函数和类的说明)。 */
|
||||
/** 预览里显示的一段文字:着色的词(一行译文、属性值),或整段 Markdown 说明(注释、函数和类的说明)。 */
|
||||
export type PreviewText = Inline[] | Markdown
|
||||
|
||||
/**
|
||||
@@ -957,7 +976,7 @@ export interface PropertyRow extends Defines { label: string, value: PreviewText
|
||||
/** 一张带表头和边框的表:列名,每行几列对齐的格子,同 PropertyRow 给了 columns 的子行。 */
|
||||
export interface PreviewTable { columns: string[], items: PropertyItem[] }
|
||||
|
||||
/** 一行译文的块翻出来的:一行译文(注释块是 Markdown 说明);跨几行写的调用还有摊开各个实参的表,预览排在这一行下面。 */
|
||||
/** 一行译文的块翻出来的:一行译文(注释块——文件开头的说明、挂在块上的注释——是 Markdown 原文);跨几行写的调用还有摊开各个实参的表,预览排在这一行下面。 */
|
||||
export interface TextTranslation { text: PreviewText, table?: PreviewTable }
|
||||
|
||||
/** 语言插件:语法树 → 代码块树,外加只有它懂、翻译插件翻表达式时要用的信息(叶子的词性、写在表达式里的遍历的结构)。 */
|
||||
@@ -971,6 +990,8 @@ export interface LanguageAdapter {
|
||||
toBlocks: (root: Node, source: string, languageId: string) => CodeBlock[]
|
||||
/** 给叶子节点定词性:源码着色用它,译文里照抄的词也按它着色、按它认出能查定义的名字。 */
|
||||
tokenRole: (leaf: Node) => TokenRole
|
||||
/** 行注释的记号(`#`、`//`):「重写注释」给还没有注释的块新写一段时用它;不填就不能新写。 */
|
||||
lineComment?: string
|
||||
/** node 是写在表达式里的遍历(推导式、生成器表达式)时给出它的结构,别的节点没有;没有这种写法的语言不填。 */
|
||||
iteration?: (node: Node) => IterationFacts | undefined
|
||||
/** node 是一次调用(含新建对象)时给出它的结构,别的节点没有;没给的语言不展开调用,照常一行译文。 */
|
||||
@@ -1036,7 +1057,7 @@ export interface Translator {
|
||||
label: string // '中文直译'
|
||||
languageIds: string[]
|
||||
displayLanguage: string // 译文用的语言('zh'):库规则按它挑自己的词表
|
||||
translate: (block: TextBlock, document: SourceDocument) => TextTranslation // 只翻 header 那一段;注释块给 Markdown 原文;跨几行写的调用带实参表
|
||||
translate: (block: TextBlock, document: SourceDocument) => TextTranslation // 只翻 header 那一段;注释块(文件开头的说明、挂在块上的注释)给 Markdown 原文;跨几行写的调用带实参表
|
||||
describe: (block: FactBlock, document: SourceDocument) => PropertyRow[] // 函数、类、枚举、异常、导入、常量、变量块 → 属性表
|
||||
expression: (node: Node, document: SourceDocument) => Inline[] // 一个表达式 / 类型节点整个翻成一行译文,译法同属性表的值;库规则借它
|
||||
doc: (node: Node, document: SourceDocument) => Doc | undefined // 说明文字(注释、docstring、当说明用的字符串)→ 正文和块标签(Doc);正文同属性表的「说明」;连着几行的行文档注释(Rust 的 `///`)node 是第一条,翻译插件自己往下连
|
||||
@@ -1064,10 +1085,10 @@ export interface KindBadge { label: string, color: ThemeColor, icon: KindIconNam
|
||||
/** 库规则认领一块后给出的替身,下面挂着原块留下的子块:规则自己的卡片,或认成的现成属性表块;这块讲在了别的卡片里时是略去它。 */
|
||||
export type RuleBlock = RuleCard | RuleFacts | RuleOmit
|
||||
|
||||
/** 这块讲在了别的卡片里,不再单独成块(React 的 "use client" 讲成组件卡片的「客户端组件」标签);不能有子块。 */
|
||||
/** 这块讲在了别的卡片里,不再单独成块(React 的 "use client" 讲成组件卡片的「客户端组件」标签);不能有子块,也不能挂着注释(注释没地方放)。 */
|
||||
export interface RuleOmit { omit: true }
|
||||
|
||||
/** 规则自己的卡片:一张属性表。种类(badge)决定筛选和边框色;卡片左边的图标是语言的概念再加这个种类、以及 concepts。 */
|
||||
/** 规则自己的卡片:一张属性表。种类(badge)决定筛选和边框色;卡片左边的图标是语言的概念再加这个种类、以及 concepts。原块的「注释」一行由宿主插进 rows,规则不管。 */
|
||||
export interface RuleCard {
|
||||
kind: string // 种类 id,「规则 id.名字」(sqlalchemy.table):筛选的 kind 值,要稳定
|
||||
badge: KindBadge // 种类的名字、颜色、图标;筛选栏里这个种类也叫这个名字,卡片边框用这个颜色
|
||||
@@ -1075,7 +1096,7 @@ export interface RuleCard {
|
||||
rows: PropertyRow[]
|
||||
defines?: SourceRange // 块自己的名字(类名):跳到的定义是它时闪整块
|
||||
attributes?: BlockAttributes // 规则自己的筛选属性,叠在宿主从原块推出的上面;kind 填了不算;名字由 LibraryRule.attributeNames 给
|
||||
absorbs: CodeBlock[] // 并进来的子块(原块 children 里的对象本身),不再单独成块;没并的照源码顺序留作子块,编辑范围同别的块,是原块整条语句
|
||||
absorbs: CodeBlock[] // 并进来的子块(原块 children 里的对象本身,讲它的注释在它的 comments 里,跟着并进来),不再单独成块;没并的照源码顺序留作子块,编辑范围同别的块,是原块整条语句
|
||||
slots?: RuleSlot[] // 挂在卡片某一行的子行上、点子行才展开的子块,一块只能放一处
|
||||
}
|
||||
|
||||
@@ -1196,7 +1217,7 @@ export interface CommandRule {
|
||||
- 注册:`CodeReaderApi.registerLibraryRule(rule)`,返回 `Disposable`;内置规则走同一个 API。
|
||||
- 必须给:`id`、`label`、`languageIds`、`libraries`(关心的库)、`claim`(看一块,认领就返回替身 `RuleBlock`,不认返回 `undefined`)。
|
||||
- 替身(`RuleBlock`)三种,按有没有 `omit`、`as` 分:
|
||||
- 略去(`RuleOmit`,`{ omit: true }`):这块讲在了别的卡片里(React 文件开头的 `"use client"` 讲成组件卡片的「客户端组件」标签,组件上面没并进块头部的 JSDoc 讲成「说明」),预览不画它、不占块的位置(后面的块 id 接着往下数)。它不能有子块,有子块时宿主当替身不合约定。
|
||||
- 略去(`RuleOmit`,`{ omit: true }`):这块讲在了别的卡片里(React 文件开头的 `"use client"` 讲成组件卡片的「客户端组件」标签),预览不画它、不占块的位置(后面的块 id 接着往下数)。它不能有子块、不能挂着注释(注释没地方放),有时宿主当替身不合约定。
|
||||
- 认成现成的属性表块(`RuleFacts`):`as` 是种类和 facts(`BlockFacts`,例如 `{ kind: 'enum', facts: EnumFacts }`),`absorbs` 同卡片。宿主把原块换成这种块(节点不变,头部是原块整条语句,子块是留下的),此后和语言插件报的这种块完全一样:翻译插件的 `describe` 排属性表、种类名取翻译插件的、颜色取这个种类的、筛选属性从 facts 推、块自己的名字从 facts 取。规则不给用词,也不给标签和颜色。只要检查并进来的是不是这块的子块。
|
||||
- 规则自己的卡片(`RuleCard`),下面几条都说的是它。
|
||||
- 卡片必须给:`kind`(写成「规则 id.名字」,宿主核对前缀;筛选记住的就是它,要稳定)、`badge`(种类的名字、暗 / 亮两种颜色和 lucide 图标名)、`rows`(用现成的 `PropertyRow`:属性名 + 着色的值或 Markdown,表格就是带 `columns` 的子行)、`absorbs`(并进来的子块)。可以给:`defines`(块自己的名字,跳到定义是它时闪整块)、`attributes`(自己的筛选属性)、`concepts`(额外认出的概念,排在种类图标后面)、`slots`(挂在卡片某一行的子行上、点子行才展开的子块,见下);表格子行填 `PropertyItem.defines`(字段名),跳到这个定义时只闪那一行。
|
||||
@@ -1209,7 +1230,7 @@ export interface CommandRule {
|
||||
- 启用:宿主收集这份源码里各层导入块的 `ImportFacts.sources`(去掉引号),有一个等于规则的某个库、或以「库.」「库/」「库::」开头(子模块;Rust 的路径用 `::`,`use axum::routing::get` 的来源是 `axum::routing`),规则才对这份源码启用。规则不用自己读导入语句。`libraries` 是空数组的规则不看导入,`languageIds` 里这几种语言的源码都启用(React:新的 JSX 写法不用导入 react。Pydantic:子类文件常常只导入父模型、不再导入 pydantic,见「内置:Pydantic 数据模型」)。
|
||||
- 认领:宿主从顶层往下每块问一遍启用的规则,按注册顺序,第一个认领的算(先注册的优先);被认领的块留下的子块照样问。
|
||||
- 出错:规则抛错、或替身不合约定(种类 id 没带规则 id 前缀、并进来的不是这块的子块、属性表里的引用标的不是自己 / 规则没给 `resolve` / 引用的段没带下标、挂在子行上的块不是留下的子块 / 放了几处 / 没有那一行或子行、要略去的块还有子块)时,宿主记一条警告日志(输出面板「Superpowers」),当它没认、接着问下一个规则;都没认这块照常显示。预览不会因为规则出错而失败。
|
||||
- 并进来的子块:不再单独成块,由规则挑(`absorbs`),宿主不替规则多并。没并进来的子块(方法、规则不讲的注释)不管写在哪(字段中间也算),都照源码顺序是替身的子块,预览里照常看得见。替身的编辑范围同别的块,是原块整条语句(从头部开始,到原块连同各子块的最后一行,类就是整个类),盖住留下的子块的行:替身编辑时预览不画这些子块,同一行不会同时在两处能改(见「预览(代码块树)」)。内置规则并成员时连同紧挨在它前面的注释块一起并(讲的是这个成员),讲方法的注释、最后面的注释照常留下。
|
||||
- 并进来的子块:不再单独成块,由规则挑(`absorbs`),宿主不替规则多并。没并进来的子块(方法、别的成员)不管写在哪(字段中间也算),都照源码顺序是替身的子块,预览里照常看得见。替身的编辑范围同别的块,是原块整条语句(从头部开始,到原块连同各子块的最后一行,类就是整个类),盖住留下的子块的行:替身编辑时预览不画这些子块,同一行不会同时在两处能改(见「预览(代码块树)」)。讲成员的注释挂在成员上(`BlockShape.comments`),成员并进来时跟着并进来,内置规则拿它当成员的说明;讲方法的注释挂在方法上,照常是方法卡片的「注释」一行。
|
||||
- 卡片在预览里:左边的图标是语言的概念(原来的类、函数……)再加 `badge` 这一个、以及 `concepts`(同一个 id 只留第一个),悬停各自的名字;卡片边框色取 `badge.color`(暗色、亮色主题各取一个),内容是 `rows`,挂在子行上的子块展开时画在它那一行下面(收起这一行时它们跟着收起;画成一层块,同块树),不算卡片的子块(卡片的折叠箭头只管后面留下的子块);筛选的 `kind` 是替身的种类 id,其余属性从原块推出(原来的类是公共的,数据表也是公共的),叠上规则给的(规则自己的属性叫 `LibraryRule.attributeNames` 给的名字,规则起名时抛错记日志、照写 id);筛选栏里这个种类叫 `badge.label`;和类块一样默认收起子块。多了图标不改筛选、不改边框色。
|
||||
|
||||
### 规则自己查定义
|
||||
@@ -1287,7 +1308,7 @@ export interface CommandRule {
|
||||
|
||||
说明:`comment=` 的字符串(comment 色);没写 `comment=` 时用字段的属性 docstring(`context.doc` 给的原文,comment 色;它随字段并进卡片)。关系的目标取第一个位置参数(字符串去掉引号),没写就用 `Mapped[...]` 里的类型;说明写「对方字段 X」(`back_populates` / `backref`)、「单个对象」(`uselist=False`)、「中间表 X」(`secondary`),用 ` · ` 隔开。
|
||||
|
||||
并进卡片的子块:`__tablename__`、`__table_args__`、每个字段和关系的赋值,连同紧挨在它们前面的注释块;`__mapper_args__`、普通属性、方法(写在两个字段中间也算)和讲它们的注释照常是子块。
|
||||
并进卡片的子块:`__tablename__`、`__table_args__`、每个字段和关系的赋值(讲它们的注释跟着并进来);`__mapper_args__`、普通属性、方法(写在两个字段中间也算)照常是子块,讲它们的注释是它们卡片的「注释」一行。
|
||||
|
||||
样例(luffy `referral/models.py` 的 `ReferralRelation`,测试里逐字核对):
|
||||
|
||||
@@ -1393,8 +1414,8 @@ export interface CommandRule {
|
||||
- facts:名称、说明(docstring)、访问级别、装饰器(`@enum.unique`)、父类照原来的类;成员照源码顺序。
|
||||
- 成员照 Python 的规则认:类主体里给一个名字赋值的语句(`A = 1`、`A: int = 1`),名字不是 `__x__`、`_x_`(enum 保留的,如 `_ignore_`、`_order_`)、`__x`(私有),不在 `_ignore_` 列的名字里(空格隔开的字符串,或字符串的列表 / 元组),值不是 `lambda`、`property(...)` / `classmethod(...)` / `staticmethod(...)`、`nonmember(...)`、连着赋值(`A = B = 1`);解构赋值(`A, B = 1, 2`)不认。只写注解的(`_value_: int`)不是成员。
|
||||
- 值:`auto()`(`enum.auto()` 也算)交给库自动取,没有 `value`(表里写「自动」);`member(x)` 的值是 `x`;别的是写的值。
|
||||
- 说明(`docs`):从上一个子块之后起紧挨在它上面的注释块(几条行注释连成的一块是几条)、它这一行行尾的注释、紧跟在它后面的属性 docstring,照源码顺序(同 Celery 定时任务的「说明」取法)。
|
||||
- 并进来的子块:各个成员连同紧挨在它前面的注释块;方法、嵌套类、不是成员的属性、讲方法的注释、最后面的注释照常是子块(不管写在哪),枚举块默认收起它们。
|
||||
- 说明(`docs`):讲它的注释(挂在成员上的 `BlockShape.comments`:它上面的,类主体最后一个子块是它时后面的也算;几条行注释连成的一段是几条)、它这一行行尾的注释、紧跟在它后面的属性 docstring,照源码顺序。
|
||||
- 并进来的子块:各个成员(讲它的注释跟着并进来);方法、嵌套类、不是成员的属性照常是子块(不管写在哪),讲它们的注释是它们卡片的「注释」一行,枚举块默认收起它们。
|
||||
|
||||
样例(`fixtures/enumModels.py` 的 `CommissionStatus`,测试里逐字核对):
|
||||
|
||||
@@ -1416,7 +1437,7 @@ export interface CommandRule {
|
||||
|
||||
- 认哪些类:装饰器是 `@dataclass`、`@dataclass(...)`、`@dataclasses.dataclass(...)`(`import dataclasses as dc` 的 `dc.dataclass`、`from dataclasses import dataclass as data` 的 `data` 也算,别名按 `context.imports` 换回)。同名的别处的东西不算(`from pydantic.dataclasses import dataclass`、`@other.dataclass`)。
|
||||
- 字段照 dataclasses 的规则认:类主体里带注解的名字(`x: int`、`x: int = 1`),照源码顺序。`ClassVar[...]`(`typing.ClassVar`、只写 `ClassVar` 也算)是类变量,不是字段,照常是子块;`InitVar[...]` 是字段,类型写方括号里的,说明前面写「仅初始化时使用」;`_: KW_ONLY` 是记号,不是字段,它后面的字段(没单独写 `kw_only=` 的)在默认值一格写「只能按名字传参」。
|
||||
- 并进卡片的子块:各个字段连同紧挨在它前面的注释块、`KW_ONLY` 记号;方法(写在字段中间也算)、`ClassVar`、没注解的类属性、讲它们的注释照常是子块。
|
||||
- 并进卡片的子块:各个字段(讲它的注释跟着并进来)、`KW_ONLY` 记号;方法(写在字段中间也算)、`ClassVar`、没注解的类属性照常是子块,讲它们的注释是它们卡片的「注释」一行。
|
||||
|
||||
属性表(有才显示;字段总有,一个都没有时写「0 个」、不画表格):
|
||||
|
||||
@@ -1434,7 +1455,7 @@ export interface CommandRule {
|
||||
|
||||
- 字段:字段名(variable 色,带下标)。类型:注解照写法翻(翻译插件翻,`str` → 字符串),`InitVar[X]` 写 X。
|
||||
- 默认值:`= x` 写 x(翻译插件翻,`None` → 空);`field(default=x)` 写 x;`field(default_factory=f)` 写「每次新建 f()」(`list` → 每次新建 list();不带参数的 `lambda` 写它返回的东西:`lambda: {"a": 1}` → 每次新建 {"a": 1});没写默认值时空着。后面接 `field(...)` 的别的参数,照写的顺序:`init=False` 不进构造函数、`repr=False` 不显示、`compare=False` 不参与比较、`hash=True` 参与哈希、`hash=False` 不参与哈希、`kw_only=True` 只能按名字传参、`kw_only=False` 可按位置传参,写成默认值的不讲,别的照写 `名=值`(`metadata={"unit": "px"}`);最后是 `KW_ONLY` 带来的「只能按名字传参」。各项用 ` · ` 隔开。
|
||||
- 说明:`field(doc="…")` 的字符串;没写时同枚举成员的说明取法(紧挨在上面的注释块、这一行行尾的注释、紧跟在后面的属性 docstring,原文用空格连起来),comment 色;都没有时是类说明里讲它的 `@param`(字段就是构造参数,Markdown)。类说明里 `@param` 的名字不是哪个字段时,在卡片的「说明」下面列成「对不上的参数」;`@throws` 是卡片最后的「异常」表。
|
||||
- 说明:`field(doc="…")` 的字符串;没写时同枚举成员的说明取法(讲它的注释、这一行行尾的注释、紧跟在后面的属性 docstring,原文用空格连起来),comment 色;都没有时是类说明里讲它的 `@param`(字段就是构造参数,Markdown)。类说明里 `@param` 的名字不是哪个字段时,在卡片的「说明」下面列成「对不上的参数」;`@throws` 是卡片最后的「异常」表。
|
||||
|
||||
样例(`fixtures/dataclassModels.py` 的 `SandboxAccess`,测试里逐字核对;说明的 Markdown 从略):
|
||||
|
||||
@@ -1460,7 +1481,7 @@ export interface CommandRule {
|
||||
- 认哪些类:模块顶层的类,父类链上有 pydantic 的 `BaseModel`。`from pydantic import BaseModel`、`BaseModel as Model`、`import pydantic` 的 `pydantic.BaseModel`、`from pydantic.main import BaseModel` 都算,别名按 `context.imports` 换回。同一文件里继承另一个已经是模型的类也算(`class Child(AIGCMetadata)`,父类写在后面也认)。不认 `TypedDict`、`NamedTuple`、普通类、没导入 pydantic 时同名的 `BaseModel`,也不认 pydantic 的 `@dataclass`(那不是这张卡片,数据类规则也不认它)。
|
||||
- 别的文件里的父类:父类是一个名字、又不是本文件里的类时,问索引 `pydantic.models`(`context.lookup`,见「规则认领时查别的文件里的定义」)。索引只扫源码里写了 `BaseModel` 的 `**/*.py`,记下本文件里能确定的模型(父类是 BaseModel,或本文件里另一个模型),值是 `"model"`。查到是模型就换成这张卡片;还没查到(或确定不是)就先按普通类画,查到后再重排。再往下跨一层、中间那个类自己的文件里写不出 `BaseModel` 的,索引不收,认不出来。
|
||||
- 字段:类主体里带注解的赋值(`x: str`、`x: str | None = None`、`x: str = Field(...)`),照源码顺序。`ClassVar[...]` 不是字段。`model_config = ConfigDict(...)`(写成带注解的赋值也算)不是字段,是「选项」。
|
||||
- 并进卡片的子块:各个字段连同紧挨在它前面的注释块、`model_config` 那一行;方法、`@field_validator`、`ClassVar`、没注解的类属性(`model_config` 除外)、讲它们的注释照常是子块。字段并进来之后不再单独画成变量块。
|
||||
- 并进卡片的子块:各个字段(讲它的注释跟着并进来)、`model_config` 那一行;方法、`@field_validator`、`ClassVar`、没注解的类属性(`model_config` 除外)照常是子块,讲它们的注释是它们卡片的「注释」一行。字段并进来之后不再单独画成变量块。
|
||||
|
||||
属性表(有才显示;一个字段都没有时不画「字段」这一行):
|
||||
|
||||
@@ -1631,7 +1652,7 @@ export interface CommandRule {
|
||||
|
||||
`vscode/src/codeReader/rules/react.ts`(读语法树的办法在 `rules/reactTree.ts`,都是纯函数),`languageIds: ['typescriptreact', 'javascriptreact']`,`libraries: []`(新的 JSX 写法不用导入 react,TSX / JSX 文件都启用)。原型:`docs/prototype/code-reader/openpencil/react.js` 的三张画板「编辑器全貌」「卡片种类」「对照」(导出图 `exports/react-main.png`、`react-kinds.png`、`react-compare.png`);样例是 luffy 的 `chat/code/bubbles/QueuedBubble.tsx`(`fixtures/queuedBubble.tsx.txt`)和 `chat/code/PlanChecklist.tsx` 第 91–226 行(`fixtures/planChecklist.tsx.txt`,前面带上文件开头的导入),以前的 `DesktopTitlebar`、`LegalDocPage`、`DeleteAppDialog`、`DesktopSettingsDialog`、`AppVaultSummary`、`ShareButton`、`PosterDialog`、`OverviewSection` 也在 `fixtures/`。
|
||||
|
||||
TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排在父卡片下面,缩进、竖线、折叠同函数体。规则只换掉 React 的几种写法,别的块(导入、接口、类型、常量、普通变量、if、注释、尝试……)照语言默认的卡片。组件卡片不把组件体并进来:组件体的语句照源码顺序是它的子块,照常交给各规则看。表格的格子里只写名字和位置,函数体只出现在子卡片里。
|
||||
TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排在父卡片下面,缩进、竖线、折叠同函数体。规则只换掉 React 的几种写法,别的块(导入、接口、类型、常量、普通变量、if、尝试……)照语言默认的卡片,注释照常挂在它讲的卡片上。组件卡片不把组件体并进来:组件体的语句照源码顺序是它的子块,照常交给各规则看。表格的格子里只写名字和位置,函数体只出现在子卡片里。
|
||||
|
||||
卡片种类(颜色写暗 / 亮):
|
||||
|
||||
@@ -1652,10 +1673,10 @@ TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排
|
||||
|
||||
认领(`LibraryRule.claim` 一块一块看,组件卡片的 `absorbs` 是空的):
|
||||
|
||||
- 组件块(函数块、只声明一个变量的常量 / 变量块)是组件时换成组件卡片。文件开头的 `"use client"`(文件里有组件时)和组件上面没并进块头部的 JSDoc(值是 `memo(…)`、直接返回 JSX 的常量块)略去(`RuleOmit`),讲成卡片上的「客户端组件」标签和「说明」。
|
||||
- 组件块(函数块、只声明一个变量的常量 / 变量块)是组件时换成组件卡片。文件开头的 `"use client"`(文件里有组件时)略去(`RuleOmit`),讲成卡片上的「客户端组件」标签;它挂着注释时不略去(注释没地方放),照常是一张语句卡片。组件上面的 JSDoc 是组件块自己的说明(TypeScript 的 JSDoc 能当常量、变量块的说明,`memo(…)`、直接返回 JSX 的常量块也是),讲成卡片的「说明」。
|
||||
- 组件体里的块:语法树往上找,块的语句直接是某个组件函数主体(语句块)的子语句才认(`enclosingComponent`:所在的函数经 `componentOfFunction` 找回它的声明,再用认组件的 `componentAt` 核对),按组件体的归类(`bodyOf`)认成状态、引用、数据源、派生值、副作用、事件处理函数。
|
||||
- `return` 块:所在的最内层函数(`enclosingFunction`)是组件函数、返回的是 JSX 时认成渲染输出;写在 `if` 里的提前返回 JSX 也算,它是如果卡片下面的子块。返回 `null` 这类的照常是返回块。
|
||||
- 别的照语言默认:组件体里普通的 `const x = 表达式` 是变量卡片,`if (…) return null` 是如果卡片、下面是返回卡片,注释照常成块(不再并进卡片)。
|
||||
- 别的照语言默认:组件体里普通的 `const x = 表达式` 是变量卡片,`if (…) return null` 是如果卡片、下面是返回卡片,注释是它讲的那张卡片的「注释」一行。
|
||||
- 回调、函数里的语句来自 TypeScript 语言插件本来给的子块:调用的实参是带语句块的函数时(任何调用都一样),那句语句、那个变量的子块就是函数里的语句,所以 `useEffect(() => {…})`、`useCallback(() => {…})`、`useMemo(() => {…})` 的语句排在副作用、派生值卡片下面;事件处理函数是函数块,函数体照常是子块。
|
||||
|
||||
组件卡片:
|
||||
@@ -1685,7 +1706,7 @@ TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排
|
||||
|
||||
副作用:触发时机按依赖数组读,`[a, b]` 是「a、b 变化时」,`[]` 是「仅挂载时」,没写是「每次渲染后」(keyword 色),依赖写成别的表达式时「deps 变化时」;useLayoutEffect 后面加「,浏览器绘制前」。最后返回清理函数时那句 return 并进来,多一行「清理函数」:`() => …` 翻它的主体,语句块一句句翻、「;」隔开。副作用函数里别的语句是子块。
|
||||
|
||||
事件处理函数:名称是函数名(function 色,带下标);参数照常翻(`e: KeyboardEvent<HTMLDivElement>`),几个「, 」隔开,没有写「无」;绑定事件从 JSX 属性反查:「<div>(修改排队消息) 的 onKeyDown」,在属性值里调用时写传入的实参「(传入 h.id)」,在列表里一项项渲染的写「每个 <button>」,几处「、」隔开;没绑在 JSX 上时写由谁调用「由 download、share 调用」,都没有「—」。函数里的语句是子块(如果、返回、调用、变量、注释、尝试……)。
|
||||
事件处理函数:名称是函数名(function 色,带下标);参数照常翻(`e: KeyboardEvent<HTMLDivElement>`),几个「, 」隔开,没有写「无」;绑定事件从 JSX 属性反查:「<div>(修改排队消息) 的 onKeyDown」,在属性值里调用时写传入的实参「(传入 h.id)」,在列表里一项项渲染的写「每个 <button>」,几处「、」隔开;没绑在 JSX 上时写由谁调用「由 download、share 调用」,都没有「—」。函数里的语句是子块(如果、返回、调用、变量、尝试……),注释挂在它讲的那块上。
|
||||
|
||||
渲染输出(「JSX 结构大纲」一行下面的子行,一行一个元素,下一层缩进;带下一层的行有折叠箭头):
|
||||
|
||||
@@ -1716,7 +1737,7 @@ react.component 23
|
||||
if 39: 如果 (localStorage.getItem(PLAN_CHECKLIST_COLLAPSED_KEY) 全等 "1")
|
||||
statement 40: queueMicrotask(() => setCollapsed(真));
|
||||
catch 42: 捕获
|
||||
comment 43: localStorage 不可用 (隐私模式等) 时静默用默认
|
||||
注释: localStorage 不可用 (隐私模式等) 时静默用默认
|
||||
react.derived 47
|
||||
名称: toggle
|
||||
计算表达式: 函数(3 条语句)
|
||||
@@ -1728,13 +1749,13 @@ react.component 23
|
||||
try 50: 尝试
|
||||
statement 51: localStorage.setItem(PLAN_CHECKLIST_COLLAPSED_KEY, 如果 next 则 "1" 否则 "0");
|
||||
catch 52: 捕获
|
||||
comment 53: 忽略写入失败
|
||||
注释: 忽略写入失败
|
||||
if 57: 如果 (todos.length 全等 0)
|
||||
return 57: 返回 空;
|
||||
variable 58
|
||||
名称: whole
|
||||
初始值: wholeStatusOf(todos, active)
|
||||
…(doneCount、counter、current 三张变量卡片,一张注释卡片,headline 变量卡片)
|
||||
…(doneCount、counter、current、headline 四张变量卡片,headline 那张带「注释」一行)
|
||||
react.render 65
|
||||
JSX 结构大纲:
|
||||
Collapsible ⟦样式 1 个类 · 取决于 CARD_SURFACE⟧ open=非 collapsed onOpenChange=toggle
|
||||
@@ -1743,7 +1764,7 @@ react.component 23
|
||||
…
|
||||
```
|
||||
|
||||
和原型不一样的地方:接口 `PlanChecklistProps` 照 TypeScript 的接口块(一行译文,字段、注释是子块),原型「对照」里画成的字段表(名称 / 类型 / 必填 / 说明)这次没做;渲染输出的大纲挂在「JSX 结构大纲」这一行下面,不是直接画在卡片里;更新位置、使用位置里的「副作用」是副作用色的字,不能跳(副作用没有名字可查定义),原生标签(`<textarea>`)也不能跳,组件标签能跳到组件定义。
|
||||
和原型不一样的地方:接口 `PlanChecklistProps` 照 TypeScript 的接口块(一行译文,字段是子块,注释挂在讲的字段上),原型「对照」里画成的字段表(名称 / 类型 / 必填 / 说明)这次没做;渲染输出的大纲挂在「JSX 结构大纲」这一行下面,不是直接画在卡片里;更新位置、使用位置里的「副作用」是副作用色的字,不能跳(副作用没有名字可查定义),原生标签(`<textarea>`)也不能跳,组件标签能跳到组件定义。
|
||||
|
||||
### 内置:Rust 的库
|
||||
|
||||
@@ -1752,7 +1773,7 @@ react.component 23
|
||||
- serde(`rules/serde.ts`,`libraries: ['serde']`):`derive` 了 `Serialize` 或 `Deserialize` 的结构体。种类 `serde.struct`,标签「可序列化」,图标 `braces`,颜色同结构体(暗 #4ec9b0 / 亮 #267f99)。名称后面再标一个「可序列化」。`rename_all = "camelCase"` 收成选项「字段名改驼峰」。字段表多一列「序列化」:`rename` 写「改名 xxx」,`skip` / `skip_serializing` 写「不输出」,没标是「—」。说明里的 `@param` 同结构体对到字段表的「说明」列。
|
||||
- thiserror(`rules/thiserror.ts`,`libraries: ['thiserror']`):`derive` 了 `Error` 的枚举。种类 `thiserror.error`,标签「错误」,图标 `triangle-alert`,颜色同异常(暗 #f14c4c / 亮 #cd3131)。变体表「变体 | 何时 | 展示」:何时是变体上面的文档注释,展示是 `#[error("…")]` 的文案。变体上的 `#[from]` 或 `#[source]` 在展示后面标「透传来源」。
|
||||
- axum(`rules/axum.ts`,`libraries: ['axum']`):处理函数上的 `#[get("/path")]`、`#[axum::post(…)]` 等(get / post / put / delete / patch / head / options / trace),或顶层语句里 `Router` 的 `.route(路径, get(函数))`。函数已经标了路由属性时,这句 `route` 不再单独成卡。种类 `axum.route`,标签「接口」,图标 `globe`,颜色同 FastAPI 接口(暗 #61afef / 亮 #1a6fb5)。属性表:名称、说明、异步(是)、请求(一项「方法」、一项「路径」、路径里的 `{名字}` 对上参数写成「路径参数」,`Path(id): Path<Uuid>` 写 `id: Uuid`)、参数(说明里写了 `@param` 才有:参数是 `Path(id)` 这类模式,不对名字,照写成「名称 \| 说明」表)、返回(`@return` 跟在后面)、异常(`@throws`)。
|
||||
- sqlx(`rules/sqlx.ts`,`libraries: ['sqlx']`):`query!` / `query_as!` / `query_scalar!`。种类 `sqlx.query`,标签「查询」,图标 `database`,颜色暗 #ce9178 / 亮 #a31515。紧挨在前面的注释收成「说明」,不再单独成块。SQL 原文等宽,参数 `$1` 对上传入的表达式,`query_as!` / `query_scalar!` 的第一个实参是返回类型,`query!` 的返回类型是「—」。
|
||||
- sqlx(`rules/sqlx.ts`,`libraries: ['sqlx']`):`query!` / `query_as!` / `query_scalar!`。种类 `sqlx.query`,标签「查询」,图标 `database`,颜色暗 #ce9178 / 亮 #a31515。前面的注释同别的块,是卡片的「注释」一行(宿主插在第一行 SQL 后面)。SQL 原文等宽,参数 `$1` 对上传入的表达式,`query_as!` / `query_scalar!` 的第一个实参是返回类型,`query!` 的返回类型是「—」。
|
||||
- tauri(`rules/tauri.ts`,`libraries: ['tauri']`):`#[tauri::command]` 的函数。种类 `tauri.command`,标签「桌面命令」,图标 `square-function`,颜色暗 #e5c07b / 亮 #9a6a00。名称后面再标「桌面命令」。参数表「名称 | 类型 | 来源」:`State<…>` 是「窗口状态」,其余是「调用方传入」;说明里的 `@param` 对上时多一列「说明」,`@return` 跟在「返回」后面,`@throws` 成「异常」表。
|
||||
|
||||
## 命令规则
|
||||
@@ -1811,17 +1832,31 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
|
||||
## 代码块树规则
|
||||
|
||||
### 注释挂到它讲的块上
|
||||
|
||||
注释一定是讲某块代码的,和语言无关,各语言插件建好整棵树后调一次 `languages/shared.ts` 的 `attachComments`(Python、TypeScript 在认异常类之前调,异常类并类属性时拿到的是挂好注释的块):
|
||||
|
||||
- 先照各语言的规矩分好注释块(`listBlocks`:相邻行同一写法的行注释合成一段,和上一条语句同一行的是行尾注释、不成块,文档注释能当说明的进 `facts.doc`;Python 当注释用的字符串也是注释块)。
|
||||
- 再把每段注释挂到它讲的块上(`BlockShape.comments`,照源码顺序),不再单独成块:
|
||||
1. 同一层(同一个父块的子块,文件顶层也算一层)里它后面最近的一块代码,中间隔着空行也算;挂在同一块前面的几段各是一段。
|
||||
2. 后面没有代码了(主体、文件最后的注释)挂到同一层前面最近的那块;这一层一块代码都没有(主体里只有注释)挂到父块。
|
||||
3. 文件开头的说明单独成块(种类 comment):第一块代码之前的注释(`#!` 解释器、Dockerfile 的解析指令不算代码,Python 第一行的 `#!`、头两行写编码的 `# -*- coding: … -*-` 也是文件的),和第一块代码之间隔着空行的那几段;紧挨着第一块代码(中间没空行)的那几段照第 1 条挂到它上面。本来就讲整个文件的总是文件开头的说明:Python 模块开头的 docstring、Rust 的 `//!` / `/*!`、写了 `@file` / `@fileoverview` / `@overview` 的 JSDoc;Rust 的 `//!` 写在 `mod` 身体里时交给那个模块。
|
||||
4. 嵌在别的语言里的代码(Dockerfile 的 RUN 里的 shell)没有文件开头的说明,一块代码都没有时注释照旧单独成块(读成步骤时不算一步)。
|
||||
- 文档注释是块的「说明」(照旧进 `facts.doc`、带块标签),普通注释是块的「注释」,一块可以两样都有。行尾注释照旧跟着那一行。
|
||||
- 块的完整范围(编辑范围)连同挂在它上面的注释(见「预览(代码块树)」);块的记号(问答挂的地方)只看块自己,改注释不丢问答。
|
||||
- 库规则拿到的块已经挂好注释:并成员时讲成员的注释跟着成员(内置规则拿它当成员的说明);规则略去的块不能挂着注释。
|
||||
|
||||
### TypeScript / JavaScript
|
||||
|
||||
- 顶层与语句块内的每条语句一块;连续的行注释合成一块注释。
|
||||
- JSDoc(以 `/**` 开头的块注释,`/**/` 不算)和下一条语句之间只有空白(空行也算,中间隔着装饰器也算)、那条语句是函数、类或枚举块时,它是这个函数、类、枚举的说明:进 `facts.doc`,头部往上延到注释开头,不单独成块。其余情况(后面不是函数、类、枚举块,中间隔着别的注释,在上一条语句的行尾)照旧是注释块。`//` 行注释和普通 `/* */` 块注释不变。
|
||||
- 顶层与语句块内的每条语句一块;连续的行注释合成一段注释,挂到它讲的块上(见「注释挂到它讲的块上」)。
|
||||
- JSDoc(以 `/**` 开头的块注释,`/**/` 不算)和下一条语句之间只有空白(空行也算,中间隔着装饰器也算)、那条语句是函数、类、枚举、常量或变量块时,它是这一块的说明:进 `facts.doc`,头部往上延到注释开头。其余情况(后面不是这几种块,中间隔着别的注释)是普通注释,挂到它讲的块上;在上一条语句的行尾的是行尾注释。`//` 行注释和普通 `/* */` 块注释是普通注释。
|
||||
- `import_statement` → import。
|
||||
- `export_statement` 包着声明 → 按声明定种类,节点取整个 `export_statement`(头部包含 `export`)。
|
||||
- `function_declaration` / `generator_function_declaration` / `method_definition` → function,子块来自主体语句。
|
||||
- 变量声明的唯一声明值是带语句块主体的箭头函数 / 函数表达式 → function(React 组件、回调常见写法),子块来自主体;是类表达式(`const A = class {}`)→ class。
|
||||
- `lexical_declaration` / `variable_declaration`:模块顶层的 `const` → const,其余 → variable。
|
||||
- `class_declaration` / `abstract_class_declaration`、`export default class {}` → class,子块:方法 → function,字段 → field(值是带语句块主体的函数 → function,值是类表达式 → class),注释 → comment。
|
||||
- 类(含类表达式)的父类是异常类时(见「异常」)→ exception:头部是整个类,字段连同前面的注释并进属性表,方法(含 constructor)、别的成员照常是子块。整棵树建好后按整份文件认(同一文件里的异常类写在后面也算)。
|
||||
- `class_declaration` / `abstract_class_declaration`、`export default class {}` → class,子块:方法 → function,字段 → field(值是带语句块主体的函数 → function,值是类表达式 → class),注释挂到讲的成员上。
|
||||
- 类(含类表达式)的父类是异常类时(见「异常」)→ exception:头部是整个类,字段连同讲它的注释并进属性表,方法(含 constructor)、别的成员照常是子块。整棵树建好后按整份文件认(同一文件里的异常类写在后面也算)。
|
||||
- `interface_declaration` → type,子块:属性 / 方法签名 → field;`type_alias_declaration` → type;`enum_declaration`(含 `const enum`、`declare enum` 的 `ambient_declaration`、`export` 包着的)→ enum,头部是整条声明,成员在属性表里讲、不成子块。
|
||||
- `if_statement` → if,子块来自 consequence;`else` / `else if` 展平成紧跟其后的兄弟块 else(`else if` 的头部是 `else if (...)`,子块来自它的 consequence)。
|
||||
- `for` / `for…in` / `for…of` / `while` / `do` → loop。
|
||||
@@ -1835,11 +1870,11 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
- `import_statement` / `import_from_statement` / `future_import_statement` → import。
|
||||
- `function_definition` → function;`decorated_definition` 按内部定义定种类,头部包含装饰器。
|
||||
- `class_definition` → class;类体里的带注解赋值 → field。
|
||||
- 父类是异常类的类(见「异常」)→ exception:头部是整个类,类属性连同前面的注释并进属性表,方法(含 `__init__`)、别的语句照常是子块。整棵树建好后按整份文件认(同一文件里的异常类写在后面也算)。
|
||||
- 父类是异常类的类(见「异常」)→ exception:头部是整个类,类属性连同讲它的注释并进属性表,方法(含 `__init__`)、别的语句照常是子块。整棵树建好后按整份文件认(同一文件里的异常类写在后面也算)。
|
||||
- 字符串语句:单独一个普通字符串字面量的表达式语句(`string`,或隐式拼接的 `concatenated_string`,每段的前缀只有 r / u 或没有;f-string、t-string、字节串不算,照旧是 statement)。
|
||||
- 函数、类主体的第一条语句(注释不算)是字符串语句时,它是这个函数、类的 docstring:进 `facts.doc`,头部往下延到字符串结尾(它和冒号之间的注释也在头部里),子块从它后面开始,不单独成块。
|
||||
- 属性 docstring:模块、类主体里(条件、函数等语句块里的不算)紧跟在一条赋值后面的字符串语句是这个常量、变量、字段的说明:常量、变量进 `facts.doc`,字段进块的 `doc`,头部往下延到字符串结尾,不单独成块。「紧跟」同 JSDoc:中间可以隔空行和赋值的行尾注释,隔着别的注释、语句就不算;只挂一个,后面再来的字符串照下一条规则。
|
||||
- 其余字符串语句(模块开头的 docstring、写在语句中间当注释用的字符串)和 `comment` → comment。
|
||||
- 其余字符串语句(模块开头的 docstring、写在语句中间当注释用的字符串)和 `comment` → 注释:模块开头的 docstring、第一行的 `#!`、头两行写编码的注释是文件开头的说明,别的挂到它讲的块上(见「注释挂到它讲的块上」)。`#!` 和写编码的那两行不和后面的 `#` 注释连成一段。
|
||||
- 赋值:模块顶层且变量名全大写 → const,其余 → variable。
|
||||
- `if_statement` → if;`elif_clause` / `else_clause` → 兄弟块 else;`for` / `while` → loop(循环的 `else` → 兄弟块 else)。
|
||||
- `try_statement` → try;`except_clause` → catch;`finally_clause` → finally。
|
||||
@@ -1849,7 +1884,7 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
|
||||
### Shell
|
||||
|
||||
- 首行 `#!` → interpreter;别的 `comment` 连着的几行合成一块注释;紧贴在函数定义上面(中间没空行)的注释是函数的说明,进 `facts.doc`、头部往上延,不单独成块。
|
||||
- 首行 `#!` → interpreter;别的 `comment` 连着的几行合成一段注释,挂到它讲的块上(见「注释挂到它讲的块上」);紧贴在函数定义上面(中间没空行)的注释是函数的说明,进 `facts.doc`、头部往上延。
|
||||
- `set` 后面全是开关(`-euo pipefail`、`+x`、`-o nounset`)→ options;有不是开关的词(`set -- a b`)→ command。
|
||||
- `variable_assignment`、`declaration_command`(local / export / readonly / declare 声明了变量的)→ variable;readonly 的、脚本顶层名字全大写且值里没有展开的 → const。一句声明几个变量是一块(`DeclaratorFacts` 各一项)。
|
||||
- `function_definition` → function,子块来自主体各句。
|
||||
@@ -1864,7 +1899,7 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
|
||||
- 文件最开头连着的 `# syntax=` / `# escape=` / `# check=`(从第一行起、中间没空行)→ directive。
|
||||
- 每个 `from_instruction` 开一个 stage,头部是 FROM 那一行,紧贴在上面(中间没空行)的几行注释是它的说明、头部往上延;到下一个阶段(连同它上面的说明)之前的指令、注释是子块;第一个 FROM 之前的照常是顶层的块。
|
||||
- 相邻行的注释合成一块注释;只写了中文名记号、紧挨着下一条指令的注释算在那条指令的块里。
|
||||
- 相邻行的注释合成一段注释,挂到它讲的块上(见「注释挂到它讲的块上」:阶段里的挂到后面那条指令,阶段最后的挂到前面那条);只写了中文名记号、紧挨着下一条指令的注释算在那条指令的块里。
|
||||
- `run_instruction` → run(整条指令,shell 写法的带 `embedded`);`copy_instruction`、`add_instruction` → copy;`label_instruction` → label;`env_instruction`、`arg_instruction` → variable(facts 的 scope 分构建参数、环境变量);WORKDIR / USER / EXPOSE / VOLUME / STOPSIGNAL / SHELL / MAINTAINER → setting;`healthcheck_instruction` → health;`cmd_instruction`、`entrypoint_instruction` → start;`onbuild_instruction` → setting,包着的指令照这些规则是它的子块;别的(语法错误)→ statement。
|
||||
- 连着写的同种指令(紧挨着下一行)并成一块:ENV、ARG 并成一个变量块(declarators 是各条的全部),LABEL 和从同一个地方复制的 COPY 并成一块(`TextBlock.group`,头部盖住全部);ADD、带 heredoc 的 COPY 不并。
|
||||
|
||||
@@ -1876,10 +1911,10 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
|
||||
注释和别的语言走同一条路(`listBlocks`,Rust 的 `CommentRules` 在 `languages/rust.ts`),文件顶层、`mod` 身体、`impl` 身体都一样:
|
||||
|
||||
- 连续的行注释合成一块注释:相邻行、写法相同才合,`//`、讲所在模块或 crate 的 `//!`、讲下一项的 `///` 各是一种写法,不混着合。中间空的 `//` 不打断,是 Markdown 里的空行、分段;隔着空行、隔着别的语句就断开。
|
||||
- 连续的行注释合成一段注释:相邻行、写法相同才合,`//`、讲所在模块或 crate 的 `//!`、讲下一项的 `///` 各是一种写法,不混着合。中间空的 `//` 不打断,是 Markdown 里的空行、分段;隔着空行、隔着别的语句就断开。合好的注释挂到它讲的项上(见「注释挂到它讲的块上」);`//!` 写在文件开头是文件的说明,写在 `mod` 身体里交给那个模块。函数体不拆,函数体里的注释留在函数的源码里。
|
||||
- 和上一条语句同一行的 `//` 是行尾注释,不单独成块。
|
||||
- `///`(和 `/**` 开头的块注释)后面紧跟的是函数、结构体、枚举、特质、实现、模块、常量、`static` 时,是这一项的说明:进 `facts.doc`(第一条注释节点),头部往上延到它开头,不单独成块;后面是 `use`、宏调用、`let` 这类不带说明的项,或隔着别的注释时,照旧是注释块。
|
||||
- 注释块的预览是去掉 `//`(`///`、`//!` 连那个 `/`、`!`)和后面一个空格的原文,按「注释的 Markdown 排版」显示。语法包把 `///`、`//!` 行尾的换行算进注释节点,块的范围不算这个换行。
|
||||
- `///`(和 `/**` 开头的块注释)后面紧跟的是函数、结构体、枚举、特质、实现、模块、常量、`static` 时,是这一项的说明:进 `facts.doc`(第一条注释节点),头部往上延到它开头;后面是 `use`、宏调用、`let` 这类不带说明的项,或隔着别的注释时,是普通注释,挂到它讲的项上。
|
||||
- 注释的预览(「注释」一行、文件开头的说明)是去掉 `//`(`///`、`//!` 连那个 `/`、`!`)和后面一个空格的原文,按「注释的 Markdown 排版」显示。语法包把 `///`、`//!` 行尾的换行算进注释节点,块的范围不算这个换行。
|
||||
|
||||
- `use` → import。来源是路径去掉最后一节(`std::sync::Arc` 的来源是 `std::sync`)。导入项表「名字 | 别名」,没起别名是「—」,`*` 是「*」。
|
||||
- `struct` → class(中文直译把这个种类叫「结构体」)。字段不单独成块,表「字段 | 类型 | 可见性」。元组结构体没有这张表。
|
||||
@@ -1924,7 +1959,7 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
|
||||
同一套表和节点模板也用来翻属性表里的值:引擎能翻任意一个节点(只取它落在块头部里的那一段),参数类型、默认值、返回类型、变量类型和初始值、字典 / 对象各项的键和值都走这条路。
|
||||
|
||||
其他规则:空数组字面量 → 空数组、空对象字面量 → 空对象(Python 空列表 → 空列表、空字典 → 空字典);复合语句头部去掉结尾的 `{` 或 `:`;多行合成一行(连续空白压成一个空格,右括号前的尾逗号去掉);注释块给去掉注释符号的 Markdown 原文(见「注释的 Markdown 排版」)。关键字与前后内容之间保留源码里的空格(`!` 翻成「非」后补一个空格)。
|
||||
其他规则:空数组字面量 → 空数组、空对象字面量 → 空对象(Python 空列表 → 空列表、空字典 → 空字典);复合语句头部去掉结尾的 `{` 或 `:`;多行合成一行(连续空白压成一个空格,右括号前的尾逗号去掉);注释(文件开头的说明、挂在块上的注释)给去掉注释符号的 Markdown 原文(见「注释的 Markdown 排版」)。关键字与前后内容之间保留源码里的空格(`!` 翻成「非」后补一个空格)。
|
||||
|
||||
关键字按所在语法节点选择译法:同一个关键字在不同语法结构里意思不同时,表里写一个默认译法,再加若干「语境 → 译法」。语境是从关键字节点往上的节点类型链,外层在前:`raise_statement` 指父节点是 raise_statement,`for_statement > else_clause` 指父节点是 else_clause、祖父节点是 for_statement(关键字包在一层子句节点里时要看到祖父节点)。几条语境同时匹配时取最长的,都不匹配用默认译法。节点类型以 tree-sitter 语法为准。下面两张表里写成「(语境)译法 / (语境)译法」的关键字就是按这条规则区分的,排第一个的是默认译法。
|
||||
|
||||
@@ -2003,15 +2038,20 @@ interface BlockViewBase {
|
||||
concepts: BlockConcept[] // 认出来的概念,从左到右;webview 按图标名画,不自己用种类查
|
||||
badge?: KindBadge // 库规则的卡片才有:筛选栏里这个种类的名字,卡片边框的颜色;图标在 concepts 里。和类块一样默认折叠
|
||||
slot?: { row: number, item: number } // 库规则挂在父卡片子行上的子块才有(RuleSlot):挂在父卡片第 row 行的第 item 个子行上,点它才在这一行下面展开(它的块 id 记成折叠着就是收着)
|
||||
commentRow?: number // 「注释」一行排第几行,0 起:属性表卡片是 properties 的下标,一行译文的卡片是 rows 的下标;没有注释就没有。「重写注释」按钮画在这一行上
|
||||
commentTarget?: CommentTarget // 「重写注释」写到哪(见「重写注释」);嵌着的代码里的块、语言没给行注释记号又还没有注释的块没有,不给按钮
|
||||
children: BlockView[]
|
||||
}
|
||||
|
||||
/** 「重写注释」写到哪,行号 0 起:换掉块前面那几段普通注释(文件开头的说明卡片是它自己),或块还没有注释时新写在 line 这一行上面。 */
|
||||
type CommentTarget = { kind: 'replace', startLine: number, endLine: number } | { kind: 'insert', line: number }
|
||||
|
||||
/**
|
||||
* 属性表块(有 facts)和库规则认领的块只带 properties,其余块只带 translation(注释块是 `{ markdown }`);没有翻译插件时是空数组。
|
||||
* 属性表块(有 facts)和库规则认领的块只带 properties(「注释」一行由宿主插在里面),其余块只带 translation(文件开头的说明是 `{ markdown }`);没有翻译插件时是空数组。
|
||||
* 一行译文里有跨几行写的调用时 table 是摊开实参的表(TextTranslation.table),块带说明(TextBlock.doc)时 doc 是翻译插件读出的说明正文(Translator.doc 的 body),
|
||||
* webview 依次排在译文下面。
|
||||
* 挂着注释时 rows 是「注释」一行,webview 依次排在译文下面。差异的标记里一行译文的卡片的 rows 同属性表逐行标。
|
||||
*/
|
||||
type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTable, doc?: Markdown } | { properties: PropertyRow[] })
|
||||
type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTable, doc?: Markdown, rows?: PropertyRow[] } | { properties: PropertyRow[] })
|
||||
```
|
||||
|
||||
- 扩展 → webview:
|
||||
@@ -2030,6 +2070,7 @@ type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTab
|
||||
- `{ type: 'askProfiles', options: { id, label }[], selected }`:「问 AI」的 profile 下拉(`id` 是 profile 名,「默认」的 `id` 是 `''`、`label` 是「默认」)。`ready` 后发一次(每次现读 profile 目录),任何一个预览选了都发给所有开着的预览(包括选的那个)。
|
||||
- `{ type: 'answer', askId, text, activity? }`:`askId` 那个问题的回答长了(`text` 是到现在为止的全文)或换了在做的事。webview 攒着、最多每 80ms 画一次。
|
||||
- `{ type: 'answerEnd', askId, status: 'done' | 'failed' | 'stopped', text?, error?, entryId? }`:答完了。`done` 带最终回答和存下的那条的 id(历史里不再重复显示它),`failed` 带给人看的原因,`stopped` 是被叫停、没存。
|
||||
- `{ type: 'rewriteProgress', anchor, question, text, activity? }`:`anchor` 那块正在重写注释:`question` 是发给模型的那一句,`text` 是正文到现在为止写出来的,`activity` 是正在读什么。`{ type: 'rewriteEnd', anchor, status: 'done' | 'failed' | 'stopped', error? }`:重写完了(见「重写注释」)。
|
||||
- `{ type: 'repoLinksChecked', id, missing, unresolved }`:回答第 `id` 次 `checkRepoLinks`,`missing` 是仓库里没有的路径,`unresolved` 是找不到的不带路径的引用。`{ type: 'repoLinkBroken' | 'repoLinkOpened', path?, symbol? }`:点了以后打不开 / 打开了;没有 `path` 的是不带路径的引用。见「注释的 Markdown 排版」。
|
||||
- webview → 扩展:
|
||||
- `{ type: 'probeDefinition', id, version, offset }`:按住修饰键指到带 `offset` 的名字上时问有没有定义,`id` 每问一次加一;`version` 不是当前文档版本就不答。
|
||||
@@ -2040,6 +2081,7 @@ type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTab
|
||||
- `{ type: 'checkRepoLinks', id, paths, symbols }`:页面上的仓库路径问哪些没有,不带路径的引用问哪些找不到(`id` 每问一次加一)。`{ type: 'openRepoLink', path?, symbol? }`:点了注释里的仓库链接(带 `path`)或不带路径的引用(只带 `symbol`)。见「注释的 Markdown 排版」。
|
||||
- `{ type: 'ready' }`
|
||||
- `{ type: 'edit', startLine, endLine, text }`:用 `WorkspaceEdit` 把这几行整行替换成 `text`(每行补回原来第一行的缩进)。
|
||||
- `{ type: 'rewriteComment', anchor }`:给 `anchor` 那块重写注释(见「重写注释」);`{ type: 'stopRewrite', anchor }`:叫停,不写文件。
|
||||
- `{ type: 'selectTranslator', id }`:按 `languageId` 记到 `globalState`,重发文档。
|
||||
- `{ type: 'setFilter', excluded }`:改块筛选(整份替换);扩展端逐项核对后记进 `workspaceState`,再发 `filter` 给所有预览。webview 不在本地先改,只按扩展端发来的显示。
|
||||
- `{ type: 'setOnlyChanges', on }`:打开 / 关掉「只看改动」;扩展端记进 `workspaceState`(`superpowers.codeReader.onlyChanges`),再发 `filter` 给所有预览。
|
||||
@@ -2106,11 +2148,12 @@ vscode/src/codeReader/
|
||||
(blockView.ts 的 readDefinitionKind:定义处落在哪块自己的名字上;editor/definitions.ts 的 definitionKind:打开定义所在的文件交给它)
|
||||
rules/pythonTree.ts Python 库规则共用的读语法树的办法(名字最后一节、字符串内容、调用的参数、别名、注解里的 X[...]、库里的名字)
|
||||
rules/segments.ts 库规则共用的拼属性表文字的办法
|
||||
rules/children.ts 库规则共用的挑子块的办法(成员连同紧挨在它前面的注释块、成员的说明节点)
|
||||
rules/children.ts 库规则共用的挑子块的办法(类主体里带注解的赋值、成员的说明节点:挂在成员上的注释、行尾注释、属性 docstring)
|
||||
docTags.ts 说明的原文按 KDoc 拆成正文和块标签(Doc:@param / @return / @throws),翻译插件的 doc 用它(纯函数)
|
||||
rules/docRows.ts 讲说明的几行,中文直译和库规则共用:正文、对不上的参数、参数按名字对说明(paramDocs)、输出后面的 @return、异常表
|
||||
symbolLinks.ts 注释里不带路径的引用指到哪:导入引进来的名字(importedNames,readBlockViews 交出)、本文件定义的优先再是导入的(resolveReference,符号和定义由预览去问)(不碰 VS Code)
|
||||
languages/shared.ts 语言插件共用的建树工具;异常类(withExceptions:按整份文件认异常类,类块换成异常块,并类属性、取构造参数)
|
||||
languages/shared.ts 语言插件共用的建树工具:一串语句分块(listBlocks)、注释挂到它讲的块上(attachComments);异常类(withExceptions:按整份文件认异常类,类块换成异常块,并类属性、取构造参数)
|
||||
commentRewrite.ts 重写注释:发给模型的那一句、读结构化结果(含逐字的进度)、新正文套回定界符 / 新写一段、核对后写回(不碰 VS Code)
|
||||
languages/typescript.ts (call:调用的结构,new 是新建;TYPESCRIPT_EXCEPTIONS:认异常类的父类名、类字段、constructor)
|
||||
languages/python.ts (iteration:推导式的结构;call:调用的结构;PYTHON_EXCEPTIONS:自带的异常类、类属性、__init__)
|
||||
languages/rust.ts Rust:代码块树
|
||||
@@ -2170,7 +2213,7 @@ vscode/src/codeReader/
|
||||
qa/qaMap.ts .spx/code-qa.json 的形状、每条怎么认、记一次 / 删一次、再问时接着哪个会话(纯函数)
|
||||
qa/prompt.ts 问 AI 的话:找到那块、外层块的开头、带行号的代码、追问
|
||||
qa/answerStream.ts stream-json 的每行 → 会话 id、逐字的回答、在做的事、最终回答 / 失败
|
||||
qa/claudeAsk.ts 命令行参数(只读、选的 profile)、问一次(问题连同图片从 stdin 发,追问找不到会话时重新问)、失败给人看的话
|
||||
qa/claudeAsk.ts 命令行参数(只读、选的 profile、要结构化结果时的 --json-schema)、问一次(问题连同图片从 stdin 发,追问找不到会话时重新问)、重写注释问一次(askCommentBody)、失败给人看的话
|
||||
qa/qaImages.ts 问题带的图片:认哪些格式、存到 .spx/code-qa/ 叫什么名字、写文件(不碰 VS Code)
|
||||
qa/askProfiles.ts AskProfiles:问 AI 用哪个 profile,下拉的选项、记在 globalState、通知所有预览(不碰 VS Code)
|
||||
qa/asks.ts QaAsks:正在答的问题,一块一个、最多 3 个、能叫停(不碰 VS Code)
|
||||
@@ -2204,7 +2247,9 @@ vscode/webview-ui/code-reader.html + src/codeReader/ 预览界面(React,Vit
|
||||
- 翻译:上面两张样例表逐字一致;属性名不被翻;每个被翻的词单独成段;节点模板嵌套时正确、槽位里照样翻、没命中模板的节点照抄;属性表里的值和一行译文用同一套表和模板。
|
||||
- `blockView`:`codeTokens` 拼起来等于 `code`;去缩进正确;函数、类、导入、常量、变量块只带属性表,其余块只带译文。
|
||||
- 块标签:拆法(`docTags.test.ts`:多行续写、空行结束、`@returns` / `@exception` 同义、JSDoc 的 `{类型}`、`[名字=默认值]`、横杠、标签前后的正文、没有标签时原样、别的标签和围栏代码块里的行留在正文、异常名写成引用);卡片(`translators/zhTemplate.test.ts` 的「说明里的块标签」):`fixtures/conversationBrief.py`(luffy 的 `render_conversation_brief`)说明里没有 `@param` / `@return`,输入参数表「说明」列四个参数的原文,输出参数后面跟 `@return`;`fixtures/localRuntimeGate.py`(luffy 的 `gate.py`)「异常」表两行,第一行是完整链接、第二行是不带路径的引用;对不上的 `@param` 排在说明下面、提示色、悬停「没有这个参数」;类的 `@param` 照写成表、异常类的对到构造参数(`*args` 去掉星号对)。React 组件(字段没注释时用 `@param`、`props.x`、讲整个参数的跟在构造参数后面、对不上的、异常表)和事件处理函数(`rules/react.test.ts`)、FastAPI 请求表的说明列和响应后面的 `@return`(`rules/fastapi.test.ts`)、Rust 函数和结构体(`languages/rust.test.ts`)、数据类字段(`rules/dataclass.test.ts`)。
|
||||
- 注释的 Markdown:注释块、函数和类「说明」的视图数据是 `{ markdown }`,原文照抄(reST 角色、双反引号、`{@link}`、HTML 都不转换,块标签拆出去),行注释连成的块留得住缩进四格的代码块;渲染时 HTML 当文字、带协议的网址和邮箱成链接、不带协议的文件名不成链接,`javascript:` / `command:` / `./` / `..` / 绝对路径的链接和 http 图片不渲染,仓库内图片按原图比例显示,点了打开原图,没有就写「找不到图片」,仓库路径链接能点、点了打开文件并跳到符号;跳到定义不认 Markdown 里的名字。不带路径的引用:行内规则(`webview-ui/.../markdown.test.ts`:`[Name]`、`[A.b]` 是 `symbol:` 链接,`` `[x]` ``、`items[i]`、`[会话进展]`、`[名字](路径)`、`[Agent](javascript:x)` 各自的结果,问 AI 的回答不认、带增删的注释照样认);问答(`repoLink.test.ts`:`symbol:` 地址只认标识符、点了发不带 `path` 的 `openRepoLink`、和仓库路径一起问、找不到的标坏、打开成功不再标、同样的链接不再问、文档换了版本再问);扩展端(`symbolLinks.test.ts`:本文件优先于导入且不问语言扩展、本文件的 `Class.member`、类有成员没有就是找不到、导入的名字问定义再在那个类底下找成员、整模块导入从顶层找、找不到;Python / TypeScript 各种导入写法引进来的名字和问定义的位置,`gate.py` 的导入)。
|
||||
- 注释挂到它讲的块上(各语言的 `languages/*.test.ts`「注释挂到它讲的块上」,`outline` 的 `notes` 是挂着的各段注释在哪):Python、TypeScript、Rust、Shell、Dockerfile 各一份,覆盖隔着空行的注释挂到后面那块、主体最后的挂到前面那块、主体里只有注释时挂到父块、文件最后的挂到最后一块、文件开头隔着空行的是文件的说明而紧挨着第一块代码的挂到它上面、`#!` / 写编码的 / `//!` / `@file` / 模块 docstring 是文件的、说明和注释并存、函数体里语句前面的注释;luffy 的 `fixtures/acquisitionRepository.py` 导入后面的注释挂到类上(`blockView.test.ts`:类卡片「名称、注释、访问级别」、编辑范围连着注释、写回原样);TypeScript 的「名称、说明、注释」、几段注释是几段 Markdown、一行译文的卡片的 `rows`;嵌着的代码里的块没有 `commentTarget`;改了注释那块算修改、「注释」一行逐词标(`diff/blockDiff.test.ts`);规则略去挂着注释的块不合约定(`libraryRules.test.ts`)。webview(`BlockTree.test.tsx`):「注释」一行照属性表画、按钮在这一行上,一行译文的卡片排在译文下面,没有注释时按钮在右上角叫「按注释规范写注释」,不能写注释的块没有按钮。
|
||||
- 重写注释(`commentRewrite.test.ts`、`qa/claudeAsk.test.ts`):发给模型的就是 `/ecc:writing-code-comments 路径:起-止` 一句;读结构化结果(正文逐字长出来、读文件是在做的事、只回一段话没有正文、报错);命令行在只读那套后面加 `--json-schema`、stdin 里只有那一句;交回结构化正文 → 换掉块前面几段注释(套回 `#` 和缩进)、文件开头的说明换它自己;没有注释的块新写一段插在上面(缩进同块,docstring 不动);没交回正文、出错、重写期间代码变了 → 失败不写,叫停 → 不写;套回壳的几种写法(三引号、`#`、`/** */`、`//`)。
|
||||
- 注释的 Markdown:「注释」一行、文件开头的说明、函数和类「说明」的视图数据是 `{ markdown }`,原文照抄(reST 角色、双反引号、`{@link}`、HTML 都不转换,块标签拆出去),行注释连成的块留得住缩进四格的代码块;渲染时 HTML 当文字、带协议的网址和邮箱成链接、不带协议的文件名不成链接,`javascript:` / `command:` / `./` / `..` / 绝对路径的链接和 http 图片不渲染,仓库内图片按原图比例显示,点了打开原图,没有就写「找不到图片」,仓库路径链接能点、点了打开文件并跳到符号;跳到定义不认 Markdown 里的名字。不带路径的引用:行内规则(`webview-ui/.../markdown.test.ts`:`[Name]`、`[A.b]` 是 `symbol:` 链接,`` `[x]` ``、`items[i]`、`[会话进展]`、`[名字](路径)`、`[Agent](javascript:x)` 各自的结果,问 AI 的回答不认、带增删的注释照样认);问答(`repoLink.test.ts`:`symbol:` 地址只认标识符、点了发不带 `path` 的 `openRepoLink`、和仓库路径一起问、找不到的标坏、打开成功不再标、同样的链接不再问、文档换了版本再问);扩展端(`symbolLinks.test.ts`:本文件优先于导入且不问语言扩展、本文件的 `Class.member`、类有成员没有就是找不到、导入的名字问定义再在那个类底下找成员、整模块导入从顶层找、找不到;Python / TypeScript 各种导入写法引进来的名字和问定义的位置,`gate.py` 的导入)。
|
||||
- 行替换:多行块替换后缩进正确。
|
||||
- 跳到定义:TS / Python 译文和属性表里的名字、点分模块名每一节、模块字符串带下标且指回源码原文,关键字、运算符、说明词不带(前面有中文注释也对得上);查到的定义 → 不动 / 原地 / 别的文件 / 挑选框,别的文件用哪种编辑器(`editor/openTarget.test.ts`:有代码阅读的用预览、带位置时滚到那一行闪定义处,没有的用默认的打开方式选中名字,打不开成文本的用默认的打开方式);webview 里按下标找目标块、要展开的祖先块和属性行,滚动位置。悬停看定义卡片:取哪块(`editor/definitionPeek.test.ts`:Python 源码走完整的语言插件 + 翻译插件,类名 → 类那块连同子块,参数 → 所在的函数,变量 → 变量那块,块外面 → 没有,挂在子行上的子块去掉 `slot`;卡片上的中文名只带画出来的、长度对得上的,别的文件只认定义本身),什么时候弹、收(`definitionPeek.test.ts`:停够延迟才问、没到时间移开不问、没有卡片不弹、迟到的回答丢掉、链接问 `peekLink` 点标题发 `openRepoLink`、没收到延迟不弹、移开过 `hidingDelay` 才收、移进浮窗不收、扫过别的名字不往后推、浮窗里不弹别的、换成新名字的卡片、Esc / 滚动后不再弹、换文档版本收起;指到符号的链接才弹;放在下方 / 上方 / 空间大的那边、钳在视口内),只读的卡片(`DefinitionPeekPopup.test.tsx`:类收起子块、没有编辑 / 问 AI / 重写按钮、中文名用卡片带的、引用不成链接;`markdown.test.ts` 的 `peek`)。闪哪一处(TS、Python 源码走完整的语言插件 + 翻译插件 + 视图数据):参数 → 它那个子行,导入项 → 它那一项,多变量声明里的一个 → 它的名称行,类的泛型参数 → 「类型参数」那一行,函数名 / 类名 / 单个变量名(含解构模式)→ 整块,循环变量 → 所在的块,翻译插件没填 `defines` → 整块(照样展开属性行);翻译插件给参数、导入项、声明的变量、泛型参数标的范围指回源码原文;块自己的名字只有函数、类和单变量声明有。
|
||||
- 高亮各处出现:段的源码范围和出现重叠才亮、边界相接不算、没下标的不亮,讲别处名字的段(`refers`)按那个名字算、自己照抄的位置不算(`occurrences.test.ts` 的 `sourceOf`),点分模块名每一节各按自己的范围认(真实的 Python 译文和属性表:定义处按写入、用到处按读取);写入 → 强高亮色,读取、按文字 → 普通高亮色,同时碰上按写入;单击名字问、点空白处清、点按钮 / 链接 / 筛选栏不动、名字在按钮里照样问,拖选、双击第二下、带修饰键的点击不动,⌘ / Ctrl + 点击照旧发跳到定义、不问出现处;回答连同名字显示、空回答不亮、换名字时回答到前旧的留着、迟到的回答丢掉、答过「没有」再点照样再问、清掉后才到的回答丢掉、换文档版本或翻译清掉而同版本同翻译重发不清、没有文档时不问。键盘跳(`occurrences.test.ts`、`reveal.test.ts`、`editor/occurrenceNavigation.test.ts`):回答照源码先后排、点中的那处是当前那一处、「2/5」和「N 处」;往后 / 往前、到头接着跳,找不到的跳过、总数照旧、一处都找不到不动,点中的不在回答里从点中的地方数起;只有当前那一处描框;能不能跳(高亮、焦点、输入框)第一次必报、之后变了才报;页面上找第一处显示着它的地方、要展开的块 / 属性行 / 子行、跳过筛掉 / 编辑 / 盖住的块、Markdown 不算;`package.json` 的两条命令、默认键、`when`、命令面板,扩展和页面的代码里不写键、不拦键,上下文键有一个预览能跳就真、变了才设,命令发给能跳的预览、没有就发给活动的;按键那一刻的位置跳转时回一次、隔太久 / 点过鼠标 / 没按过键不回,跳完守住跳到的位置、过了 `KEY_SCROLL_MS` 或又按键、点鼠标不守。
|
||||
@@ -2220,7 +2265,7 @@ vscode/webview-ui/code-reader.html + src/codeReader/ 预览界面(React,Vit
|
||||
- 语言插件(`languages/bash.test.ts`,真实解析):`fixtures/fetchRuntime.sh` 的代码块树(种类、行号、层级,同原型 `SHELL_BLOCKS`,原型略去的行也在);elif / else 展平、while / for 的主体是子块、条件串和命令串;解释器(env、写死的路径)、选项(连写拆开、`-o`、`+`、`set --` 不是)、变量(local 一句几个、没值的、readonly 和顶层全大写写死的是常量)、函数(按位置的参数和名字、打印的几句、被 `$(…)` 拿去用、写了的 return);命令的词(写死的文字、有展开的没有)和重定向;同一文件里的名字(函数、赋值、local、for、read、展开,第几个参数不算);行尾 `# @Comment`。
|
||||
- 中文直译(`translators/bashZh.test.ts`,走 `readBlockViews`):`fetchRuntime.sh` 整份逐行同 `FETCH_READING`(即上面「Shell 脚本」的样例);展开(长度、去头去尾、截取、没设时、替换、特殊变量)、条件、重定向、命令规则(不认识的选项照抄、没有规则的照抄)、`&&` / `||`、遍历、`$(dirname "$0")`、常量;字符串色 / 变量色 / 常量色;规则出错照抄命令并报告。
|
||||
- 宿主:命令规则按语言、注册顺序给(`registry.test.ts`),shellscript 的 document 消息带命令规则读的译文、shell 的种类名、同一文件里的名字(`editor/documentMessage.test.ts`),跳到之前最近的定义、定义处算写入(`localSymbols.test.ts`)。
|
||||
- Rust(`languages/rust.test.ts`、`rules/rustLibs.test.ts`,真实解析):`fixtures/rustLang.rs` 的导入、结构体、枚举、实现(方法挂在方法表的子行上)、函数(异步、分情况)、特质逐行同预览;给结构体加一个字段,字段表那一行标成新增。`fixtures/rustComments.rs` 开头连着写的 `//` 合成一块注释,预览是去掉 `//` 的三段 Markdown;隔着空行、语句的注释各是一块,行尾 `//` 不单独成块,`//!` 连着几行合成一块,`///` 并进下一个函数当说明,`mod`、`impl` 身体里同一套。编译属性:Tauri `main.rs` 的 `cfg_attr` 卡片逐行(属性的着色、「非 调试构建」、「整个 crate」、windows 子系统的说明),别的文件顶层的 `allow` 是本模块、列出 lint 名,认不得的属性没有说明、不知道文件名时是所在模块,`cfg_attr` 里几个属性是一张表、套着的条件加括号,`isCrateRoot` 的几种路径。`fixtures/rustLibs.rs` 的 serde(改名、不输出、字段名改驼峰)、thiserror(展示、透传来源)、axum(方法、路径、路径参数)、sqlx、tauri 逐行同预览;没导入 serde 时 derive 仍是结构体;改 axum 的路径,路径那一格标成改过。`axum::routing` 这种来源算导入了 axum。
|
||||
- Rust(`languages/rust.test.ts`、`rules/rustLibs.test.ts`,真实解析):`fixtures/rustLang.rs` 的导入、结构体、枚举、实现(方法挂在方法表的子行上)、函数(异步、分情况)、特质逐行同预览;给结构体加一个字段,字段表那一行标成新增。`fixtures/rustComments.rs` 开头连着写的 `//` 合成一段,是文件的说明,预览是去掉 `//` 的三段 Markdown;别的注释挂到后面那一项(「注释」一行),行尾 `//` 不单独成块,`//!` 连着几行合成一段、是文件的说明,`///` 并进下一个函数当说明、普通注释同时是它的「注释」,`mod`、`impl` 身体里同一套。编译属性:Tauri `main.rs` 的 `cfg_attr` 卡片逐行(属性的着色、「非 调试构建」、「整个 crate」、windows 子系统的说明),别的文件顶层的 `allow` 是本模块、列出 lint 名,认不得的属性没有说明、不知道文件名时是所在模块,`cfg_attr` 里几个属性是一张表、套着的条件加括号,`isCrateRoot` 的几种路径。`fixtures/rustLibs.rs` 的 serde(改名、不输出、字段名改驼峰)、thiserror(展示、透传来源)、axum(方法、路径、路径参数)、sqlx、tauri 逐行同预览;没导入 serde 时 derive 仍是结构体;改 axum 的路径,路径那一格标成改过。`axum::routing` 这种来源算导入了 axum。
|
||||
- Dockerfile:
|
||||
- 语言插件(`languages/dockerfile.test.ts`,真实解析):两份 luffy 的 Dockerfile 的代码块树(同原型,后端的三行注释是阶段说明);并块(紧挨着才并,空行、注释、别的指令隔开,COPY 要从同一个地方,ADD、heredoc 的 COPY 不并,第一个 FROM 之前的是顶层);ONBUILD 和各种设置;facts(解析指令、阶段的名称 / 序号 / 说明 / 标签 / 摘要 / 平台 / 接着前面的阶段、构建参数和环境变量并块、健康检查两种写法和 NONE、启动);嵌着的 shell 的几段(续行去掉、heredoc 正文);数组写法的命令(VOLUME、SHELL 的数组不算);同一文件里的名字(阶段名在 --from、--mount 的 from、FROM 里,变量);中文名;着色。
|
||||
- 中文直译(`translators/dockerfileZh.test.ts`,走 `readBlockViews`,RUN 交给 bash 的插件):两份 luffy 的 Dockerfile 整份逐行同 `NEXT_READING`、`BACKEND_READING`;阶段的各种写法、变量的展开和注解、RUN 的选项 / 数组写法 / heredoc / 一条循环 / 带重定向的一串、没有 shell 插件时照抄、复制和 ADD、设置、健康检查、启动;阶段名和表里变量名的源码下标、RUN 的源码按 shell 着色。
|
||||
@@ -2234,14 +2279,14 @@ vscode/webview-ui/code-reader.html + src/codeReader/ 预览界面(React,Vit
|
||||
- 库规则的引用:引用标的不是自己、规则没给 `resolve`、段没带下标时当替身不合约定;查引用交给标它的规则,规则不在、没给 `resolve`、出错时记下来、当作没有定义;视图数据里的引用(下标 → 引用)只从规则认领的块的属性表里取,查定义时是引用的问规则、其余问语言扩展,只对记下它的那个文档版本有效(`editor/definitionSources.test.ts`)。
|
||||
- 工作区索引(内存里的工作区,`MemoryIndexHost`):第一次查才建、同一个 id 只建一份;查到的是名字的行列(列按 UTF-16)、照文件和行排好;预筛不过的不解析;改了只重看那一份、新建加进来、删目录连里面的去掉;新建 / 删掉问过在不在的文件(`__init__.py`)时问过它的文件重看;建索引期间的改动建好后补上;读不了、规则出错的记下来、别的照常;dispose 后不再盯着。还要跳过的文件(`workspaceScope.test.ts`,内存里的文件夹):子目录里 `.git` 是文件的 git worktree、`.git` 是目录的子仓库整个跳过,工作区自己的 `.git` 不算;`.gitignore` 忽略的目录跳过,每层规则相对那一层、取反照 gitignore 写法,`.ignore` 也读;`search.useIgnoreFiles` 关着时不读忽略文件、嵌套的 checkout 照样跳过;同一个目录只查一次。
|
||||
- Celery 规则:`fixtures/celeryApp.py` 的应用卡片和定时任务卡片逐字同上面的样例(列名、「12 条,另有展开 1 处」、行尾注释、条目里单独成行的注释、跨行的 `10⏎ * 60`、`每 get_settings().… 秒`、展开一行);任务名是引用、下标指回源码原文;应用卡片的位置参数按参数顺序认、别的参数各一行、展开、属性 docstring、别名;没导入 celery、不是 `Celery(...)` 的不认;频率换算(秒数算式、`timedelta`、`crontab` 各种写法、`schedule`、换算不了的「每 X 秒」和照写法);说明取哪些注释;条目名和任务名不同、没写任务名、任务名不是字符串、值不是字典、选项一列有才有;`conf.update(beat_schedule=…)`、不带 `beat_schedule` 的 `conf.update` 和 `autodiscover_tasks` 照常。任务名索引:显式 `name=`、默认「模块路径.函数名」(包、`src` 下的命名空间包、没有包)、`@shared_task` / `@shared_task()` / `@app.task` 不带括号 / 老写法 `@task`、`async def`、函数里的只认显式名字、`name=` 不是字符串的不认、同名几处都给、文件改了和新建 `__init__.py` 后跟着变、没有任务装饰器的文件不解析。
|
||||
- 枚举(`rules/enum.test.ts`、`languages/typescript.test.ts`):`fixtures/enumModels.py` 的 `CommissionStatus` 逐字同上面的样例,`SecretScope` 的 docstring 当说明、没有说明列;种类 enum、叫「枚举」、访问级别同原来的类、没有标签(badge),编辑范围是整个类;Python 成员规则(dunder、sunder、私有名、`_ignore_`、lambda、`property`、`nonmember`、只写注解的不是成员,`auto()` 写「自动」,`member(x)` 取 x,说明取上面的注释块、行尾注释、属性 docstring,装饰器);方法、嵌套类、不是成员的属性照源码顺序是子块,成员前面的注释并进来、最后面的留下,「编辑」写回整个类;类名、成员名的定义范围和带下标的词指回源码原文;没导入 enum、SQLAlchemy 的 `Enum`、不是枚举类型的父类不认,`import enum as e` 的 `e.IntEnum` 认。TypeScript:`enums.ts` 里 export / const / declare / 函数里的 enum 都是枚举块、JSDoc 进头部,写的值、自增算出的值(接不上数字就没有)、说明(上面的注释和 JSDoc、行尾注释,同一行的 JSDoc 讲下一个),访问级别;自增的值和「自动」按 hint。TypeScript 和 Python 同样的成员得到一样的种类、属性表行、列名和格子着色(除了 Python 多的「继承」)。宿主:规则认成现成属性表块时照语言插件报的这种块显示、并进来的不是子块时照常显示;webview 枚举块默认折叠。
|
||||
- 数据类(`rules/dataclass.test.ts`):`fixtures/dataclassModels.py` 的 `SandboxAccess` 逐字同上面的样例,`AdminUserRow`、`RedirectPayResult`(`field(init=False, default=…)`)、`SmsSent`(`default_factory=dict`)的行;种类 `dataclasses.dataclass`、叫「数据类」、颜色、访问级别同原来的类;编辑范围是整个类、写回原样,`__post_init__` 是子块;类名、字段名的定义范围和带下标的词指回源码原文;装饰器的写法(别名、`dataclasses.dataclass`、`dc.dataclass`)认,pydantic 的、`other.dataclass` 不认,没导入 dataclasses 不认;每个选项的译法、默认值不讲、别的照写、`**x`、别的装饰器一行;字段规则(`ClassVar`、`typing.ClassVar` 留作子块,`InitVar` 的类型和「仅初始化时使用」,`KW_ONLY` 记号并进来、后面的字段「只能按名字传参」、单独写 `kw_only=False` 的「可按位置传参」),`field(...)` 的默认值、`default_factory`(名字、lambda)、各参数、`metadata` 照写、`doc=`,说明取上面的注释块、行尾注释、属性 docstring;没注解的类属性、字段中间的方法照源码顺序是子块,「编辑」写回整个类。
|
||||
- 枚举(`rules/enum.test.ts`、`languages/typescript.test.ts`):`fixtures/enumModels.py` 的 `CommissionStatus` 逐字同上面的样例,`SecretScope` 的 docstring 当说明、没有说明列;种类 enum、叫「枚举」、访问级别同原来的类、没有标签(badge),编辑范围是整个类;Python 成员规则(dunder、sunder、私有名、`_ignore_`、lambda、`property`、`nonmember`、只写注解的不是成员,`auto()` 写「自动」,`member(x)` 取 x,说明取讲它的注释、行尾注释、属性 docstring,装饰器);方法、嵌套类、不是成员的属性照源码顺序是子块,讲成员的注释跟着并进来、类主体最后的注释挂在最后一块上,「编辑」写回整个类;类名、成员名的定义范围和带下标的词指回源码原文;没导入 enum、SQLAlchemy 的 `Enum`、不是枚举类型的父类不认,`import enum as e` 的 `e.IntEnum` 认。TypeScript:`enums.ts` 里 export / const / declare / 函数里的 enum 都是枚举块、JSDoc 进头部,写的值、自增算出的值(接不上数字就没有)、说明(上面的注释和 JSDoc、行尾注释,同一行的 JSDoc 讲下一个),访问级别;自增的值和「自动」按 hint。TypeScript 和 Python 同样的成员得到一样的种类、属性表行、列名和格子着色(除了 Python 多的「继承」)。宿主:规则认成现成属性表块时照语言插件报的这种块显示、并进来的不是子块时照常显示;webview 枚举块默认折叠。
|
||||
- 数据类(`rules/dataclass.test.ts`):`fixtures/dataclassModels.py` 的 `SandboxAccess` 逐字同上面的样例,`AdminUserRow`、`RedirectPayResult`(`field(init=False, default=…)`)、`SmsSent`(`default_factory=dict`)的行;种类 `dataclasses.dataclass`、叫「数据类」、颜色、访问级别同原来的类;编辑范围是整个类、写回原样,`__post_init__` 是子块;类名、字段名的定义范围和带下标的词指回源码原文;装饰器的写法(别名、`dataclasses.dataclass`、`dc.dataclass`)认,pydantic 的、`other.dataclass` 不认,没导入 dataclasses 不认;每个选项的译法、默认值不讲、别的照写、`**x`、别的装饰器一行;字段规则(`ClassVar`、`typing.ClassVar` 留作子块,`InitVar` 的类型和「仅初始化时使用」,`KW_ONLY` 记号并进来、后面的字段「只能按名字传参」、单独写 `kw_only=False` 的「可按位置传参」),`field(...)` 的默认值、`default_factory`(名字、lambda)、各参数、`metadata` 照写、`doc=`,说明取讲它的注释、行尾注释、属性 docstring;没注解的类属性、字段中间的方法照源码顺序是子块,「编辑」写回整个类。
|
||||
- Pydantic 数据模型(`rules/pydantic.test.ts`):`fixtures/aigcMetadata.py` 的 `AIGCMetadata` 逐字同上面的样例(7 个无默认值字段、选项「严格 · 禁止多余字段」、`model_config` 不单成一块),`TextTrace` 的可空字段默认值是「空」;`fixtures/createShareRequest.py` 的 `CreateShareRequest` 逐字核对字段、说明、长度约束,`@field_validator` 仍是子块;种类 `pydantic.model`、叫「数据模型」、颜色、图标 `braces`;同一文件里继承模型的也算,`TypedDict`、`NamedTuple`、普通类、没导入 pydantic 的不是;别名、`Field` 的默认值 / `default_factory` / 约束、说明优先于注释,`ClassVar` 和没注解的类属性留下;类型里的名字带源码下标;索引只收本文件里能确定的模型、没写 `BaseModel` 的文件不解析,别的文件里的父类查不到先当普通类、查到再换成卡片;差异:加一个字段标新增,改一个默认值标那一格。
|
||||
- FastAPI 接口(`rules/fastapi.test.ts`):`fixtures/routes.py` 的 `update_user` 逐字同上面的样例(查到 `Forbidden` 是 403 时四条消息写在一行,没查到时不列),名字、颜色、图标、列名、筛选属性、定义范围、编辑范围是整个函数、函数体是子块;着色(URL 的 `{参数}` / 路径,花括号里的参数名 `refers` 到函数的参数,方法的 Swagger 颜色、成功的状态码绿色、自动带的 422 淡色,带下标的词指回源码原文);`fixtures/skillHubRoutes.py` 的 `list_skills`(Annotated 里的 Query、`_` 的依赖)、`get_skill`(HTTPException 的 status_code / detail)、`install`(Request 不算、`-> None` 没有内容);`fixtures/consoleRoutes.py` 的 `create_user`(`status_code=201`、Pydantic 模型、调别的函数间接抛的不算)、`list_users`(查到的类型别名 `FilterQuery` 是依赖、Literal 是简单类型);参数放在哪儿的各条(路径里的名字含 `{x:path}`、各种标记两种写法、上传文件、枚举和类型别名查到的、Pydantic 模型、`Security`、`Depends()`);标签、依赖、`responses=` 叠上路由对象的,`status.HTTP_…` 常量、`response_model=None`、`response_description`、`raise … from`、只写 `raise`、嵌套函数里的;`FastAPI()` 上的接口、别的装饰器一行;不认的(没导入、路由对象在别的文件、不是路由对象、`websocket`、不带括号)。跨文件(工作区索引 + 假的语言扩展):`update_user` 的 `Forbidden` 按定义处查到 `core/exceptions/schemas.py` 的 403,同名的别处的类不算;索引认的类上的 `status_code`(带注解、常量)、枚举类、`Annotated` 类型别名,普通类不认。路由器卡片:`fixtures/routes.py` 的 `router` 逐字同上面的样例,名字、颜色、图标、列名、编辑范围、定义范围;接口表的函数名带下标、路径里的 `{user_id}` 各 `refers` 到各自函数的参数、方法的颜色;接口卡片的「路由器」行排在说明后面、名字带下标指回路由器;写了依赖、默认响应才有这两行,`FastAPI()` 没有前缀,属性 docstring 是说明,没挂接口时「0 个」、不画表格。
|
||||
- React 组件(`rules/reactTree.test.ts`、`rules/react.test.ts`,luffy 的九个真实组件):认组件(七个文件里的组件、小写工具函数和不渲染 JSX 的不认;memo / forwardRef 包着的、默认导出、文件末尾 export 的、null 和 JSX 混着返回的;组件体里的语句、提前返回的 if 里的 return 认得出在哪个组件里);构造参数(行内类型字面量、同文件接口带 JSDoc、回调、children、默认值、改名、其余属性、方法签名、`FC<Props>`、`forwardRef<R, Props>`、导入的类型查不到和查到了);组件体的归类、名字用在哪(副作用、渲染时重置、挂在 `<main>` 的 ref、处理函数绑在每个按钮上);渲染大纲(原生标签、组件、类、条件、三元、列表、片段、注释、几处返回)和 className 的写法。卡片:组件卡片只有名称 / 说明 / 构造参数,组件体照源码顺序是子块,`"use client"` 和 JSDoc 不单独成块(文件里没组件时 `"use client"` 照常成块);`fixtures/planChecklist.tsx.txt` 逐字同上面的样例;QueuedBubble 的状态、引用、变量、副作用、两个事件处理函数、渲染输出照源码顺序、函数体是子卡片,提前 `return null` 是如果卡片;状态的更新位置、引用的使用位置只写名字和位置;数据源的几种说明;useMemo / useCallback 的派生值、带清理的副作用、触发时机的几种写法、没绑在 JSX 上的处理函数写由谁调用;直接返回 JSX 的组件把大纲写在卡片里;九个文件认领下来都合约定;差异:加一个属性、改一个副作用的依赖,组件卡片属性表那一行新加、副作用卡片「触发时机」逐截标。宿主:`libraries` 空的规则都启用;略去的块不出块、有子块的不能略去。webview:小标签、条件小框、类名小标的样子(`SegmentText.test.tsx`)。
|
||||
- React 组件(`rules/reactTree.test.ts`、`rules/react.test.ts`,luffy 的九个真实组件):认组件(七个文件里的组件、小写工具函数和不渲染 JSX 的不认;memo / forwardRef 包着的、默认导出、文件末尾 export 的、null 和 JSX 混着返回的;组件体里的语句、提前返回的 if 里的 return 认得出在哪个组件里);构造参数(行内类型字面量、同文件接口带 JSDoc、回调、children、默认值、改名、其余属性、方法签名、`FC<Props>`、`forwardRef<R, Props>`、导入的类型查不到和查到了);组件体的归类、名字用在哪(副作用、渲染时重置、挂在 `<main>` 的 ref、处理函数绑在每个按钮上);渲染大纲(原生标签、组件、类、条件、三元、列表、片段、注释、几处返回)和 className 的写法。卡片:组件卡片只有名称 / 说明 / 构造参数,组件体照源码顺序是子块,`"use client"` 不单独成块(文件里没组件时、它挂着注释时照常成块),JSDoc 是组件块的说明;`fixtures/planChecklist.tsx.txt` 逐字同上面的样例;QueuedBubble 的状态、引用、变量、副作用、两个事件处理函数、渲染输出照源码顺序、函数体是子卡片,提前 `return null` 是如果卡片;状态的更新位置、引用的使用位置只写名字和位置;数据源的几种说明;useMemo / useCallback 的派生值、带清理的副作用、触发时机的几种写法、没绑在 JSX 上的处理函数写由谁调用;直接返回 JSX 的组件把大纲写在卡片里;九个文件认领下来都合约定;差异:加一个属性、改一个副作用的依赖,组件卡片属性表那一行新加、副作用卡片「触发时机」逐截标。宿主:`libraries` 空的规则都启用;略去的块不出块、有子块的不能略去。webview:小标签、条件小框、类名小标的样子(`SegmentText.test.tsx`)。
|
||||
- 规则查别的文件里的定义(`ruleLookups.test.ts`):第一遍当没查到、记下问了什么(同一索引同名的只记一处);查到后叫重排,交出定义处正是的那一项;同一版本不再查;索引里没有同名的不问语言扩展,定义处不是索引里的项算没有,没变不叫重排;新版本先用上一版的、再查、变了才叫重排;语言扩展没答时已知的不动、隔一会儿再查。
|
||||
- 带自己颜色的词(webview `SegmentText.test.tsx`):`cr-colored`,暗色、亮色写在 style 上;讲别处名字的段 `data-offset` 记那个名字的下标。
|
||||
- 异常(`languages/exceptions.test.ts`,真实解析 + 中文直译 + 视图数据):`fixtures/appExceptions.py` 的 `AppException`、`NotFound` 逐字同「异常」的样例(列名随有没有类型、说明变),`GatewayTimeout` 的多段说明,方法是子块;`fixtures/commerceExceptions.py` 16 个类都是异常、只有说明的四行、写了 `__init__` 的构造参数;认哪些类(自带的异常类、`Warning`、不合后缀的自带类 `StopIteration` / `KeyboardInterrupt`、`pkg.errors.AppException`、同一文件里写在后面的父类一层层往下传、泛型和别的父类混写,关键字参数、`Mapping[...]`、`*bases` 不算,函数里的类也认);类属性(带不带注解、只写注解、说明取上面的注释块 / 行尾注释 / 属性 docstring,连着赋值、解构赋值、方法、讲方法的注释、最后面的注释留作子块),构造参数去掉 self、`*args` 开头的不去;`@dataclass` 的异常类照样是异常卡片;编辑范围是整个类、改卡片写回整个类,类名、属性名、参数名的定义范围和带下标的词指回源码原文;TypeScript `fixtures/exceptions.ts.txt`(`extends Error`、类字段含 static、参数属性、JSDoc、写在后面的父类、类表达式、`ns.X<T>`,父类名不合习惯的照常是类)、JavaScript 的类字段;TypeScript 和 Python 同样的异常得到一样的行和列名;筛选的种类叫「异常」、没有 badge;属性的中文名和去掉行尾记号。webview:异常块默认折叠(`viewState.test.ts`),跳到类名闪整块、属性名 / 构造参数名只闪表里那一行(`reveal.test.ts`)。
|
||||
- 异常(`languages/exceptions.test.ts`,真实解析 + 中文直译 + 视图数据):`fixtures/appExceptions.py` 的 `AppException`、`NotFound` 逐字同「异常」的样例(列名随有没有类型、说明变),`GatewayTimeout` 的多段说明,方法是子块;`fixtures/commerceExceptions.py` 16 个类都是异常、只有说明的四行、写了 `__init__` 的构造参数;认哪些类(自带的异常类、`Warning`、不合后缀的自带类 `StopIteration` / `KeyboardInterrupt`、`pkg.errors.AppException`、同一文件里写在后面的父类一层层往下传、泛型和别的父类混写,关键字参数、`Mapping[...]`、`*bases` 不算,函数里的类也认);类属性(带不带注解、只写注解、说明取讲它的注释 / 行尾注释 / 属性 docstring,连着赋值、解构赋值、方法留作子块,讲方法的注释、类主体最后的注释挂在方法、最后一块上),构造参数去掉 self、`*args` 开头的不去;`@dataclass` 的异常类照样是异常卡片;编辑范围是整个类、改卡片写回整个类,类名、属性名、参数名的定义范围和带下标的词指回源码原文;TypeScript `fixtures/exceptions.ts.txt`(`extends Error`、类字段含 static、参数属性、JSDoc、写在后面的父类、类表达式、`ns.X<T>`,父类名不合习惯的照常是类)、JavaScript 的类字段;TypeScript 和 Python 同样的异常得到一样的行和列名;筛选的种类叫「异常」、没有 badge;属性的中文名和去掉行尾记号。webview:异常块默认折叠(`viewState.test.ts`),跳到类名闪整块、属性名 / 构造参数名只闪表里那一行(`reveal.test.ts`)。
|
||||
- 筛选:块的属性(TS、TSX 有抽象、仅类型,JavaScript / JSX 没有这两个属性、属性表也没有这两行,Python 有访问级别、异步);语言插件自己报的属性叠上去、盖过推出来的,kind 不变;文件里出现过的属性按契约顺序排、语言的排后面,值按第一次出现排、带所有层的块数,名字取翻译插件的、没有的显示 id,中文直译的名字和属性表一致;下拉框只给两种以上值的属性(或一种值正被去掉的),按钮上的字;全选 / 取消全选只动这份文件里的值、别的文件的去掉状态和别的属性不动、取消全选藏掉有这个属性的块(整棵子树)、再全选全回来;同一属性内「或」、不同属性「且」、没有这个属性不受影响、藏整棵子树、「已隐藏」只数直接筛掉的;筛选记在 `workspaceState`、新实例读得回来、所有订阅的预览收到、形状不对的当没有;跳到被筛掉的块临时露出路径、目标的子块照常筛、文档刷新只留正在编辑的。
|
||||
- 文件注释:键相对工作区文件夹、`/` 分隔,根和外面的路径没有键,手写的 `./`、结尾 `/` 规范掉;保存去空白、清空即删;文件改名、目录挪位置里面各层一起走、名字只是前缀相同的不动、跨工作区文件夹先取出再放进去;删目录连带里面的;读写:文件缺失 / 解析失败 / 不是对象返回空表、跳过不合法条目、建 `.spx`、键排序、删光留 `{}`;有注释 / 没注释的行的描述、悬停提示(Markdown 转义)、contextValue,和 `package.json` 里菜单的 when 子句对得上。
|
||||
- 侧栏行上的菜单(`explorer/rowMenus.test.ts`,读 `package.json`):行尾按钮先「复制」子菜单再注释,有没有注释换「添加 / 编辑注释」,工作区根都没有;「复制」子菜单带 `$(copy)`,注释图标 `$(note)` / `$(edit)`;子菜单和右键菜单里文件四项、目录三项(有没有注释一样)、菜单上的字;复制命令都登记了、和代码里的命令表一致、命令面板里藏起来;「在系统文件管理器中显示」文件和目录(含未提交、有注释)都有、工作区根和分组行没有、审查时也有,三个系统各只出自己那一项、字和 VS Code 自带的一样,自成一组排在复制和注释中间,不挂行尾按钮、命令面板里藏起来。
|
||||
|
||||
Reference in new issue
Block a user