我目前正在Rust中构建一个控制台应用程序,该应用程序可用于轻松构建提交。考虑一半git add -i
具有更好的用户界面,一半系统可以轻松一致地构建高质量的提交消息。
目前,我有一个可以添加和提交消息的应用程序,它很棒。但是,由于我经常使用git add
的patch
功能,我想将其添加到我的应用程序中。
正如我现在所做的,在调用我的程序后,用户将看到一个更改文件的列表,与运行git add -i
时相同,但所有文件都在一个列表中——未跟踪的文件不会被分离出来。现在,这只是一个复选框列表,您可以使用箭头键上下移动。如果您将鼠标悬停在某个文件上,用户将可以对该文件执行操作,例如查看未暂存的更改或对其运行git add --patch
,而不是暂存整个文件。
现在,我已经让未记录的更改视图工作得很好。这是代码:
let unstaged_changes = Command::new("git")
.current_dir(&project_root)
.args(&["diff", "--"])
.args(file_name)
.stdout(Stdio::piped())
.spawn()?;
Command::new("less")
.current_dir(&project_root)
.stdin(unstaged_changes.stdout.ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "failed to get stdout")
})?)
.status()?;
我使用less
,因为不使用它会锁定终端并导致各种问题。滚动会很尴尬和不一致,如果我向上滚动太远,整个diff日志就会消失,有时它会与上面的文本合并,导致各种视觉问题。现在,也许这是我的终端的一个问题,但无论如何,都不能拥有它。使用less
完美地解决了这些问题。
我想为git add --patch
做一些类似的事情。我不能直接运行命令,因为它除了非交互式之外还会导致各种问题,也就是说,我不能将命令交给工具。
我也不能将它传递给less
,因为less
不能处理那种输入。我需要能够处理完整的补丁选项套件:
Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?
(尽管缺少了一对只出现在上下文中的情侣(。
有什么简单的工具可以做到这一点吗?我想我不介意另一个终端窗口暂时打开,只要我能在补丁完成后尽快关闭它,它就能跨平台工作。
您是否尝试过在不使用管道的情况下运行命令?
[编辑]
从文档中:您可能正在查找Command::status()
:
将命令作为子进程执行,等待其完成并收集其退出状态。
默认情况下,stdin、stdout和stderr是从父级继承的。
如果您想显式共享";您的";带子命令的stdin:
.stdin(Stdio::inherit())
您还没有说明您正在使用哪个库来管理终端。
如果您使用的是curses或为curses提供抽象的库,那么通常的方法是在调用外部命令之前离开curses模式,然后在命令完成后恢复终端状态。从链接(这是C,但Rust接口可能使用相同的名称(:
addstr("Running git");
def_prog_mode(); /* save current tty modes */
endwin(); /* restore original tty modes */
system("git add --patch"); /* run git */
addstr("donen"); /* prepare return message */
refresh(); /* restore save modes, repaint screen */
对于其他一些终端管理库,您可以查看该库在应用程序退出时如何恢复终端状态。基本上,在执行更新终端的命令之前,您希望请求执行相同的操作。
对于crossterm
,在执行命令之前运行以下内容可能就足够了:
execute!(stdout(),
terminal::LeaveAlternateScreen,
style::ResetColor,
event::DisableMouseCapture,
terminal::Clear(ClearType::All),
cursor::MoveTo(1, 1)
)?;
terminal::disable_raw_mode()?;
可能并不需要所有这些命令,尤其是当您的应用程序从未触及终端状态时。