【问题标题】:How can I prevent ANSI escape sequences in my Python script from messing with my zsh RPROMPT and cursor positions?如何防止我的 Python 脚本中的 ANSI 转义序列弄乱我的 zsh RPROMPT 和光标位置?
【发布时间】:2015-08-08 19:42:48
【问题描述】:

我一直在编写一个 Python 脚本,它为 zsh 生成一个关于当前工作目录中 git repo 状态的 RPROMPT。它在我的 .zshrc 文件中调用:

RPROMPT='$(python3 ~/.git_zsh_rprompt.py)'

为了将它与终端中的其他文本区分开来,我使用了 ANSI 转义码使其变为粗体,并根据 repo 是干净还是脏了颜色。无论出于何种原因,添加这些转义码导致我的 RPROMPT 向左移动,并且它也将我的光标移到了我的左侧 PROMPT 上方。这是一个表示,块代表我的光标:

jared@Jareds-Mac⌷ook-Pro:foobar%                    master( +2 ~4 )

除了一些未受过教育的猜测之外,我不完全确定为什么会发生这种情况。我希望这里有人这样做并且知道解决方案或解决方法,可以将所有内容恢复到应有的位置。作为参考,这是有问题的脚本:

from collections import Counter
from os import devnull
from subprocess import call, check_output, STDOUT

def git_is_repo():
    command = ["git", "branch"]
    return not call(command, stderr = STDOUT, stdout = open(devnull, "w"))

def git_current_branch():
    command = ["git", "branch", "--list"]
    lines = check_output(command).decode("utf-8").strip().splitlines()
    return next((line.split()[1] for line in lines if line.startswith("* ")),
        "unknown branch")

def git_status_counter():
    command = ["git", "status", "--porcelain"]
    lines = check_output(command).decode("utf-8").strip().splitlines()
    return Counter(line.split()[0] for line in lines)

if __name__ == "__main__":
    if git_is_repo():
        counter = git_status_counter()

        # Print bold green if the repo is clean or bold red if it is dirty.
        if counter.elements() == []:
            print("\033[1;32m", end="")
        else:
            print("\033[1;31m", end="")

        print(git_current_branch(), end="")

        # Only print status counters if the repo is dirty.
        if counter.elements() != []:
            print("(", end="")

            if counter["??"] != 0:
                print(" +{}".format(counter["??"]), end="")
            if counter["M"] != 0:
                print(" ~{}".format(counter["M"]), end="")
            if counter["D"] != 0:
                print(" -{}".format(counter["D"]), end="")

            print(" )", end="")

        # Reset text attributes.
        print("\033[0m", end="")

【问题讨论】:

    标签: python zsh ansi-escape


    【解决方案1】:

    您想在提示符中围绕 ANSI 转义使用 %{ %} ZSH 转义序列,如 here 所记录的那样

    %{...%}

    包含一个字符串作为文字转义序列。字符串 大括号内不应改变光标位置。大括号对 可以嵌套。

    % 和 { 之间的正数参数被视为 下面针对 %G 进行了描述。

    【讨论】:

    • 伟大的保存;比我预期的要容易得多的解决方案。很高兴知道我仍然可以在我的 Python 脚本中使用 zsh 序列。
    【解决方案2】:

    这是zsh 的常见问题,与所有其他 shell 一样,不知道您的提示符持续了多长时间,除非您通过 strlening 字符串,除非您以某种方式为它标记非打印字符。

    对于每个 shell,都有解决此问题的方法,* 但在 zsh 中,您真的不必这样做;这就是它首先在提示格式中使用visual effects commands 的一半原因。**

    所以,例如,而不是这个:

    print("\033[1;32m", end="")
    

    ……你可以这样做:

    print("%B%F{green}", end="")
    

    zsh 知道如何查找粗体和绿色并为您的终端插入适当的转义序列,它现在知道根据提示长度计算这些序列。


    * IIRC,zsh 支持bash 样式的转义方括号,以及它自己的%{%} 标记。

    ** 另一半是视觉效果将限制到正确的转义序列,或者如果不可能,则降级为无,而不是仅仅假设一切都是 ANSI。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 2022-12-15
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多