尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

PowerToys Run URI 插件深度解析:如何解析、解析校验并排序用户输入的 URI

发布时间:2026/9/7 19:30:38

资讯中心
01
ARTICLE

PowerToys Run URI 插件深度解析:如何解析、解析校验并排序用户输入的 URI

PowerToys Run URI 插件深度解析:如何解析、解析校验并排序用户输入的 URI
PowerToys Run URI 插件深度解析如何解析、解析校验并排序用户输入的 URI【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys本文以 PowerToys 仓库中 URI 插件的开发者文档 为主体结合Microsoft.Plugin.Uri插件的实际源码完整讲解 PowerToys Run原 PowerToys Run中 URI 插件的工作机制它如何把用户键入的文本解析为 Web URI 或系统 URI、如何通过 URI Resolver 校验主机、为何结果图标是默认浏览器图标以及评分为 0 的结果是如何排在其他插件之后的。读完本文你可以准确复述该插件的解析分支与判定规则并能基于IUriParser/IUrlResolver接口理解其可扩展点。一、插件定位把输入的 URI 直接当作查询执行URI Plugin 的作用与名字一致直接把用户输入的 URI 作为查询执行——先解析输入、校验 URI然后执行打开它。从 plugin.json 可以看到该插件的注册信息{ ID: 03276A39D4E9417C8FFD200B0EE5E871, ActionKeyword: //, IsGlobal: true, Name: Windows Uri Handler, Author: Microsoft, Version: 1.0.0, Language: csharp, Website: https://aka.ms/PowerToys, ExecuteFileName: Microsoft.Plugin.Uri.dll, IcoPathDark: Images\\uri.dark.png, IcoPathLight: Images\\uri.light.png }这里有几个关键点ActionKeyword为//用户输入//加 URI 可以强制调用该插件IsGlobal为 true即使用户不带关键词该插件也会参与全局查询的结果聚合IcoPathDark/IcoPathLight插件自带的深/浅色图标对应 Images/uri.dark.png 等文件用于系统 URI非网页结果。插件入口类Main实现了IPlugin, IPluginI18n, IContextMenu, ISavable, IReloadable, IDisposable接口见 Main.cs构造时即创建三个核心协作对象ExtendedUriParser解析器、UriResolver校验器和PluginJsonStorageUriSettings设置持久化。除文档描述的“解析 → 校验 → 执行”主路径外Main.cs 的 Query 方法 还包含一个源码可确认的补充行为当查询为空且系统已设置默认浏览器时BrowserInfo.IsDefaultBrowserSet插件会返回一条“打开默认浏览器”的结果副标题显示浏览器可执行文件路径执行时通过Helper.OpenInShell(BrowserInfo.Path)启动浏览器见 Main.cs#L53-L74。若打开失败会通过Context.API.ShowMsg弹出错误提示。二、URI ParserExtendedUriParser 的解析分支文档指出ExtendedUriParser.cs 负责解析用户输入并借助UriBuilder返回System.Uri结果同时覆盖UriBuilder不处理的场景如输入以:、.或:/结尾的情况。其对外契约由 IUriParser 接口 定义public interface IUriParser { bool TryParse(string input, out System.Uri webUri, out System.Uri systemUri); }注意这里同时输出webUri与systemUri两个结果前者是规范化后的网页地址后者是保留原样方案scheme的系统 URI如tel:、mailto:、ms-*等应用协议。下面按源码分支逐一拆解 TryParse 方法1. 仅带 scheme 的输入mailto、应用 URIconst string schemeRegex ^([a-z][a-z0-9\-.]*):; if (input.EndsWith(:, StringComparison.OrdinalIgnoreCase) !input.StartsWith(http, StringComparison.OrdinalIgnoreCase) !input.Contains(/, StringComparison.OrdinalIgnoreCase) !input.All(char.IsDigit) Regex.IsMatch(input, schemeRegex)) { systemUri new System.Uri(input); return true; }见 ExtendedUriParser.cs#L26-L38当输入以:结尾、且 scheme 部分符合 RFC 3986 的规则[a-z][a-z0-9\-.]*这一点源于 issue #15035 的修复时直接构造systemUri返回。典型输入如mailto:、ms-powerpoint:通常代表“用该应用打开”。2. 明确拒绝的输入形态if (input.EndsWith(:, StringComparison.CurrentCulture) || input.EndsWith(., StringComparison.CurrentCulture) || input.EndsWith(:/, StringComparison.CurrentCulture) || input.EndsWith(://, StringComparison.CurrentCulture) || input.All(char.IsDigit)) { return false; }见 ExtendedUriParser.cs#L40-L49这正是文档所说的“捕获 UriBuilder 不处理的用例”以:、.、:/、://结尾的半截输入用户在逐步敲 URL 的中间状态以及纯数字输入一律判定为不可解析。注意第一个分支scheme-only必须先于这个拒绝逻辑执行否则mailto:会被误拒。3. 主体解析UriBuilder 与端口归一化var urlBuilder new UriBuilder(input); urlBuilder.Port urlBuilder.Uri.IsDefaultPort ? -1 : urlBuilder.Port;见 ExtendedUriParser.cs#L53-L56用UriBuilder构造后若 URI 携带的是默认端口http 的 80 / https 的 443把Port置为-1以从结果 URL 中去除端口号让展示更干净例如https://example.com:443展示为https://example.com。随后进入几类分支判断大写HTTP://归一化若输入以HTTP://不区分大小写开头显式把 scheme 设为httphost:port形式无 scheme输入匹配^[\w\.]:\d域名端口或 IPv6端口^\[([\w:]:)[\w]\]:\d正则时先尝试构造https:// 输入的 URI若解析出的端口是 80则把 scheme 降回http。该分支用catch (UriFormatException)兜底注释明确说明这是为了处理tel:xxxx之类输入——当“端口”超过 65535 时UriBuilder会抛异常捕获后可仍保留原始解析结果用于返回systemUri见 ExtendedUriParser.cs#L62-L85。分支末尾用单标签正则[\.:]|^http$|^https$|^localhost$判断主机若主机是localhost等单标签形式则不产生systemUri只保留网页结果避免把localhost:8080误当成自定义 scheme URI。含冒号但不是 http、无方括号的输入ExtendedUriParser.cs#L86-L92保持UriBuilder的原样解析结果直接作为systemUri。这是tel:12345、mailto:exampledomain等应用协议进入结果的通道。其余情况把 scheme 默认设为httpsExtendedUriParser.cs#L93-L96。也就是说直接输入example.com会得到https://example.com的网页结果。最后统一收尾只要最终 scheme 是http或https就把结果赋给webUriExtendedUriParser.cs#L98-L102UriBuilder抛UriFormatException时整体返回 false。4. 解析结果如何变成可点击的条目回到 Main.cs 的 Query只有当_uriParser.TryParse成功且_uriResolver.IsValidHost(webUriResult)为 true 时才生成结果随后webUri与systemUri若非 null会分别生成一条Result结果TitleSubTitle图标执行动作webUri规范化后的 URL 字符串“Website”本地化资源默认浏览器图标BrowserInfo.IconPathHelper.OpenInShell(url)systemUri原样 URI 字符串“Open”本地化资源插件默认图标DefaultIconPathHelper.OpenInShell(uri)因此像mysite:8080这类host:port输入可以同时出现“网站”https 补全版与“打开”自定义 scheme 原样版两条结果由用户选择打开失败时同样会以Plugin: 插件名为标题弹出ShowMsg错误消息。值得注意的是源码中的一条维护约束ExtendedUriParser.cs#L15// When updating this method, also update the local method IsUri() in Community.PowerToys.Run.Plugin.WebSearch.Main.QueryWebSearch 社区插件在 Main.cs#L137-L168 中实现了本地私有方法IsURI其判定逻辑与ExtendedUriParser保持平行用于在启用NotGlobalIfUri选项时Main.cs#L97-L103把“查询本身已是 URI”的场景从全局 Web 搜索结果中排除避免搜索网页与打开 URI 两条结果重复。修改 URI 解析规则时两处必须同步。三、URI Resolver主机校验的扩展点文档说明 UriResolver.cs “对有效主机返回 true”并且目前没有额外的非法主机过滤逻辑——这一点在源码中得到逐字印证public class UriResolver : IUrlResolver { public bool IsValidHost(System.Uri uri) { return true; } }它实现 IUrlResolver 接口在 Main.cs#L76-L78 中被调用if (!string.IsNullOrEmpty(query?.Search) _uriParser.TryParse(query.Search, out var webUriResult, out var systemUriResult) _uriResolver.IsValidHost(webUriResult))当前实现对任何由解析器成功构造的 Uri 都放行文档同时指出这是一个有意保留的扩展位未来可以在这里加入针对特定 host 的过滤逻辑例如黑名单或仅放行 http/https 主机。对维护者而言这意味着“解析成功”与“结果可用”是两个独立关卡Resolver 是插入策略的正确位置。四、默认浏览器图标来自注册表并随主题切换文档中“Default Browser Icon”一节说明每条 URI 结果的图标是用户设置的默认浏览器的图标相关信息来自用户注册表并在 PT Run 主题变化时更新。源码中的对应实现分三层图标来源网页结果直接取BrowserInfo.IconPathBrowserInfo即Wox.Plugin.Common.DefaultBrowserInfo见 Main.cs#L14即 Windows 默认浏览器对应的图标系统 URI 结果则取插件自身的DefaultIconPath。主题切换刷新Init时订阅Context.API.ThemeChanged事件并调用UpdateIconPathUpdateIconPath按主题选择 uri.light.png 或 uri.dark.pngLight 与 HighContrastWhite 用浅色其余用深色见 Main.cs#L130-L168。数据时效Init与ReloadData都会调用BrowserInfo.UpdateIfTimePassed()Main.cs#L170-L178即浏览器信息不是只读一次而是按需刷新——用户更换默认浏览器后无需重启即可反映到结果图标。此外插件还定义了 UriSettings含ShowBrowserIcon true属性并通过PluginJsonStorage在Save()时持久化。从当前源码结构看Query中网页结果直接使用了BrowserInfo.IconPath该设置对象更多是插件设置的承载与扩展位。五、Score 为 0URI 结果为何排在其他插件之后文档“Score”一节指出URI 插件的所有结果评分为 0因此会显示在其他插件之后——唯一的例外是索引器indexer插件它同样是 0 分。这一点可以从两个方向得到印证结果对象默认分Run 的插件结果类型Result定义在 Wox.Plugin/Result.cs#L109Score是int且无显式初始值。URI 插件的 Main.cs 在构造Result时没有给Score赋值因此所有结果天然为 0。0 分的含义是“最低优先级基线”对比其他插件可以看到分数如何被用来抬升结果优先级例如 Community.PowerToys.Run.Plugin.VSCodeWorkspaces/Main.cs#L147-L155 会把Score 0的结果提升到 100再按匹配度加减分。可以推断URI 插件的 0 分设计意图就是“宁可排在应用、文件等高分结果之后”只有在没有其他更相关结果时或配合索引器同级结果时用户才会看到并选中 URI 条目而输入//关键词则可越过排序直接强制调用本插件。六、小结把文档结论与源码对应起来URI 插件的完整工作链路是plugin.json声明//关键词与全局参与plugin.jsonMain.Query拦截查询空查询且设置了默认浏览器时给出“打开浏览器”条目否则交给 ExtendedUriParser 解析解析器先处理 scheme-only 输入再拒绝:/./://://结尾与纯数字输入随后用UriBuilder做端口归一化、http(s)补全与host:port补 https最终产出webUri和/或systemUriUriResolver 当前无条件放行是预留给主机过滤策略的扩展点结果以 0 分进入全局排序网页结果佩戴默认浏览器图标来自注册表、随主题与浏览器变更刷新系统 URI 结果佩戴插件深/浅色图标与 WebSearch 插件的IsURI逻辑互为镜像需同步维护。对希望在 PowerToys Run 中扩展 URI 行为的开发者而言三个文件值得精读ExtendedUriParser.cs 的解析分支、Main.cs 的结果组装与图标生命周期以及 UriResolver.cs 这个最小化的策略接口。【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。