ARTICLE DETAIL

资讯详情

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

fish shell `commandline` 内建命令完全指南:读取与改写命令行缓冲区

fish shell `commandline` 内建命令完全指南:读取与改写命令行缓冲区 CLI开发工具【免费下载链接】fish-shellThe user-friendly command line shell.项目地址https://gitcode.com/GitHub_Trending/fi/fish-shell点击查看免费下载commandline是 fish shell 中一个专为交互式场景设计的内建命令用于读取、修改当前正在编辑的命令行缓冲区command line buffer是补全脚本、自定义快捷键函数和交互式提示符的核心工具。读完本文你将掌握它的全部选项语义、缓冲区作用域buffer/job/process/token的划分规则并能够写出像commandline -xpc这样专业级的补全辅助代码。本文以 doc_src/cmds/commandline.rst 为骨架并结合作品仓库中 src/builtins/commandline.rs 的 Rust 实现与 tests/checks/commandline.fish 测试用例进行源码级验证。一、命令概览与基本用法语法commandline [OPTIONS] [CMD]commandline的功能可以用一句话概括读取或设置当前命令行的内容。它在 C 语言时代就是 fish 的传统内建命令如今在 Rust 重写版本中由src/builtins/commandline.rs中的commandline()函数实现。无参数与单参数行为不带任何参数commandline直接打印当前命令行的完整内容等价于commandline --current-buffer默认作用域。带 CMD 参数清除当前命令行缓冲区并用CMD的内容整体替换它等价于默认的--replace模式。需要特别注意的是commandline只有在交互式会话中才有意义。从源码看当既不存在 transient commandline补全包装时产生的临时命令行也没有交互式会话时会直接报错Can not set commandline in non-interactive mode见 src/builtins/commandline.rs。测试用例 tests/checks/commandline.fish 也验证了fish -c commandline foo会输出这一错误。二、选项总览commandline的选项数量多、组合规则严格先给出一张总览表信息依据 doc_src/cmds/commandline.rst分类选项说明光标与选区-C/--cursor读取或设置光标位置配合-j/-p/-t时位置相对相应子串光标与选区-B/--selection-start读取选区起点位置光标与选区-E/--selection-end读取选区终点位置光标与选区-L/--line打印/设置光标所在行从 1 开始光标与选区--column打印/设置光标在当前行的码点偏移从 1 开始更新方式-a/--append不清空现有命令行将字符串追加到末尾更新方式-i/--insert/--insert-smart在光标位置插入字符串--insert-smart启用 DWIM 模式更新方式-r/--replace清空并用指定字符串替换默认作用范围-b/--current-buffer整个命令行默认不含自动补全建议作用范围-j/--current-job当前 job一条流水线停在逻辑运算符或;、、换行处作用范围-p/--current-process当前 process一条命令停在逻辑运算符、终止符和管道处作用范围-s/--current-selection当前选区作用范围-t/--current-token当前 token作用范围--search-field操作 pager 搜索框而非命令行搜索框未显示时返回假作用范围--inputINPUT把INPUT当作命令行内容来操作便于配合--tokens-expanded等打印方式-c/--cut-at-cursor只打印到光标位置为止的选区打印方式-x/--tokens-expanded对选区做参数展开每个参数单独一行输出打印方式-o/tokenize/--tokens-raw已弃用不要使用输入函数-f/--function把参数当作输入函数放入队列先于后续按键被读取不可与其他选项组合状态查询-S/--search-mode判断是否处于历史搜索模式状态查询-P/--paging-mode判断是否显示 pager 内容如 Tab 补全状态查询--paging-full-modepager 内容且所有行都显示没有 more rows状态查询--is-valid判断命令行是否语法完整有效状态查询--showing-suggestion判断是否正在显示历史自动补全建议通用-h/--help显示帮助上述所有选项的解析都发生在commandline()函数开头的 getopt 循环中src/builtins/commandline.rs并且源码中还有一批文档未收录但已实现的--forward-jump、--backward-jump、--forward-jump-till、--backward-jump-till跳转选项它们会调用reader_jump()驱动光标跳转。三、三种更新模式追加、插入与替换commandline修改缓冲区的方式由三个互斥选项控制源码中以AppendMode枚举表示src/builtins/commandline.rs选项AppendMode行为-r/--replaceReplace移除当前命令行用指定字符串替换默认模式-i/--insertInsert保留当前命令行把字符串插入到光标位置--insert-smartInsertSmart同 insert但启用 DWIMDo-What-I-Mean智能处理-a/--appendAppend保留当前命令行把字符串追加到选区末尾从源码replace_part()src/builtins/commandline.rs可以看到四种模式的差异Replace直接丢弃选区内文本拼入新字符串光标移到新内容末尾Append先保留选区内原文再在后面追加新字符串Insert/InsertSmart在光标处把字符串楔入选区中间光标前移一个插入串长度。DWIM 模式--insert-smart 的特殊行为--insert-smart会调用strip_dollar_prefixes()src/builtins/commandline.rs它会解析插入后的完整文本当某一行行首的进程带有$前缀时自动剥掉这个前缀。例如插入$ echo 123最终进入缓冲区的是echo 123而不是$ echo 123。这个选项有两处限制源码中有显式校验不能与--current-token组合因为当前 token 可能只是命令中间的一部分语义不明见 src/builtins/commandline.rs不能与--search-field组合。对应测试 tests/checks/commandline.fish 中commandline --insert-smart $ echo 123 --current-token会报错options cannot be used together。四、作用范围buffer、job、process 与 token理解commandline作用范围的划分是正确使用它的前提。源码中用TextScope枚举区分四种范围src/builtins/commandline.rs实际范围计算交给parse_util模块的get_job_extent/get_process_extent/get_token_extent-b/--current-buffer整个命令行缓冲区不包括显示的自动补全建议默认。源码中直接映射为0..current_buffer.len()。-j/--current-job光标所在的job即一条流水线。划分边界是逻辑运算符和终止符;、、换行符。-p/--current-process光标所在的process即一条命令。划分边界是逻辑运算符、终止符和管道符|。-t/--current-token光标所在的token。-s/--current-selection当前选区的文本内容若有选区直接输出rstate.text[selection]。以下面的命令行光标在 flounder 的 o 上为例_ echo $flounder 2 | less; and echo $catfish按照文档的定义和get_process_extent、get_job_extent的实现逻辑第一个process是echo $flounder 2第二个是less第三个是and echo $catfish第一个job是echo $flounder 2 | less第二个是and echo $catfish当前的token是$flounder。实际运行验证输出与文档示例一致_ commandline -t $flounder _ commandline -p echo $flounder 2 _ commandline -j echo $flounder 2 | less _ commandline -b # 或直接 commandline echo $flounder 2 | less; and echo $catfish五、打印与分词选项--cut-at-cursor 与 --tokens-expanded-c / --cut-at-cursor只输出光标之前的部分-c让打印在光标位置截断。配合--tokens-expanded时输出到最后一个已完成的 token排除光标所在的 token。这通常是补全场景下最想要的结果。文档给出了一个经典组合技巧想同时拿到光标前的已完成 token和正在输入的 token可以用两条命令commandline --cut-at-cursor --tokens-expanded; commandline --cut-at-cursor --current-token短写形式commandline -cx; commandline -ct-x / --tokens-expanded展开后逐行输出参数-x会对选区执行参数展开大括号展开、变量展开、通配符展开等每个展开结果单独一行输出命令替换不会被展开而是原样透传。这在补全脚本里极其常用。底层实现位于write_part()src/builtins/commandline.rs关键点是expand_string()以CmdsubstMode::Skip模式执行展开即跳过命令替换并设置了COMMANDLINE_TOKENS_MAX_EXPANSION 512的展开数量上限如果展开结果超出限制或出现WildcardNoMatch会回退为输出未展开的原始 token。分词采用Tokenizer的accept_unfinished模式并会跳过重定向目标 token如out中的out——测试commandline --input echo {arg1,arg2} in out --tokens-expanded的输出正是echo、arg1、arg2三行见 tests/checks/commandline.fish。已弃用选项-o、tokenize、--tokens-raw已弃用文档明确警告do not use。它们对应TokenOutputMode::Unescaped与TokenOutputMode::Raw前者做反转义、后者完全不做展开直接输出原始 token。源码中这三种 token 选项互相排斥--tokens options are mutually exclusive测试 tests/checks/commandline.fish 也覆盖了该报错路径。六、光标与选区信息--cursor、--selection-start/end、--line、--column-C / --cursor不给参数打印当前光标位置相对选区的偏移。给参数把光标移动到指定位置。若同时指定-j、-p或-t位置是相对对应子串的而不是相对整个缓冲区。源码实现里光标位置会经过range.start.saturating_add_signed(...)换算并钳制在缓冲区长度以内src/builtins/commandline.rs。注意-C与-ccut-at-cursor不可组合测试 tests/checks/commandline.fish 验证了该组合会报invalid option combination。-B / --selection-start 与 -E / --selection-end分别打印当前选区的起始和结束位置无选区时返回错误。两者不能带位置参数测试用例commandline --selection-start foo会报too many arguments。-L / --line 与 --column--line不给参数时打印光标所在行号最上面一行是 1给参数时把光标设置到指定行。--column不给参数时打印从行首到光标的Unicode 码点偏移从 1 开始给参数时把光标设置到指定列。源码中行号与列号都从 1 开始计数line/column index starts at 1列号超过行长度会报column N exceeds line length行号超过最大行数会报there is no line N——这些边界都在测试中逐一覆盖tests/checks/commandline.fish。七、状态查询选项判断 shell 当前处于什么状态这些选项都只读不改返回值用于条件判断0 表示真非 0 表示假/错误选项查询内容源码实现-S/--search-mode是否正在进行历史搜索rstate.search_mode-P/--paging-mode是否正在显示 pager如 Tab 补全列表rstate.pager_mode--paging-full-modepager 是否完整显示无 more rowsrstate.pager_mode rstate.pager_fully_disclosed--is-valid命令行是否语法完整detect_parse_errors()--showing-suggestion是否正在显示自动历史补全建议reader_showing_suggestion(parser)--is-valid 的三态返回值--is-valid是比较特别的选项它的返回值有三种返回 0真命令行语法有效且完整此时按回车execute绑定函数会直接执行返回 2命令行不完整例如echo foo |后面还缺内容返回 1命令行存在语法错误例如echo $$。源码通过detect_parse_errors(buffer, None, accept_incompletetrue)区分解析成功返回 0incomplete标记为真的返回 2其余解析错误返回 1src/builtins/commandline.rs。空命令行也视为错误返回 1。测试 tests/checks/commandline.fish 完整验证了这三种情况。--showing-suggestion 的典型用途--showing-suggestion用于判断当前是否有一条自动补全建议正在显示、等待被forward-*系列绑定消费。文档给出的典型场景是判断光标在行尾时右移是没有效果还是会接受补全forward-char-passive会自动处理这个逻辑。八、--search-field 与 --input操作非真实命令行--search-fieldcommandline默认操作真实命令行缓冲区--search-field让操作对象变为pager 的搜索输入框。如果搜索框当前没有显示命令返回假。源码中会从rstate.search_field取出搜索框文本与光标位置src/builtins/commandline.rs。该选项不能与--current-buffer、--tokens-expanded、--insert-smart组合。--inputINPUT--input让命令操作给定的字符串而不是真实命令行。这在非交互式环境里测试、或在脚本中复用--tokens-expanded等解析能力时非常有用——测试文件 tests/checks/commandline.fish 里大量用例都依赖--input才能脱离交互式终端运行。源码注释还提到它是一个历史遗留、未收录进文档的选项实现中会直接把current_buffer替换为INPUT字符串。九、--function把输入函数放入队列-f/--function是绑定脚本中常用的程序化按键手段它把每个参数解释为输入函数如execute、repaint、forward-char等完整列表见 bind 命令文档放入输入队列让它们先于后续真实按键被读取。-f不能与任何其他选项组合-h除外。源码实现里每个参数都会经input_function_get_code()转换为ReadlineCmd后通过reader_execute_readline_cmd()入队src/builtins/commandline.rs未知函数名会报Unknown input function foo测试 tests/checks/commandline.fish 覆盖了该错误路径。另外如果当前正处于重绘repaint流程中源码会跳过RepaintMode/ForceRepaint/Repaint类命令以避免无限循环。仓库内置函数__fish_toggle_comment_commandlineshare/functions/__fish_toggle_comment_commandline.fish就演示了-f的经典组合用法它用commandline -r $cmdlines把加上#的注释版本写回缓冲区然后用commandline -f execute让 fish 立即按键执行function __fish_toggle_comment_commandline --description Comment/uncomment the current command set -l cmdlines (commandline -b) if test -z $cmdlines set cmdlines (history search -p # --max1) end set -l cmdlines (printf %s\n #$cmdlines | string replace -r ^## ) commandline -r $cmdlines string match -q #* $cmdlines[1] and commandline -f execute end十、补全脚本的标准范式xpc 与 ct 组合文档明确指出补全脚本最常用的写法是set -l tokens (commandline -xpc)这行命令的含义可以逐字母拆解-x对选区做参数展开每个参数输出一行-p只取当前process正在被补全的那条命令不含|之后的其他命令-c截断到光标位置。组合效果是得到当前进程已被完成的参数列表逐个展开但不包含正在输入的那个 token。如果还想拿到正在输入的 token 本身追加set -l current (commandline -ct)文档特别提醒这样拆分之后不要再用$tokens/$current去手动做前缀匹配因为 fish 自身有 infix matching中缀匹配机制——最好的做法是让补全直接输出所有可能性把与当前 token 的匹配交给 fish 内置逻辑处理。这个范式在仓库补全系统中被广泛使用例如 share/functions/__fish_complete_command.fish 中的set -l ctoken $(commandline -ct)以及 share/functions/__fish_list_current_token.fish 中set -l val $(commandline -t | string replace -r ^~ $HOME)绑定在 Alt-L 上列出光标下目录的内容。十一、更复杂的实战函数拆解fish_commandline_prependshare/functions/fish_commandline_prepend.fish是一个把给定字符串加在命令行开头的完整实战样例它同时用到了读取、替换、插入和光标定位四种能力function fish_commandline_prepend --description Prepend the given string to the command-line, or remove the prefix if already there if not commandline | string length -q commandline -r $history[1] # 空命令行时先取上一条历史 end set -l process (commandline -p | string collect) # 读取当前进程文本 set -l to_prepend $argv[1] ... set -l cursor_location (commandline -pC) # 读取相对进程的光标位置 ... commandline -pC 0 # 光标移到进程开头 commandline -pi -- $to_prepend # 在进程开头插入前缀 commandline -pC (math max 0,($cursor_location $length_diff)) # 恢复光标 end这里可以看到几个要点commandline -pC是读取/设置相对当前 process 的光标位置commandline -pi是相对当前 process 插入——也就是-C文档中提到的配合-j、-p、-t时位置相对子串的实际应用。替换历史条目文档给出的第一个示例是commandline -j $history[3]它把光标所在的job当前流水线替换为历史记录的第 3 条。这是-j选区和-r默认替换模式结合的典型场景。十二、与complete -C STRING的协同文档指出如果在调用complete -C STRING补全给定字符串的过程中调用commandlinecommandline会把STRING视为当前命令行内容。从源码实现看这依赖 fish 的transient commandline机制当parser.libdata().transient_commandline存在时即正在求值complete --arguments之类的包装补全commandline读取/写入的都是这个临时缓冲区而非真实命令行src/builtins/commandline.rs。唯一例外是在求值期间设置光标位置--cursor带参数尚不被支持会报setting cursor while evaluating complete --arguments is not yet supported。十三、注意事项与常见错误综合文档、源码与测试用例使用commandline时有以下几点容易踩坑只能在交互式环境使用fish -c commandline foo会报Can not set commandline in non-interactive mode。要在脚本/测试中使用请搭配--input。选项组合限制严格-f不能与其他选项组合--tokens-*三类互相排斥-c与-C不能组合--is-valid系列状态查询与读取/写入类选项不能混用。源码中都有显式校验并返回STATUS_INVALID_ARGS。--cut-at-cursor和 token 选项不能用于设置场景当同时给出位置参数要写入内容时报--cut-at-cursor and token options can not be used when setting the commandline。行号/列号从 1 开始传入 0 会报错超出范围如列号超过行长度也会报错。空命令行在--is-valid下是错误返回 1而不是不完整2。-o、tokenize、--tokens-raw已弃用新代码一律使用-x/--tokens-expanded。小结commandline是 fish 交互层能力的枢纽它同时扮演读取器buffer/job/process/token 分片读取、展开分词、状态查询和写入器替换/插入/追加/光标定位并深度参与了complete -C的 transient 补全流程。掌握它的选项矩阵与作用范围语义是编写高质量 fish 补全脚本和自定义绑定函数的基础。若需继续深入可研读其实现 src/builtins/commandline.rs、官方文档 doc_src/cmds/commandline.rst以及覆盖了各选项错误路径与正常行为的测试套件 tests/checks/commandline.fish同时可参考 bind 命令文档 了解可入队的输入函数全集。赞分享CLI开发工具【免费下载链接】fish-shellThe user-friendly command line shell.项目地址https://gitcode.com/GitHub_Trending/fi/fish-shell点击查看免费下载相关推荐fish shell type 内建命令完全指南定位命令并解析其类型fish shell type 内建命令完全指南定位命令并解析其类型 导读 type 是 fish shell 的内建命令builtin用于定位一个命令CLI开发工具从命令行计数异常到核心修复Fish Shell 4.0b1 commandline命令深度解析从命令行计数异常到核心修复Fish Shell 4.0b1 commandline命令深度解析 问题背景与影响范围 当开发者在Fish Shell 4.0b1CLI开发工具fish-shell 的 builtin 命令强制调用内建命令的完整指南fish shell 的 builtin 命令强制调用内建命令的完整指南 导读 本文围绕 fish shell 中的 builtin 命令展开讲解如何强制CLI开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表