开发工具【免费下载链接】clinkBashs powerful command line editing in cmd.exe项目地址https://gitcode.com/gh_mirrors/cli/clink点击查看免费下载Clink 将 Windows 原生的 cmd.exe 与 GNU Readline 库强大的命令行编辑能力结合起来为 Windows 命令行用户提供与 Bash 同级的补全、历史与行编辑体验。本篇技术指南以仓库文档 docs/clink_v049.md 为核心结合当前仓库源码逐一验证每个功能点的真实实现帮助读者掌握 Clink 的安装注入、参数配置、Readline 定制以及基于 Lua 的补全、提示符扩展等全部实战技能。Clink 是什么Clink 的核心目标非常明确把 GNU Readline 库的编辑体验带进 Windows 的 cmd.exe。Readline 是著名的 Unix Shell如 Bash、Mac OS X 与许多 Linux 发行版的标准 Shell所使用的行编辑库其补全、历史与按键绑定能力久经考验。Clink 通过把 Readline 嵌入 cmd.exe让 Windows 命令行用户在保留原有 Shell 语义的同时获得 Unix 风格的行编辑体验。从当前仓库源码结构看项目由多个子系统组成app/src/loader/clink.exe的命令行入口负责inject、autorun、set、history等子命令的分发见 loader.cppapp/src/dll/被注入目标进程的 DLL 本体见 dll.cpplib/src/核心的行编辑器实现包括 Readline 集成、匹配生成、补全显示、历史数据库等lua/src/Lua 运行时桥接层把补全生成器、参数解析框架、提示符过滤等能力暴露给脚本readline/GNU Readline 库源码是行编辑能力的直接来源。功能总览Clink 在 cmd.exe 中提供的能力包括与 Bash 相同的行编辑直接来自 GNU Readline 库支持 Emacs/vi 模式等全部编辑语义会话间历史持久化命令历史可以保存到磁盘下次会话继续使用上下文相关补全可执行文件含别名目录相关命令环境变量第三方工具Git、Mercurial、SVN、Go、P4新增键盘快捷键从剪贴板粘贴Ctrl-V增量历史搜索Ctrl-R / Ctrl-S强大补全TAB撤销Ctrl-Z自动cd ..Ctrl-Alt-U环境变量展开Ctrl-Alt-E按Alt-H可查看更多按键绑定基于 Lua 的可脚本化补全可着色、可脚本化的提示符自动应答 “Terminate batch job?” 提示。默认情况下Clink 将Alt-H绑定为显示当前按键绑定表。更多功能细节可查阅 GNU Readline 与 History 库的官方手册Clink 本身在lib/src/与readline/中维护了这些库的完整源码。从源码角度验证_default_inputrc仓库根目录展示了现代 Clink 默认开启的 Readline 选项colored-completion-prefix on、colored-stats on、mark-symlinked-directories on、completion-auto-query-items on、search-ignore-case on等可见“彩色补全”“忽略大小写搜索”等体验都是直接映射到 Readline 配置项的。使用 Clink 的三种方式文档明确给出了三种使用 Clink 的途径写入 cmd.exe 的 autorun 注册表项安装器在安装时可选择此方式。Clink 同时提供命令行工具来管理该 autorun 项运行clink autorun --help可查看详细信息。手动注入在某个 cmd.exe 会话内运行clink inject即可在该会话中启用 Clink。使用安装器添加到开始菜单的 Clink 快捷方式该快捷方式本质上是cmd.exe /k clink inject命令。autorun 命令细节从源码看autorun.cppclink autorun提供如下子命令install [-- args...]安装一条命令到 cmd.exe 的 autorun用于启动 Clinkshow显示 cmd.exe 的 autorun 变量的当前值set string...显式将 cmd.exe 的 autorun 设置为指定字符串uninstall移除 Clink 的 autorun 条目。安装逻辑见 autorun.cpp会先移除任何旧的 Clink autorun 条目保证不会重复、且与其他 hook cmd.exe 的项目友好共存再把形如clink路径\clink.bat inject --autorun的新条目追加到现有 autorun 值的末尾。其中--autorun是一个特殊标记告诉 Clink 本次注入来自 autorun 环境。此外还支持-a, --allusers选项修改所有用户的 autorun需要管理员权限。inject 命令细节clink inject的底层行为见 inject.cpp它会检查目标进程是否受支持然后把 Clink DLL 注入目标进程并建立远程调用。注入前DLL 会被复制到系统临时目录下的clink\dll_cache\版本号缓存中见 inject.cpp以避开正在运行的 DLL 文件锁问题。Clink 的工作原理当通过上述方式运行 Clink 时它首先检查父进程是否受支持然后向其中注入一个 DLL。该 DLL 随即 hook 两个 Windows API 函数WriteConsole()用于捕获当前提示符内容ReadConsole()hook 后让 Clink 提供自己的、基于 Readline 的命令行编辑。也就是说cmd.exe 自己原本的交互式输入输出路径被 Clink 接管用户看到的命令行编辑行为全部由 Readline 提供。从当前仓库的lib/src/display_readline.cpp如 display_readline.cpp可以看到Clink 最终通过WriteConsoleW输出 Readline 渲染结果而输入侧则经由终端输入模块terminal/src/win_terminal_in.cpp处理 Windows 控制台输入事件。配置 Clink配置 Clink 最简便的方式是使用clink set命令行选项它可以列出、查询和设置 Clink 的设置项。在一个已安装 Clink 的 cmd.exe 进程中运行clink set --help可以获得更详细的用法说明以及每个选项的描述。clink set命令的实现见 set.cpp支持list列出所有设置项、listkeys仅输出名称、查询指定键的完整描述名称、描述、当前值、默认值以及设置/清除设置值。对于布尔型设置会列出true/false枚举型会列出全部可选项颜色型会列出bold、bright、red、green、sgr等关键字语法见 set.cpp。用环境变量覆盖设置Clink 启动时加载的设置可以被与环境变量同名且带clink.前缀的变量覆盖。例如命令set clink.prompt_colour10会把提示符变成绿色无论设置文件里写的是什么。覆盖值不会保存到磁盘。从源码看该机制与 profile/状态目录的解析紧密相关见 app_context.cppclink_profile环境变量可覆盖所有其他状态目录来源而clink.profile由注入器设置的特殊环境变量则记录当前 profile 路径。设置项完整表格下表完整列出文档给出的 v0.4.9 设置项及其含义名称描述ansi_code_support打印提示符时Clink 内置了对 SGR ANSI 转义序列的基础支持用于控制文本颜色。若检测到第三方工具也提供该能力则自动禁用也可将其设为 0 来手动禁用。ctrld_exits在空行上按下 Ctrl-D 时退出进程。esc_clears_line按下 Esc 时清除当前行Readline 的 vi 模式启用时除外。exec_match_style当命令行中没有路径分隔符时Clink 如何匹配可执行文件。0 仅 PATH1 PATH 和 CWD2 PATH、CWD 和目录。无论取值如何当存在路径分隔符时可执行文件和目录都会被匹配。history_dupe_mode若输入的行与已有历史条目重复设为 2 时 Clink 会抹掉旧的重复项设为 1 时不向历史中添加重复项设为 0 时总是添加。history_expand_mode输入行中的!字符可被解释为引用历史中的词。设为 1 或 0 可分别启用或禁用。值为 2、3、4 时分别跳过单引号、双引号、或两种引号内的!字符。history_file_lines设为正整数时这是 Clink 把命令历史保存到磁盘时持久化的行数0 表示无限行负数表示禁用历史持久化。history_ignore_space向历史添加条目时忽略以空白字符开头的行。history_io控制历史何时写入磁盘、何时读回。1 在新一行编辑开始前读入历史2 写入历史3 两者都做默认值 0 进程退出时写入历史。match_colour显示补全匹配项时使用的颜色。小于 0 的值表示使用默认颜色的相反亮度。prompt_colour用 ANSI 转义序列包围提示符以设置其颜色0..15。值小于 0 时禁用。space_prefix_match_files若行以空白开头Clink 绕过可执行文件匹配改为匹配所有文件和目录。terminate_autoanswer自动应答 cmd.exe 的Terminate batch job (Y/N)?提示。0 禁用1 应答 Y2 应答 N。use_altgr_substituteWindows 提供 Ctrl-Alt 作为 AltGr 的替代历史上用于支持没有 AltGr 键的键盘。这可能与 Readline 的部分按键绑定冲突。现代 Clink 的设置迁移需要特别说明的是当前仓库已是较新版本上述 v0.4.9 的设置名大多在新版本中发生了迁移。clink set仍能识别旧名并自动迁移见 settings.cpp 的migrate_setting()。其中exec_match_style→ 拆分为exec.enable、exec.path、exec.cwd、exec.dirs四个开关prompt_colour→ 映射到color.prompt如bri red、gre等 DOS 颜色名ansi_code_support→terminal.emulationauto/nativeesc_clears_line→terminal.raw_esc取值语义反转history_file_lines→history.savehistory.max_linesctrld_exits→cmd.ctrld_exitsspace_prefix_match_files→exec.space_prefixterminate_autoanswer→cmd.auto_answerhistory_ignore_space→history.ignore_spacehistory_dupe_mode→history.dupe_modehistory_io→history.sharedhistory_expand_mode→history.expand_modeuse_altgr_substitute→terminal.use_altgr_substitute。而match_colour已不再是设置项应改用 inputrc 中的colored-stats与LS_COLORS见 settings.cpp。这些迁移后的设置同样可以查看clink set --help获得完整列表。文件位置设置与历史记录会在会话之间持久化到磁盘其位置取决于 Clink 的发行方式使用.exe 安装器安装时Clink 使用当前用户的非漫游应用程序数据目录通常位于c:\Documents and Settings\username\Local Settings\Application DataWindows XPc:\Users\username\AppData\LocalVista 及之后使用.zip 发行包时Clink 会在其核心文件所在目录创建并使用一个名为profile的目录。以上所有位置都可以通过clink inject --profile path命令行选项覆盖。从源码看profile 路径的解析还支持环境变量clink_profile和波浪号展开见 app_context.cpp优先级依次为clink_profile环境变量 clink.profile 用户目录。需要注意的是现代 Clink 里--profile若传入以\结尾的路径会触发一个已知的引号解析怪癖见 inject.cpp实际使用时应避免路径以反斜杠结尾。配置 ReadlineReadline 本身也可以配置方法是创建一个 Readline 初始化文件为 Clink 添加自定义按键绑定和宏。Readline 官方手册见文档附带的 readline 文档目录详细记录了所有可用的配置选项。Clink 会在HOME环境变量指定的目录中搜索以下文件按顺序匹配其一即可clink_inputrc、_inputrc、.inputrc。如果HOME未设置Clink 会使用 Windows 标准环境变量%homedrive%\%homepath%或%userprofile%。其他也使用 Readline 的软件同样会查找.inputrc文件可能还有_inputrc。为了设置仅对 Clink 生效的宏和按键绑定可以使用 Readline 初始化文件的条件构造$if cmd.exe # 仅对 Clink 生效的绑定写在这里 $endif不建议编辑clink_inputrc_base因为该文件会随版本变化未来版本中可能不再存在。仓库根目录的 _default_inputrc 展示了当前版本默认开启的 Readline 设置例如colored-stats on、search-ignore-case on等可作为自定义 inputrc 的参考基准。扩展 ClinkLua 脚本化Readline 库允许客户端为补全匹配提供备选生成路径。Clink 借此把 Lua 挂入补全流程从而可以用 Lua 脚本编程式地生成补全匹配。Lua 运行时桥接层的核心实现在 lua/src 目录其中 lua_match_generator.cpp 展示了补全生成器是如何在按下 TAB 时被调用的Clink 构造当前行状态对象后调用 Lua 侧的clink._internal._generateLua 侧再回调用户注册的各个生成器函数。Lua 脚本的位置Clink 在配置 Clink一节所述的目录中查找 Lua 脚本。默认情况下Ctrl-Q被映射为重新加载全部 Lua 脚本这对开发调试自己的脚本非常有用。脚本加载的实现可参考 lua_script_loader.cpp内置脚本则由 lua_scripts.cpp 嵌入。仓库的 docs/examples 目录提供了大量可直接借鉴的示例脚本例如 ex_generate.lua、ex_prompt.lua 等。匹配生成器Match Generators匹配生成器是注册到 Clink、在 Readline 补全流程中被调用的 Lua 函数形式如下function my_match_generator(text, first, last) -- 使用 text / rl_state.line_buffer 生成匹配项 -- 通过 clink.add_match() 提交给 Clink -- 返回 true / false end其中text是被补全的词first与last是text在完整行缓冲区中的起止索引完整行缓冲区可通过变量rl_state.line_buffer访问。如果后续无需再调用其他匹配生成器则函数应返回 true。注册匹配生成器clink.register_match_generator(my_match_generator, sort_id)sort_id用于对匹配生成器排序sort id 较小的生成器会先被调用。配套的 API 文档见 docs/api_v049.md对clink.register_match_generator(generator, sort_id)的说明与之一致生成器函数形如generator_function(text, first, last)当按 TAB默认补全键时被调用。下面是一个简单示例检查text是否以%开头若是以 % 开头则用text的剩余部分匹配环境变量名。function env_vars_match_generator(text, first, last) if not text:find(^%%) then return false end text clink.lower(text:sub(2)) local text_len #text for _, name in ipairs(clink.get_env_var_names()) do if clink.lower(name:sub(1, text_len)) text then clink.add_match(%..name..%) end end return true end clink.register_match_generator(env_vars_match_generator, 10)这里用到的clink.add_match(text)、clink.get_env_var_names()在 docs/api_v049.md 中均有对应条目其中clink.get_env_var_names()返回当前进程环境变量名的数组。参数补全Argument CompletionClink 提供了一套框架用于用 Lua 编写复杂的参数匹配生成器。其思路是创建一个描述命令参数与标志的parser 对象然后把它注册到 Clink。当 Clink 检测到当前被编辑的命令行中正在输入该命令时就使用该 parser 生成匹配。下面是一个名为foobar的简单 parser 示例my_parser clink.arg.new_parser() my_parser:set_flags(-foo, -bar) my_parser:set_arguments( { hello, hi }, { world, wombles } ) clink.arg.register_parser(foobar, my_parser)这个 parser 描述了一个具有两个位置参数各有两个候选值的命令并带有两个标志。标志被认为是位置无关的——只要被补全的词以某个前缀开头parser 就会尝试从标志集合中匹配。在命令行上补全效果大致如下C:\foobar hello -foo wo world wombles C:\foobar hello -foo wo_clink.arg.new_parser()也可以直接接受标志和位置参数作为调用clink.arg.set_arguments()与clink.arg.set_flags()的替代写法some_parser clink.arg.new_parser( { arg1-1, arg1-2 }, { arg2-1, arg2-2 }, -flag1, -flag2 )更多高级用法链接 Parser经常出现命令参数解析依赖前面词的情况例如git merge ...与git log ...不同。对此 Clink 允许用 Lua 的字符串连接运算符把 parser 链接到参数的词上parser 也可以与标志连接。a_parser clink.arg.new_parser():set_arguments({foo, bar }) b_parser clink.arg.new_parser():set_arguments({ abc, 123 }) c_parser clink.arg.new_parser() c_parser:set_arguments( { foobar .. b_parser }, { c_parser } )按前一小节的语法展开即为parser clink.arg.new_parser a_parser parser({foo, bar }) c_parser parser( { foobar .. parser({ abc, 123 }) }, { c_parser } )如上例所示也可以不把 parser 连接到词上直接使用。当 Clink 跟随一个链接到达某个 parser 后该链接是永久的不会回到之前的 parser。从配套 API 文档docs/api_v049.md可以补充更多 parser 方法parser:add_arguments()追加位置参数、parser:add_flags()追加标志、parser:be_precise()要求精确匹配词才前进到下一个参数、parser:disable_file_matching()禁止解析结束后默认匹配文件系统、parser:dump()打印 parser 结构、parser:go(parts)直接运行解析、parser:is_flag(word)判断是否为合法标志、parser:loop(index)使解析在指定参数处循环而非终止。这些方法共同构成了完整的参数补全框架。函数作为参数选项参数选项不限于字符串Clink 也接受函数从而支持更具上下文的参数选项function rainbow_function(word) return { red, white, blue } end the_parser clink.arg.new_parser() the_parser:set_arguments( { zippy, bungle, george }, { rainbow_function, yellow, green } )函数接收一个参数来自被编辑命令行的某个词若该词正位于光标下则为部分词。函数应返回候选匹配的表格若它自己直接调用了clink.add_match()则返回空表。过滤补全显示有些情况下更适合以与传给 Readline 的内部匹配不同的形式来显示候选匹配。例如 Readline 标准的文件名匹配匹配项是完整被补全的词但只显示路径的最后一部分例如匹配foo/bar显示为bar。为支持这种需求Clink 提供了clink.match_display_filter变量可设置为一个函数该函数会在匹配项被显示之前被调用function my_display_filter(matches) new_matches {} for _, m in ipairs(matches) do local _, _, n m:find(\\([^\\])$) table.insert(new_matches, n) end return new_matches end function my_match_generator(text, first, last) ... clink.match_display_filter my_display_filter return true end函数的唯一参数matches是 Clink 将要显示内容的表格返回值是按匹配生成器需求过滤后的输入匹配表格。clink.match_display_filter的值在每次匹配生成被调用时都会被重置。对应的显示侧实现可参考 display_matches.cpp 与 matches_impl.cpp它们负责把匹配项渲染到终端。定制提示符Clink 在显示提示符之前会先把提示符内容经过 Lua 过滤从而可以定制提示符。这一过程在每次显示提示符时都会发生因此支持上下文相关定制例如在 git 仓库中显示当前分支。编写提示符过滤器很直接最合适的示例是当前目录是 git 仓库时显示当前 git 分支。function git_prompt_filter() for line in io.popen(git branch 2nul):lines() do local m line:match(%* (.)$) if m then clink.prompt.value [..m..] ..clink.prompt.value break end end return false end clink.prompt.register_filter(git_prompt_filter, 50)过滤器函数不接收参数而是通过clink.prompt.value变量读取和修改提示符。它返回 true 表示提示符过滤已结束返回 false 表示继续执行下一个已注册的过滤器。过滤器函数通过clink.prompt.register_filter()连同 sort id 一起注册进过滤器链sort id 决定过滤器被调用的顺序较小的 sort id 先被调用。从当前仓库的 prompt.lua 可以看到clink.prompt.register_filter(filter, priority)的现代实现它内部把传入函数包装进一个带优先级的过滤器对象并在回调中维护clink.prompt.value。clink.promptfilter(priority)是与之等价的旧接口标记为 deprecated。此外现代版本还支持clink.promptcoroutine(func, cookie)协程式提示符仅能在提示符过滤器中使用见 prompt.lua。更丰富的提示符示例异步提示符、右侧提示符、环绕提示符、瞬时提示符等可在 docs/examples 目录中找到。其他功能绑定特殊按键由于 Windows 与 Linux 的差异PageUp/PageDown 与方向键等在 Clink 中的转义码与 Linux 不同。转义码格式为\e?其中 ? 是下表中的一个字符按键普通ShiftCtrlCtrl-ShiftHomeGaw!UpHbTPageUpIcU#LeftKds$RightMet%EndOfuDownPgVPageDownQhv(InsertRiW)DeleteSjX*Tab(n/a)Z(n/a)(n/a)下面是 clink_inputrc 文件中的一行示例把 Shift-End 绑定到 Readline 函数transpose-word\ef: transpose-word注意文档中该示例使用\e后跟反引号再加 f其中 Shift-End 对应的表内字符为 f。实际使用时请以表内字符为准。Readline 的 menu-completeClink 支持 Readline 的 menu-complete 命令与 vanilla cmd.exe 那种循环切换匹配项而非列表展示的补全方式类似。要使用这种菜单式补全Clink 提供了替代命令clink-menu-completion-shim。使用它可确保进行适当的路径分隔符转换。PowerShellClink 对 PowerShell 提供基础支持。为了正确显示补全Clink 需要解析 PowerShell 的提示符以提取当前目录。如果提示符被自定义过Clink 很可能无法按预期工作。结语Clink v0.4.9 所描绘的图景在今天的仓库中依然清晰可辨注入器负责把 Readline 塞进 cmd.execlink set管理从颜色到历史行为的一切开关而 Lua 扩展系统则把补全生成器、参数解析框架与提示符过滤全部开放给用户。无论你只是想获得 Bash 式的行编辑手感还是想为自己的工具编写深度补全脚本这篇指南覆盖的安装注入、设置迁移、inputrc 定制与 Lua 扩展四大部分都可以直接对照当前仓库源码loader 下的autorun.cpp、inject.cpp、set.cpplua/src 下的lua_match_generator.cpp、prompt.cpp逐一验证、按需扩展。赞分享开发工具【免费下载链接】clinkBashs powerful command line editing in cmd.exe项目地址https://gitcode.com/gh_mirrors/cli/clink点击查看免费下载相关推荐Clink 使用指南让 cmd.exe 拥有 Bash 级的命令行编辑、补全与历史体验Clink 使用指南让 cmd.exe 拥有 Bash 级的命令行编辑、补全与历史体验 Clink 将 Windows 原生外壳 cmd.exe 与 GNU开发工具合金装备2 PC版终极修复指南MGS2修复补丁安装教程与常见问题解决合金装备2 PC版终极修复指南MGS2修复补丁安装教程与常见问题解决 还记得当年在电脑上第一次打开《合金装备2自由之子》的惊喜吗分辨率被锁死在低档、人【亲测免费】 Clink安装与配置完全指南在Windows上体验Bash般的命令行编辑Clink安装与配置完全指南在Windows上体验Bash般的命令行编辑 Clink是一款强大的开源工具旨在将Windows的经典命令提示符 cmd.exe开发工具CLI上一篇WonderTrader量化交易全流程解决方案的技术突破与落地实践下一篇7个颠覆性技巧Steam交易卡自动化解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?