无需命令即可评估 zsh 中的术语

无需命令即可评估 zsh 中的术语

我正在使用 zsh普雷斯托配置框架。我希望能够输入类似的术语1 + 2 * (3 / 4)并从中得到“2.5”。

这些术语可以被识别,因为它们仅包含某些字符:0123456789 +-*/()。对于更复杂的事情,我可以打开一个专用程序(如 python shell)。

解决方案不够好

  1. 使用程序:我不想python -c在我的术语之前输入或将其输入到bc.打字太多了,希望能做得更好。
  2. 使用函数或别名: 有一些解决方案那里允许在使用cor=或 时进行这些计算calc,就像在= 1 + 2 * (3 / 4).这很好,但基本上与第 1 点相同。
  3. 使用另一个外壳: 我知道克森什我确信还有其他 shell 可以做到这一点。但我喜欢 zsh 并且不想换 shell。

什么可能有效

  1. zsh 插件:我可以想象一个 zsh 插件,它可以查找命令是否与某个正则表达式匹配,然后将其通过管道传输到 python/bc/whatever 中。有点类似于当您仅输入目录名称时自动 cd 的作用。我不知道这是否可能。我很想听到一些提示,这样我就可以写下来。
  2. 截距command not found:与4类似。也许可以拦截zsh在未找到命令时的行为。但我又不知道该怎么做。
  3. 所有号码的别名:我想您可以为所有数字编写一个别名,以便它们成为将数学字符串的其余部分作为参数的命令。这可能有用,但看起来很老套。此外,“所有数字”是相当多的别名,即使在自动生成代码时也是如此。

我想听听关于如何解决这个问题的想法。我并不害怕编写代码,但我更喜欢干净的解决方案而不是黑客的解决方案。

答案1

在命令执行之前拦截它是可能的,但为时已晚:该命令已经被解析并且别名已经被扩展。例如,2 * 3将显示为未找到命令2(假设没有该名称的命令),后跟当前目录中的文件列表。

相反,您需要在命令提交后(甚至在解析它之前)立即拦截该命令。因此,您需要挂接到命令行界面,而不是挂接到命令执行引擎。我认为没有通用的方法可以做到这一点:我能想到的唯一方法是覆盖 Enter 键命令及其兄弟命令,并让它们重写命令行。这不太漂亮,但它满足您的要求。

主要的回车键命令是accept-line,绑定到^J^M。您可以按如下方式覆盖它(您需要对您使用的其他类似小部件执行此操作,例如accept-and-holdaccept-line-and-down-history等):

function my-accept-line {
    my-rewrite-accepted-line "$@"
    zle accept-line "$@"
}
zle -N my-accept-line
bindkey '^J' my-accept-line
bindkey '^M' my-accept-line

现在,让函数重写接受的行。该行内容位于BUFFER。唯一的困难是重写的逻辑。也许是这样的,它要求该行以数字(不是变量,这太不明确了)开头,可选地在前面加上一元运算符和括号,后面跟着一个二元运算符:

function my-rewrite-accepted-line {
  emulate -L zsh
  setopt extended_glob
  if [[ ${BUFFER// /} == [\(+\-]#([0-9]##(|.[0-9]#)(|e(-|+|)[0-9]##)|0x[0-9A-Fa-f]##)[-+*/%\&\|\^]* ]]; then
    BUFFER="echo \$(($BUFFER))"
  fi
}

请注意,我仅使用裸 zsh 进行了最少的测试。我还没有调查这是否会干扰 Prezto。

相关内容