fish shell:仅当先前的输出存在时才在提示前添加换行符

fish shell: add newline before prompt only when previous output exists

(免责声明:我使用的是鱼,但这同样适用于 bash)
我当前的 shell 在提示符之前打印一个换行符,因此我可以在命令输出之间轻松找到它。

# [...]
echo # newline before prompt
echo -s $arrow ' ' $cwd $git_info
echo -n -s '❯ '

但是,当没有先前的输出时,也会打印换行符,例如使用 printf "3c" 清除终端后(或首次打开终端时):

                           <--- bad newline: no previous output
➜ /some/dir            
❯ command1            
output...             
                           <--- good newline
➜ /some/dir          
❯ command2             

问题:有什么办法可以摆脱这个审美上的小烦恼吗?



编辑 #1:

澄清一下:“没有以前的输出”是指我的控制台的内容是空的,即在(重新)初始化终端之后(因为 that's all printf "3c" does)。

编辑:post 编辑得更便携。

这是我在 bash 中的做法:

__PROMPT_NEWLINE=$'\nVVV '
__set_missing_newline_fix()
{
    local CURPOS
    echo -en "3[6n" # ANSI DSR
    read -s -d R CURPOS
    CURPOS=${CURPOS#*;}
    if [ $CURPOS -eq 1 ]; then
        __MISSING_NEWLINE_FIX=""
    else
        __MISSING_NEWLINE_FIX="$__PROMPT_NEWLINE"
    fi
}

PROMPT_COMMAND=__set_missing_newline_fix
PS1="${__MISSING_NEWLINE_FIX}\w > "

请注意,它配置为在我的提示符前加上 VVV 前缀,让我知道最后一条命令没有以换行符结尾。

演示:

$ source bashrc.sh
/tmp/so/newline > echo hello
hello
/tmp/so/newline > echo -n hello
hello
VVV /tmp/so/newline > 

小丑:

ANSI DSR 将导致终端将其当前光标位置写为输入。由于我们是交互式 shell,该输入可用于 shell 的标准输入,所以我们只是 read -s 它(没有回显)。

在上面的 link 中,您会看到响应的格式为 CSI Pl; Pc R,因此我们告诉 read 阅读并包括 R -d R.

然后我们使用 bash'“删除匹配前缀”语法 ${CURPOS#*;} 提取 Pc 部分,该语法删除包括分号 ; 在内的所有内容。

然后,如果光标位置不为1,即我们不在换行符的开头,我们手动在提示中添加一个换行符。

ANSI DSR 应该适用于每个与 ​​ANSI 兼容的终端,但如果您遵循 link,您会发现它并没有字面上说 3[6n,而是 CSI 6 n. CSI is the beginning of an escape sequence。转义序列以 ASCII 27 ESC 字符(八进制 033)开头。

在我最初的回答中,我使用了 \E,其中 bash' 内置 echo -e 命令解析与 3 相同,因此上面的编辑。

Stock fish 已经处理了这个(并且已经处理了很多年),不需要提示来做。

当输出未以换行符结尾时,您会看到“缺少换行符”,如“¶”或“⏎”,后跟一个换行符,然后才是您的提示。

exec 事件在几年前合并到 fish-shell 中。我想你可以在这里使用这些。它们的工作方式类似于其他语言中的事件生命周期挂钩。 https://github.com/fish-shell/fish-shell/pull/1666

作为测试,我创建了一个名为 postexec-newline.fish 的文件,其中包含以下内容:

function postexec_test --on-event fish_postexec
   echo
end

发出 source postexec-newline.fish 后,您描述的行为已被观察到。当使用 C-l 清除屏幕时,换行符也不可见,我认为这就是这种功能的表现方式。

如果您希望永久更改,此功能可以存在于 config.fish 中。