我想在git log
周围写一个包装,有点像gitk
,但在终端上。
我认为这应该很容易,因为git log
已经格式化了输出,我要做的就是将其放在列表视图中,我可以选择一个提交。
但是,urwid和curses都弄乱了git log
使用的颜色代码。
我尝试实现一个自定义的urwid小部件,希望它可以不使用颜色代码,但行为没有任何不同。
我考虑将输出的颜色从git log
移到我的包装器中,但是使用--graph
选项是不可能的。
颜色的直接传递适用于普通的打印语句,但是我不想重新发明窗口管理,输入处理,重新设置大小的识别,而且我不知道其他什么。
如何停止烦扰或诅咒触摸颜色代码?
MWE:
model.py
:
#!/usr/bin/env python
import subprocess
class LogModel():
encoding = "utf-8"
cmd = ["git", "log", "--color", "--graph", "--pretty=format:%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset", "--abbrev-commit"]
def get_lines(self):
p = subprocess.run(self.cmd, stdout=subprocess.PIPE, check=True, encoding=self.encoding)
out = p.stdout
return out.splitlines()
if __name__ == '__main__':
log = LogModel()
for ln in log.get_lines():
print(ln)
(git日志格式的信用为here)
main_urwid.py
:
#!/usr/bin/env python
import urwid
import model
class MyText(urwid.Widget):
_sizing = frozenset(['flow'])
def __init__(self, text):
super().__init__()
self.text = text.encode("utf-8")
def render(self, size, focus=False):
(maxcol,) = size
return urwid.TextCanvas([self.text], maxcol=maxcol, check_width=False)
def rows(self, size, focus=False):
return 1
class LogView(urwid.ListBox):
def __init__(self, log_model):
widgets = [self.create_line_widget(ln) for ln in log_model.get_lines()]
body = urwid.SimpleFocusListWalker(widgets)
super().__init__(body)
def create_line_widget(self, ln):
#return urwid.Text(ln, wrap=urwid.CLIP)
return MyText(ln)
class App():
palette = []
def __init__(self):
self.view = LogView(model.LogModel())
def run(self):
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
def unhandled_input(self, k):
if k == "q":
raise urwid.ExitMainLoop()
if __name__ == '__main__':
a = App()
a.run()
main_curses.py
:
#!/usr/bin/env python
import curses
import model
def main(stdscr):
log_model = model.LogModel()
curses.use_default_colors()
stdscr.clear()
col = 0
for row, ln in enumerate(log_model.get_lines()):
stdscr.addstr(row, col, ln)
stdscr.refresh()
stdscr.getkey()
if __name__ == '__main__':
curses.wrapper(main)