如何防止Python脚本中的ANSI转义序列弄乱我的zsh RPROMPT和光标位置?

时间:2015-05-26 22:51:20

标签: python zsh ansi-escape

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

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

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

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="")

除了一些没有受过教育的猜测之外,我不完全确定为什么会这样。我希望有人在这里做,并且知道一个解决方案或解决方法,它将所有东西都放回原来的位置。作为参考,这是违规脚本:

db.procedures.find({'procedure.name':'nameOfMyProcedure'})

2 个答案:

答案 0 :(得分:1)

您希望在提示中围绕ANSI转义使用%{ %} ZSH转义序列,如文档here

所示
  

%{...%}

     

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

     

%和{之间的正数字参数被视为   描述为下面的%G。

答案 1 :(得分:0)

这是zsh的常见问题,就像所有其他shell一样,不知道你的提示有多长,除了strlen字符串,除非你在某些标签上标记非打印字符方式。

有很多方法可以为每个shell解决这个问题, * ,但在zsh中,你真的不需要;这是它首先以提示格式visual effects commands的原因的一半。 **

因此,例如,而不是:

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

......你可以这样做:

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

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

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

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