尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VSCode snippets 代码模板:语法、变量与团队共享实践

VSCode snippets 代码模板:语法、变量与团队共享实践 我最早对 VSCode snippets代码模板的印象就是敲三个字母加一个 Tab然后屏幕上冒出一行console.log()。当时觉得这功能挺可爱但也就那样。真正让我改变看法的是接了一个前后端混杂的项目同一天里我要写 Vue 3 的组件骨架、写 Node 的接口处理器、写几段 Python 数据处理脚本还要顺手改一点 C 的测试用例。一天下来统计了一下我敲的字符里有相当一部分是在重复同一批结构——script setup开头那几行、try/except的固定收尾、for循环的固定模板。这些代码没有任何智力含量却实实在在吃掉了时间和注意力。snippets 解决的正是这部分劳动。它不是代码补全也不是 AI 生成它是你自己预先写好的一段文本骨架靠一个短前缀唤出来把光标按你预留的位置一个个跳过去让你只填真正需要动脑的部分。这篇文章想做的事情很具体把 VSCode 里 snippets 从语法到落盘、从个人使用到团队共享、从写不出来到排查为什么不出效果完整讲一遍。如果你已经用过 snippets 但只停留在「从插件市场装了个 Vue 3 snippets 包」的阶段那这篇正好补齐你自己动手的那一半。1. snippets 在编辑器里到底替代了哪部分劳动1.1 补全、模板、AI 生成解决的不是同一件事很多人把这三者混在一起讨论其实它们的触发逻辑完全不同搞混了就会在错误的地方找解决方案。IntelliSense 补全依赖语言服务Language Server对当前工程做语义分析。它能告诉你这个对象上有哪些方法、这个函数的参数是什么类型前提是代码能被正确解析。所以当你在 C 项目里发现「写 C 没有代码提示」问题通常出在编译配置或语言服务上跟 snippets 一点关系都没有。snippets依赖你自己定义的文本模式。它不理解语义你把foo定义成一段while(1){}它照样给你吐出来。好处是绝对可靠、零延迟、离线可用坏处是它不会替你判断这段模板在这里合不合适。AI 补全依赖上下文概率能生成你从没写过的东西但结果不稳定同一位置多按几次可能给出不同答案而且在涉及内部规范、私有接口、特定业务约束时经常跑偏。维度snippetsIntelliSense 补全AI 补全判断依据你定义的文本模式语言服务语义分析上下文概率预测可靠性完全确定高依赖工程可解析波动较大触发成本极低低有网络与算力成本适合场景结构固定、写法统一的骨架符号、方法、参数探索性、非重复性代码团队一致性可以版本化统一依赖工程配置难以统一看完这张表就能明白snippets 的位置其实很清晰只负责那些你已经确定「就应该这么写」的部分。1.2 一个 snippet 从敲下前缀到展开的完整链路想排查问题先得知道正常流程长什么样。一次 snippet 展开大致经过这么几步你在编辑器里输入字符编辑器收集当前光标前的词建议列表Suggest Widget根据当前语言过滤可用的 snippet 集合命中某个 snippet 的prefix后把body拿出来做渲染渲染过程中求值所有内置变量比如TM_FILENAME、CURRENT_YEAR光标跳到第一个 tabstop你填内容按 Tab 进入下一个全部 tabstop 走完后光标落在$0指定的位置。这个链路里任何一环断了表现都不一样第 2 步断了是「建议列表里根本没有」第 3、4 步断了是「展开出来是空的或者变量没被替换」第 5 步断了是「展开后光标不动或者跳错位置」。你后面遇到问题时先判断卡在哪一环比盲目重启编辑器有用得多。1.3 模板化省下的不只是按键数我自己的体感是snippets 的价值分三层。第一层是省时间这是最容易感知的但通常也是最不值钱的一层。省下的那几百次按键累计起来可能一天也就十几分钟。第二层是降低认知切换成本。写惯了一种结构之后大脑会自动把「新建一个组件」这件事打包成一个动作。如果你每次都要从零回忆「这个项目里 props 是写在 setup 前面还是后面」那这个切换成本是持续的。模板把这段决策固化了你的注意力可以全部放在业务逻辑上。第三层是统一团队代码风格这一层价值最大也最容易被忽略。当log在所有人的编辑器里都展开成同一套日志格式、apicall都展开成同一种错误处理结构时代码评审里关于「这里写法不一致」的讨论会显著减少。这部分收益不用等到项目结束第一周的 PR 就能看出来。2. 手写一个 snippet把 JSON 结构逐字段拆开看2.1 prefix、body、description 各自的职责边界VSCode 的 snippet 定义就是一个 JSON 对象外层 key 是这个 snippet 的名字只在配置界面里显示内层三个字段各自有明确分工。{ Log to console: { prefix: log, body: [ console.log($1);, $0 ], description: 输出一行日志到控制台 } }prefix是触发词可以写成数组比如[log, clog, consolelog]这样一个模板能用多个入口唤出来。我个人的建议是不要贪多同一模板给两三个前缀就够给太多会污染建议列表反而降低筛选效率。body是真正的内容支持字符串和数组两种写法。数组写法每一行是一个元素可读性好得多而且不用担心换行符和缩进转义的问题。只要模板超过两行就老老实实用数组这是我踩过几次坑之后的固定做法。description会显示在建议列表右侧写清楚它的用途团队共享时能省掉大量沟通。2.2 tabstop 与占位符$1、$0、${1:默认值} 的行为差异这是 snippets 里最容易写错、也最值得花十分钟搞明白的部分。$1、$2、$3是光标停留点按编号顺序跳转。同一个编号出现多次时它们会联动编辑——你在第一个位置输入什么其他同编号位置同步变化。这个特性非常有用比如生成一对同名的变量和函数。$0是最终光标位置不参与编号顺序永远在最后。如果省略$0光标会停在模板末尾。${1:默认内容}是带默认值的占位符展开后默认内容被选中你直接输入就替换掉按 Tab 保留默认值。${1|红色,蓝色,绿色|}是可选项占位符展开时给一个下拉列表让你选。举个实际例子写一个 Vue 3 组件的骨架{ Vue 3 SFC skeleton: { prefix: v3s, body: [ template, div class\${1:container}\, $0, /div, /template, , script setup lang\ts\, const props defineProps{, ${2:title}: ${3:string}, }(), , /script, , style scoped lang\scss\, .${1:container} {, }, /style ], description: Vue 3 单文件组件骨架 } }注意这里$1用了两次一次在模板的 class 名一次在样式选择器里。你展开后输入card两处同时变成card这就是联动编辑的实用价值所在。这类写法在很多 Vue 3 snippets 扩展包里也能看到但自己写一遍才知道它为什么这样组织。2.3 内置变量TM_ 系列、时间、剪贴板与随机值内置变量是 snippets 真正拉开差距的地方。常用的有这么几类变量含义典型用途TM_FILENAME当前文件名含扩展名生成文件头注释TM_FILENAME_BASE当前文件名不含扩展名生成同名类名或测试名TM_DIRECTORY当前文件所在目录的绝对路径调试信息、模块路径TM_FILEPATH当前文件完整路径生成__FILE__类信息RELATIVE_FILEPATH相对工作区根目录的路径日志定位、文档链接WORKSPACE_NAME当前工作区名称多仓库场景下的标识CURRENT_YEAR等年月日时分秒版权头、变更记录CURRENT_DAY_NAME星期几变更记录LINE_COMMENT当前语言的行注释符号跨语言通用注释模板BLOCK_COMMENT_START/_END块注释符号跨语言文档注释CLIPBOARD系统剪贴板内容粘贴路径、URL 做注释RANDOM/RANDOM_HEX随机字符串生成临时 IDUUID一个 UUID v4需要唯一标识的场合LINE_COMMENT这个变量特别值得说一句。它会让你的注释模板变成跨语言通用的同一份 snippet在 Python 里展开成#在 C 里展开成//在 SQL 里展开成--。我现在的文件头模板就是靠它做的一份定义在七八种语言里都能用。写一个我实际在用的文件头模板{ File header: { prefix: fhdr, body: [ $LINE_COMMENT ${TM_FILENAME_BASE}, $LINE_COMMENT, $LINE_COMMENT Created: $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE, $LINE_COMMENT Author: $1, $LINE_COMMENT, $0 ], description: 插入文件头注释 } }这个模板我放在用户级通用位置不绑定具体语言Python、C、Shell 里都能直接fhdr Tab 展开。2.4 转义$、}和反斜杠在 JSON 里的双重身份这部分是新手最容易翻车的地方因为你在处理两层转义。第一层是JSON 自身的转义JSON 字符串里的双引号必须写成\反斜杠必须写成\\。所以如果你的模板内容里有一个正则\d在 JSON 里要写成\\d。第二层是snippet 语法的转义如果你想在模板里输出一个字面量$而不是变量必须写\$。想输出字面量}写\}。把两层叠起来就会出现很反直觉的写法。比如你想生成一段 Shell 脚本里面有个$HOME{ shell home: { prefix: shome, body: [echo \\\$HOME \\$HOME\] } }第一次写的时候我盯着这行看了半天。理解方式很简单先按 snippet 规则处理\$变成字面$剩下的\交给 JSON 解析器处理。写复杂模板时我的建议是先在一个空文件里手写出你想要的最终结果然后倒推着加转义比正向硬想快得多。3. snippet 放哪儿作用域、优先级与拆分策略3.1 三个层级的落盘路径VSCode 的 snippet 有明确的层级选错位置会出现「在我电脑上能用、同事那边没有」这类问题。层级存放位置适用范围用户级 · 语言专属用户目录下snippets/language.json所有项目中的该语言文件用户级 · 通用用户目录下snippets/*.code-snippets所有项目、所有语言工作区级项目内.vscode/*.code-snippets仅当前项目插件自带扩展安装目录取决于插件声明用户目录的位置按系统区分Windows 在%APPDATA%\Code\User\macOS 在~/Library/Application Support/Code/User/Linux 在~/.config/Code/User/。最省事的入口不是手动找路径而是按CtrlShiftPmacOS 是CmdShiftP输入Snippets选「配置用户代码片段」编辑器会弹出语言列表让你点。选一项它自动建好文件并打开。工作区级的同理选「新建全局代码片段文件」或用项目里的.vscode目录手工建文件都行。3.2 同名 prefix 撞车的时候谁赢这是个很实际的问题。你装了一个 Vue 3 snippets 插件自己又写了一个v3s插件里恰好也有v3s那按下去会出哪一个VSCode 的处理方式是把所有匹配的候选都列在建议列表里顺序上更具体的作用域排得更靠前——工作区级优先级高于用户级用户级语言专属高于用户级通用。但要注意这个排序规则在版本迭代中有过调整所以在依赖顺序做事之前最稳妥的办法是实测一次把两个同名 snippet 都定义好展开看看谁在前面。如果确实撞车处理方式有三种改自己的prefix加个团队前缀比如x-v3s直接覆盖插件的行为把插件里那个 snippet 的 key 抄过来改 body因为同名 key 会覆盖禁用插件的 snippet 贡献如果插件支持单独关闭的话。我一般选第一种代价最小也最容易维护。3.3 什么情况下值得把 snippet 拆成 .code-snippets 独立文件.json结尾的是早期格式一个文件对应一种语言文件名就是语言 ID。.code-snippets结尾的是后来引入的格式一个文件里可以混放多种语言的 snippet靠每个条目里的scope字段来限定。{ API handler: { scope: typescript,javascript, prefix: apih, body: [ export async function ${1:handlerName}(req, res) {, try {, $0, } catch (err) {, res.status(500).json({ message: err.message }), }, } ] } }我判断是否拆分的标准很简单这份模板需不需要跨语言复用或者需不需要跟项目走。跨语言复用就写.code-snippets放用户级项目专属就写.code-snippets放.vscode目录跟着仓库一起提交。单语言、纯个人的小模板用语言专属.json就够了不用折腾。值得一提的是项目内的.vscode/*.code-snippets会随代码库分发新同事拉下代码就自动有了这套模板。这是团队统一模板最轻量的落地方式比写文档、发配置文件都省事。4. 让模板会「加工」正则转换、条件插入与嵌套调用4.1 转换语法${1/regex/format/options}逐段解释基础占位符只能替换转换语法能让模板对输入内容做加工。完整形式是${变量或占位符/匹配正则/替换格式/选项}四个部分逐个说清楚第一个斜杠前被处理的源。既可以是编号占位符$1也可以是内置变量TM_FILENAME。中间的正则用来捕获源里的片段用括号分组分组在替换格式里用$1、$2引用。注意这里的$1指的是正则捕获组和上面的 tabstop 编号是两套东西容易看混。替换格式可以是纯文本也可以用${1:/upcase}形式的大小写转换。选项i忽略大小写g全局匹配m多行模式。一个真实用例——把文件名转成驼峰命名用来生成类名或函数名{ Filename to camelCase: { prefix: fnc, body: [const ${TM_FILENAME_BASE/(.*)/${1:/camelcase}/} $0] } }假设当前文件叫user-profile.ts展开后得到const userProfile 。这一招我在写测试文件时用得最多测试文件名和被测对象名之间就靠它建立关联。支持的格式修饰符有upcase、downcase、capitalize、camelcase、pascalcase、snakecase、kebabcase覆盖了绝大多数命名风格转换需求。需要注意一个坑正则里的反斜杠在 JSON 里要写成双份。如果你想匹配点号.正则应写\\.而不是\.否则 JSON 解析阶段就会报错或者吞掉字符。我第一次写转换的时候就在这儿卡了快二十分钟。4.2 条件插入可选片段的两种写法有时候模板里有些行是「可有可无」的。条件插入能根据占位符有没有值来决定插不插入。${1:text}如果$1有值就插入text${1:-text}如果$1没有值就插入text。举个实用例子写一个带可选await的调用模板{ Maybe await call: { prefix: maw, body: [ ${1:const data }${2:await }${3:fetchData}(), $0 ] } }如果你在第二个位置填了任意内容await就会出现直接按 Tab 跳过就变成同步调用。这种写法比我早期做的「同步版 异步版两个模板」优雅得多维护成本也更低。我个人的经验是条件插入适合处理一到两个开关型差异。差异超过三个模板的复杂度会急剧上升写出来自己都记不住该怎么填这时候拆成几个模板反而更清楚。4.3 嵌套调用composite snippet 的用法和它的天花板带isFileTemplate: true的 snippet 会被标记为文件模板可以在新建文件时直接套用。而在普通 snippet 的 body 里也可以把一个 snippet 的名字当成变量来引用实现嵌套。{ Component with header: { prefix: cmph, body: [ $LINE_COMMENT ${TM_FILENAME_BASE}, $LINE_COMMENT, import React from react, , export default function ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}() {, return (, div$0/div, ), } ] } }坦白说我在实际项目里很少做深层嵌套。原因很直接嵌套会把调试难度抬高一个量级。展开出来的东西不符合预期时你很难判断是外层模板的问题还是内层模板的问题。我的做法是让每个 snippet 保持「一眼能看完」的体量需要组合的场景用手动连续展开几次而不是把它们焊死在一起。这条经验是我在维护一个包含二十多个互相引用的模板集合之后总结出来的。那个集合最后的结局是被整体重写拆成了十几个互不依赖的小模板。5. 从个人快捷键到团队资产命名、版本化与淘汰5.1 把 prefix 当成 API 来设计一旦 snippet 要分享给同事用prefix的命名就不再是个人喜好的问题而是接口设计问题。我踩过的坑是早期用了t、c、d这种单字母前缀结果和编辑器自带的补全、语言服务的缩写严重冲突按下去经常出不来我想要的东西。现在我的命名规则大致是两到四个字符太短容易冲突太长影响输入效率语义可猜看到apih能猜到是 API handler看到v3s能猜到是 Vue 3 骨架加语义化前缀区分来源团队规范相关的统一加某个字母开头避免和插件市场装的包撞车不用纯数字和特殊符号虽然语法上允许但输入体验很差。一个具体的小技巧前缀里尽量包含一个不常见的字母组合。比如clg比log更好因为log在很多人项目里是一个真实存在的变量名你打字打一半它就跳出来干扰你甚至可能在你想要那个变量的时候给你展开模板。5.2 用工作区文件承载项目专属模板个人模板和工作模板要分开放。我的分层是这样的内容类型存放位置例子跨语言通用用户级.code-snippets文件头注释、TODO 标记语言通用用户级语言.jsonPython 的try/except骨架项目专属项目.vscode/*.code-snippets内部 API 调用模板、组件骨架临时试验先放用户级稳定后再下沉新增的日志格式模板项目专属模板我基本都会跟着仓库提交。这样做的好处是模板和代码在同一份版本历史里改模板这件事有记录、可追溯、可回滚。比把模板放在共享网盘里让大家手动下载靠谱得多。需要注意的是工作区级的.code-snippets里每个条目要显式写明scope否则它会对所有语言生效。我就干过忘记写scope结果在 YAML 文件里敲apih也展开出一段 TypeScript 代码的蠢事。5.3 模板的评审与淘汰机制模板最大的风险不是不够多而是悄悄过期。项目用的框架升级了、内部的 API 封装改名了、日志规范调整了但模板还是老样子下发给所有人那它就从提效工具变成了污染源。我现在的做法是给模板加一道轻量的维护机制每份模板的description里写清适用范围和最后更新意图比如「适用于 v2 接口层v3 迁移后作废」在季度回顾时清一遍把半年内没人用或者已经过期的删掉新模板先由一个人用一个月稳定了再进工作区文件改动模板走普通 PR 流程让它和其他代码改动一样接受评审。这套做法看起来有点重但实际操作起来成本很低——毕竟模板改动一年也就那么几次。真正省下的是「有人用着过期模板写出不符合规范的代码然后在评审时被退回」这件事带来的额外往返。6. snippet 不生效、乱弹出、展开错位一条完整排查链路6.1 第一步永远先确认语言 ID这是最高频的原因没有之一。VSCode 认的是语言 ID不是文件后缀。你建了个文件叫foo.tsx但如果编辑器右下角显示的是Plain Text那所有 TypeScript 相关的 snippet 都不会出现在建议列表里。同理.vue文件如果没装对应的语言支持它可能被识别成 HTML 而不是 Vue。排查动作很简单看编辑器状态栏右下角的语言标识点一下能切换。如果这里不对后面所有排查都是白费力气。还有一个容易忽略的情况.code-snippets文件里scope写的是typescript但你的文件被识别成typescriptreact。这两个是不同的语言 ID。我见过不少人在这里反复折腾其实只要把scope改成typescript,typescriptreact就解决了。6.2 JSON 语法错误与转义问题的定位snippet 文件是 JSON但 VSCode 对它的容错比较宽松——有些错误它不报只是默默让这个文件的部分或全部条目失效。这就是「我明明写了但就是不出现」的常见原因。定位顺序看文件里有没有红色的波浪线有就先解决检查最外层是不是一个合法的对象逗号有没有多写或漏写最后一项后面不能有逗号检查每个 snippet 的内层对象prefix、body、description之外的多余字段虽然不报错但也没用检查字符串里的双引号有没有转义路径里的反斜杠有没有写成双份检查body数组里每一行是否都是合法字符串换行是不是被误写成了真实换行符。如果这些都看不出来我的土办法是把可疑条目单独复制到一个新建的 snippet 文件里测试。如果单独放能用说明是文件里其他条目的语法有问题如果单独放也不能用那就是这个条目自身的问题。二分法排查比一行行盯快得多。6.3 和补全源抢触发词症状是你输入前缀建议列表出来了但第一个不是你的 snippet得往下翻好几条才能找到。或者更糟——列表里压根没有被别的补全结果挤掉了。原因通常有三类前缀和真实变量名、函数名冲突语言服务把它当成已有符号优先推荐装了多个 snippet 扩展前缀撞车AI 补全插件的建议权重更高把 snippet 压下去了。处理手段有两个方向。一是改前缀用更独特的组合这是一劳永逸的做法。二是调整建议列表的排序策略在设置里搜snippetSuggestions可以设成top让 snippet 排在前面、bottom沉底、inline混排、none完全不显示。我一般设成top因为能被我自己定义成 snippet 的东西基本就是我确定要优先用的。另外还有一个设置值得知道editor.tabCompletion。把它设成onlySnippets或on之后你可以不经过建议列表直接按 Tab 展开匹配的 snippet。这个方式在你不确定建议列表会不会干扰的时候特别好用缺点是容易误触需要适应一段时间。6.4 建议列表里没有但 Tab 能展开这个现象很有意思说明你的 snippet 是有效的、语言 ID 也没错问题出在建议列表的过滤上。常见原因是前缀里有特殊字符或者你在设置里打开了某些过滤选项导致建议列表的模糊匹配没把它算进来。比如某些配置下建议列表对大小写和特殊符号的处理比较严格。还有一种情况是 snippet 的body为空数组或空字符串它不会报错但展开出来什么都没有看起来就像「没生效」。6.5 远程 SSH、WSL、容器下的差异现在很多人在远程开发模式或者 WSL 里写代码这里有个关键点一定要记住用户级 snippet 读的是你连上去的那一端的环境路径不是本地机器。也就是说你本地编辑器的用户目录在哪儿和远端机器上的用户目录在哪儿是两个不同的位置。如果你在本地配了一堆 snippet连上远端服务器后一个都没有不要怀疑编辑器坏了就是位置的问题。解决方式有两种看你的使用习惯远端机器单独配一份适合长期连同一台机器的情况把项目相关的模板全放进项目内的.vscode目录这样它跟着代码库走无论本地还是远端、无论谁拉下来都能用这也是我更推荐的方式。WSL 场景下还有一个细节Windows 侧的用户目录和 WSL 内的用户目录也是分开的。如果你在 Windows 里的 VSCode 打开 WSL 里的文件snippet 的加载取决于窗口是用哪种模式打开的。这个差异不太好用文字描述清楚实测一次看效果最直接。7. 哪些代码不该做成模板7.1 会持续演进的业务逻辑snippet 最大的误用是把还在演进的业务逻辑固化下来。判断标准很清晰如果这段代码未来三个月内会因为需求变化而修改就不要做成模板。比如某个接口的请求参数结构、某个页面的表单校验规则、某段状态机的流转逻辑。这些东西正在变化中做成模板等于把「过时的写法」批量复制到项目各处。我见过比较典型的反面案例是有人把一个三行就能写完的组件定义做成了二十行的模板里面包含了当时的 props 默认值、当时的样式变量命名、当时的埋点调用。半年后这些东西全变了模板还在新人用它生成组件然后每一处都要手改回来。我自己的筛选标准是——这段代码我连续三个月、在至少五个不同文件里写过几乎一模一样的版本才考虑做成模板。这个门槛拦掉了很多冲动型的模板化需求。7.2 snippet 和 AI 补全、LSP 的分工现在的开发环境里这三种能力是共存的搞清楚分工比争论谁更好用实际得多。语言服务负责语义层面的事符号跳转、类型检查、重命名重构、参数提示。这些事 snippet 和 AI 都做不了遇到「无法跳转到定义」这类问题方向是检查语言服务配置、编译参数、项目索引是否正常而不是去翻 snippet 配置。snippet 负责确定性结构结构固定、写法统一、几乎不随业务变化的骨架。它的核心价值是「确定」你按下去就知道会得到什么。AI 补全负责探索性内容写一个没见过的算法、翻译一段逻辑、生成一批测试数据的变体。它的核心价值是「跳跃」你按下去可能得到惊喜也可能得到垃圾。我的实际组合方式是项目脚手架和固定骨架用 snippet 打底中间的业务逻辑用语言服务补全和 AI 交替推进。三者不冲突它们在不同的抽象层级上工作。在选择编辑器扩展时也要注意区分。插件市场里那些自动闭合标签、自动重命名配对标签的插件属于编辑辅助行为跟 snippets 是两回事——它们不需要你定义前缀是直接作用在你输入过程中的。如果你遇到的问题是「标签没有自动闭合」那该找的是这类插件而不是 snippet 配置。我在实际使用中的几点体会写到最后说几个我摸索了很久才想明白的点。不要在第一天就把模板库做得很全。我最早的一版模板集合有四十多个条目三个月后真正还在用的不到十个。先攒痛点再用模板解决而不是先建模板库再找地方用。我现在习惯是在正常写代码时如果同一个结构一天内手打了三次以上才停下来花两分钟加一个 snippet。description一定要写哪怕你觉得这个模板只有自己用。半年后你看到那个xyz前缀真的想不起来它是干嘛的。写一句「生成带重试的 HTTP 请求封装」未来能省下你翻文件查看的时间。最后是一个小技巧想把一段已经写好的代码变成 snippet不用手打。选中那段代码按CtrlShiftPmacOS 是CmdShiftP输入Insert Snippet再选「新建代码片段」编辑器会帮你把选中内容预填进模板结构里你只需要补上prefix和description。这个路径比从空文件开始写快很多尤其适合处理那些结构复杂、缩进敏感的多行模板。
返回列表