十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Windows Terminal Snippets:用 .wt.json 和 wt x-save 实现可分享、可发现的命令片段

Windows Terminal Snippets:用 .wt.json 和 wt x-save 实现可分享、可发现的命令片段 Windows Terminal Snippets用 .wt.json 和 wt x-save 实现可分享、可发现的命令片段【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminalWindows Terminal 的 Snippets曾用名 Tasks特性让长命令不必再靠记忆或散落在.bashrc、OneNote、shell 脚本里它们可以被统一存储、按意图检索、随项目分享给整个团队。本文基于仓库中的规格文档 doc/specs/#1595 - Suggestions UI/Snippets.md 展开完整覆盖sendInput多行输入扩展、.wt.json项目级片段文件、wt x-save命令行保存语法与安全设计并结合 AppCommandlineArgs.cpp、ActionArgs.idl 等源码印证各设计在仓库中的落地情况帮助你从零搭建一套可复用的团队命令库。![使用 wt 保存命令后通过 Suggestions UI 调用片段的原型演示](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_sourcegitcode_repo_files#1595 - Suggestions UI/img/save-command.gif)动机为什么不用 alias 或脚本文件规格文档在 Background 一节给出了完整论证。命令行强大的前提是使用者记住具体命令、flag 与参数对长命令或不常用的命令回忆精确语法的心理开销很大而团队内部又需要共享这些任务。文档提出用想做什么what do I want to do取代怎么做how do I do it的检索方式。相比传统方案Alias/脚本的老问题即使用户创建了 alias 或.ps1/.bat/.sh脚本仍要记住我创建过它、它存在哪、它怎么用。Snippets 的差异提供一个专属 UI 让命令始终触手可及不需要回忆 alias 名只需检索想做的事。命令不再散落在.bashrc、.bash_profile、.profile各处而是统一存放在 Terminal 配置或相关项目的旁边——任何人接手代码库都能立即获得可用任务集。跨 shell 且面向新手alias 倾向服务于资深 shell 用户Snippets 通过 fragment 扩展机制让工具可以随应用捆绑常见工作流Terminal 可自动加载即使是新手也能直接使用。灵感来源上规格文档追溯到了作者早年写的#keep用数字召回暂存的长命令与目录、iTerm2 的 Command History 菜单、VsCode Tasks工作区根目录共享任务文件、运行时可挑选参数以及 Warp 的 workflows 与 Fig 的自动补全生态——整个生态对更可发现的命令行工具存在普遍需求。核心实现基于 sendInput 动作规格文档 Implementation Details 的开宗明义是这部分绝大部分已经以sendInput动作实现——sendInput本来就会向终端发送文本天然适合作为 snippet 的载体。在此之上规划了三处增强input支持字符串数组当input是字符串列表时Terminal 依次发送每个字符串中间以Enter分隔从而支持多行脚本waitForSuccess参数默认false设为true且启用 shell integration时Terminal 会等待上一条命令退出后再发送下一条description属性为 Command 增加描述字段供菜单展示扩展作者也可提供更详细信息。此外还有一个命名调整SuggestionsSource枚举中的source: tasks更名为snippets出现旧值时优雅迁移tasks 是该特性的早期名称改用 snippets 可与 VsCode 侧的命名对齐。多行 snippet 示例文档用一个真实脚本演示问题一段 PowerShell 同步 issue/bug 到项目看板的脚本。若作为单个input字符串写入sendInput由于 JSON 不支持多行字符串每一行都要用\r\n拼成一行{ command: { action: sendInput, input: $sInvoke-GitHubGraphQlApi \query{organization(login:\Microsoft\){projectV2(number: 159) { id } } }\\r\n$tasks get-GitHubIssue -Labels \Issue-Task\ -state open\r\n$bugs get-GitHubIssue -Labels \Issue-Bug\ -state open\r\n$issues $tasks $bugs\r\n$issues | ? {$_.labels.Name -NotContains \Needs-Triage\ } | ? { $_.milestone.title -Ne \Icebox ❄\ } | ? type -Ne \PullRequest\ | select -expand node_id | % {\r\n $resp Add-GitHubBetaProjectItem -ProjectNodeId $s.organization.projectV2.id -ContentNodeId $_ ;\r\n} }, name: Upload to project board, description: Sync all our issues and bugs that have been triaged and are actually on the backlog to the big-ol project }这份 JSON 基本完全不可用。改用字符串数组后每个字符串按序发送、中间插入Enter{ command: { action: sendInput, input: [ $sInvoke-GitHubGraphQlApi \query{organization(login:\Microsoft\){projectV2(number: 159) { id } } }\, $tasks get-GitHubIssue -Labels \Issue-Task\ -state open, $bugs get-GitHubIssue -Labels \Issue-Bug\ -state open, $issues $tasks $bugs, $issues | ? {$_.labels.Name -NotContains \Needs-Triage\ } | ? { $_.milestone.title -Ne \Icebox ❄\ } | ? type -Ne \PullRequest\ | select -expand node_id | % {, $resp Add-GitHubBetaProjectItem -ProjectNodeId $s.organization.projectV2.id -ContentNodeId $_ ;, }, ] }, name: Upload to project board, description: Sync all our issues and bugs that have been triaged and are actually on the backlog to the big-ol project }这比单行版本稍微更易维护。再配合 shell integration 设置waitForSuccess: true脚本任一步失败剩余部分就不会继续发送。严格前提脚注 1shell integration 是waitForSuccess生效的硬性要求。没有它Terminal 只会发出脚本第一行然后永远等待FTCS_COMMAND_FINISHED信号脚本就卡死在第一行之后。![从当前工作目录加载 .wt.json 任务并调用的原型演示](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_sourcegitcode_repo_files#1595 - Suggestions UI/img/tasks-from-cwd.gif)Fragment 动作规格文档指出该能力已由 fragment 扩展机制上游 PR #16185支持第三方开发者可以开发应用向 Terminal 注入额外 snippet需为每个动作添加id用户随后可将动作id绑定到键位。文档以 docker/docker-compose 命令系列为例说明这类内容可以直接加入 Terminal。项目级 Snippets 文件.wt.json为了让团队成员共享命令规格文档定义了.wt.json机制Terminal 会自动在 shell CWD 的所有上级目录中查找.wt.json并把其中的动作一并加载。文件语法是标准 settings schema 的简化版示例如下{ $version: 1.0.0, snippets: [ { input: bx, name: Build project, description: Build the project in the CWD }, { input: bcz, name: Clean build solution, icon: \uE8e6, description: Start over. Go get your coffee. }, { input: nuget push -ApiKey az -source TerminalDependencies %userprofile%\\Downloads, name: Upload package to nuget feed, icon: \uE898, description: Go download a .nupkg, put it in ~/Downloads, and use this to push to our private feed. } ] }Schema 要点顶层键是snippets而非actions每个 snippet 对象是Command的简化体拥有与Command相同的name、description、icon属性但没有任意action而是直接内嵌sendInput动作的参数如input作为属性支持$version字段以便未来破坏性变更缺省时假定版本为1.0.0即本规格最初提案的 schema。CWD 解析、缓存与目录分层文档给出了一组明确的运行时规则值得逐条对照实现默认 CWD 来源TermControl初始化时 CWD 总会被设为所属 profile 的startingDirectory。因此即使用户没启用 shell integrationTerminal 也能从 profile 的startingDirectory加载.wt.json若 shell integration 配置了 CWD 上报则用户切换目录时列表会随之刷新。缓存 map在Terminal.Settings.Model中缓存 path→actions 映射避免同一 CWD 下的多个 pane 重复读盘重建。懒加载CWD 变化时不需要控件主动发事件等 UISuggestions UI / Snippets pane首次请求时才按需加载。多级.wt.json分层若 CWD 的祖先链上存在多个.wt.json例如c:\a\b\c\d\下同时存在c:\a\.wt.json与c:\a\b\c\.wt.json每个都会分别加入 path→actions 映射实际取用 CWD 的动作时深层目录的同名 snippet 优先于浅层——例如浅层定义input: foo, name: Build、深层定义input: bar, name: Build用户位于c:\a\b\c下选中Build时得到bar位于c:\a下则得到foo。解析失败策略解析.wt.json失败时直接忽略该文件但要向用户显示警告——打开 Suggestions UI 时以 Toast 提示首次加载失败Snippets pane 顶部可显示静态文本failed to parse snippets found inpath/to/file。键位绑定与安全隔离文档中两条关于键位绑定的设计值得特别注意本地 snippet 不可被键位绑定。即便.wt.json中的动作带 ID构建键位映射keymap时该文件尚未加载且无人希望键位映射随 CWD 变化。本地动作存放在独立的 CWD→actions 映射中主 keymap 也无法轻易触达它们。本地 snippet 不进入 Command Palette。sendInput动作在 settings 文件与 fragment 中仍会进入 Command Palette但本地 snippet 不会——因为 Command Palette 与自有 ActionMap 设置模型defaults、fragments、用户设置层层叠加紧耦合运行时不易变更而 Suggestions UI 与 Snippets pane 更擅长处理与TermControl相关的上下文动作且能同时按Name和Input过滤Command Palette 目前只能按名字过滤。安全一节Security considerations进一步解释了禁止惰性绑定键位的深层原因malicious.exe完全可以在%HomePath%创建.wt.json写一个 snippet 内容为\u003pwn-your-machine.exe\r任何应用都能读你的 settings 文件恶意应用也可以把自己的动作id设置为与某个你已绑键的善意本地 snippet 相同的 ID。对应的缓解措施是首次从.wt.json加载 snippet 时询问用户是否信任该目录类似 VsCode 的工作区信任机制接受后把该目录加入state.json永久保存的信任列表否则忽略该文件对话框中还提供信任父目录勾选框并且要与安全团队合作确认解析不可信 JSON 所需的额外措施。从命令行保存 Snippetswt x-save规格文档描述的工作流是刚跑通的命令应该能一键存下来——按Up、Home输入wt x-save回车不必打开设置手工复制粘贴。底层由saveSnippet动作驱动但不从用户 settings 文件中解析该动作在设置文件里放一个保存 snippet 到设置文件的动作本身就不合逻辑。x-save 子命令语法x-save [--name,-n name][--description,-d description][-- commandline]把给定命令行作为sendInput动作保存到 Terminal 设置文件立即写入 settings 文件。参数参数说明--name,-n name为保存的命令指定name。省略时留空菜单中显示自动生成的 Send input:... 名称--description,-d description可选为命令指定描述commandline要保存为sendInput动作input的命令行窗口行为单独运行save子命令时Terminal 隐含-w 0参数把动作发送到当前窗口除非命令行手动指定了-w避免弹出一个新窗口只为告知命令已保存与其他子命令一起运行时动作就在执行这些子命令的同一窗口中运行。实验性状态文档中明确团队讨论后决定先按实验性experimental接受主要顾虑是字符串转义的奇怪边缘场景太多故命名为x-savex-前缀即实验性之意将来若增加保存 snippet 的对话框再将其转正。源码印证x-save 在仓库中的实现规格描述与当前仓库代码可以互相印证。AppCommandlineArgs.cpp 中的_buildSaveSnippetParser()确实注册了名为x-save的子命令资源字符串SaveSnippetDesc为 Save command line as input action选项包括--name,-n、--keychord,-k与位置参数command,即命令行正文并通过positionals_at_end(true)保证--之后的参数按序归入命令行解析回调构造出ShortcutAction::SaveSnippet动作与SaveSnippetArgs其中含空格的参数项会被引号包裹后拼接避免保存时语义走样。单独 x-save 不弹新窗口的行为同样有对应实现ValidateStartupCommands()AppCommandlineArgs.cpp检测到_startupActions仅含一条SaveSnippet且未指定窗口目标时把_windowTarget设为0把动作导向当前窗口并跳过自动插入 NewTab 逻辑。动作参数模型定义在 ActionArgs.idl[default_interface] runtimeclass SaveSnippetArgs : IActionArgs, IActionArgsDescriptorAccess { SaveSnippetArgs(); SaveSnippetArgs(String Name, String Commandline, String KeyChord); String Name; String Commandline; String KeyChord; }可以看出实现比规格文档更进一步除了Name与Commandline还带了KeyChord与x-save的--keychord,-k选项对应用于保存时直接指定键位。处理入口在 AppActionHandlers.cpp 的TerminalPage::_HandleSaveSnippet并受Feature_SaveSnippet特性开关保护。Snippets pane独立的浏览面板规格文档规划了一个新的 pane 类型type: snippets非终端内容能力随 1.21 Preview 落地后添加新 pane 类型变得简单。设计要点pane 内部是一个TreeView加一个过滤文本框类 Command Palette 体验每个 TreeView 条目是FilteredCommand带一个播放按钮点击即快速执行该命令可支持 Suggestions UI 的各类建议源如把recentCommands从当前活动控件接入并提供复选框过滤不同建议源。该 pane 在当前仓库中已有对应实现痕迹defaults.json 中内置了动作Terminal.OpenSnippetsPanesplitPane且type: snippets并且 TerminalApp 工程包含 SnippetsPaneContent.h、SnippetsPaneContent.cpp 与 SnippetsPaneContent.xaml 源文件说明 pane 的 UI 骨架已在代码库中成形。UI/UX 设计展示层面主要复用 Suggestions UI——一个相对文本光标的 UI 表面能在用户工作上下文中快速呈现动作。文档以 VsCode Tasks 与 Warp workflows 作为这类菜单在业界已有的样子的参照![VS Code tasks 演示](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_sourcegitcode_repo_files#1595 - Suggestions UI/img/vscode-tasks-000.gif)![Warp workflows 演示](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_sourcegitcode_repo_files#1595 - Suggestions UI/img/warp-workflows-000.gif)文档还附了两段原型演示wt save foo bar --baz保存命令后经 Suggestions UI 调用的流程见文首配图以及从 CWD 读取任务的流程见多行 snippet 小节配图。设计权衡Tenets规格文档用一张表记录了各维度的权衡核心内容维度结论兼容性曾考虑为.wt.json支持 YAML因为 JSON 对命令行不友好tab\t、换行\r、转义字符还好引号转义在 JSON 中配合各 CLI 工具各自的引号解析规则会变得很快失控但支持 YAML 需要定义一套 YAML 语法并引入、实现 OSS YAML 解析器成本远高于 JSON最终选 JSON可访问性无特别项Snippets pane 需与其他 UI 表面一样进行 a11y 测试可持续性无显著环境影响不使用昂贵计算资源本地化担忧社区贡献的 snippet 描述无法本地化未来或需支持description: { en-us: , pt-br: , ... }的语言映射暂列为未来事项安全见上文键位绑定与安全隔离一节禁止本地 snippet 惰性绑键、目录信任对话框、state.json持久化信任列表、与安全团队复核不可信 JSON 解析已知限制与其他潜在问题重定向陷阱wt save ping 8.8.8.8 foo.txt不会按用户期望工作——shell 会先解析命令行把wt的输出重定向到foo.txt而不是把整条命令当作参数保存。远程连接本地 snippet 在 ssh 等远程连接下不可用Terminal 只能读取本地文件系统至多能读取用户 ssh 出发前所在目录的 snippet。实施计划与未来展望文档按 Crawl/Walk/Run 划分路线图其中 ✅ Done 的用户故事 A/B/H 即从菜单快速执行任务、fragment 可向用户设置提供任务、按已输入文本过滤 snippet。当前仓库中可确认的已落地部分Suggestions UI含片段源已实现、fragment 可向用户设置注入动作、Snippets pane 骨架代码存在、x-save命令行已实现并由特性开关控制。文档 Conclusion 指出与用户交流后所有人都能立刻理解 snippet 的价值。Future Considerations 罗列了后续方向save子命令增加保存位置参数--local存入 CWD 的.wt.json没有则创建、--parent存入最近的祖先目录、--settings手动存入 settings 文件、--profile可能借助WT_SESSION_ID环境变量定位 pane 所属 profile但依赖尚未充分设计的 per-profile actions团队讨论后认为--local/--parent/--settings反响良好也许现在就做长工作流更适合以 notebook 形态暴露与 markdown notebook 体验合流因为长脚本需要在命令间穿插富文本标注兼容 Warp 的 workflows YAML 语法仓库附带 dump-workflows.py脚注 2 所指脚本可将 Warp workflow YAML 转换为 Terminal 可加载的 JSON非常直接这些命令以 Apache 2.0 许可发布可被其他开源项目消费可发现性Actions 页可加只显示 snippets的开关与wt save提示文本启用 shell integration 后可把Save command as snippet放入 prompt 旁的 quick fix 菜单终端内直接保存 snippet 的对话框输入命令行、名称、描述Snippets pane 上加 Add new 按钮wt save可改为打开预填好的对话框甚至用 shell integration 的最近命令预填schema v2.0 可参考.vscode/tasks.json支持更复杂的任务定义运行时向用户提示不同参数取值与可提示输入段prompt-able sections方向合流未来可加shell属性声明 snippet 适用的 shell从而按当前 shell 过滤暂缓原因目前没有可靠方式知道用户当前运行的 shell 应用未来可考虑把sendInput动作提升为 settings.json 顶层snippets数组便于在用户设置与.wt.json之间互相迁移社区 Snippets最大的 stretch 目标在公共仓库仿 winget-pkgs 模式托管社区维护的 snippet 列表Terminal 自动拉取最新社区命令可直接作为另一个 suggestion source.wt.json中的 Profiles既然目录里已有.wt.json是否也该动态增删 profile例如 Terminal 仓库自身的 PowerShell 构建环境与 CMD 构建环境各放一个 profile文档坦承语义尚未想清楚可能与 Dev Home 方向结合或作为 winget DSC 创建 fragment profile。小结Snippets 特性的完整拼图是以sendInput动作为执行底座支持字符串数组多行发送与waitForSuccess条件续发、以.wt.json为团队共享载体含目录分层覆盖、缓存、信任机制与安全隔离、以wt x-save为刚跑通就保存的快捷入口实验性前缀x-如实反映转义边缘场景的未决风险、以 Suggestions UI 与 Snippets pane 为两种互补的呈现面前者上下文感知且可按 NameInput 双字段过滤后者是独立的 TreeView 浏览面板。文档中每条设计都给出了取舍理由YAML vs JSON、为什么不进 Command Palette、为什么禁止本地动作绑键源码中x-save的完整解析链AppCommandlineArgs.cpp → ActionArgs.idl 的SaveSnippetArgs→ AppActionHandlers.cpp 的_HandleSaveSnippet与 Snippets pane 源文件的存在印证了这份规格并非停留在纸面而是与仓库实现持续对齐的活文档。【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表