我正在尝试实现raw_input()的替换,它将使用像vim这样的可配置文本编辑器作为用户的接口.
理想的工作流程如下:
如果您熟悉git,这是使用时的体验git commit
,其中编辑器是通过core.editor配置的.其他公用事业crontab -e
也这样做.
最后,我希望my_raw_input()函数也可以使用一个可选字符串w /默认输入内容,然后用户可以编辑它.
-
命令行参数可以从stdin中读取,但是没有要写入stdout的内容:w
.这可能吗?
到目前为止答案很好.我还发现了做同样事情的mecurial代码.我还提出了一个从查看crontab代码开始工作的示例,但与某些响应相比,它看起来像是不必要的复杂.
#!/usr/bin/python
import os
import tempfile
def raw_input_editor(default=None, editor=None):
''' like the built-in raw_input(), except that it uses a visual
text editor for ease of editing. Unline raw_input() it can also
take a default value. '''
editor = editor or get_editor()
with tempfile.NamedTemporaryFile(mode='r+') as tmpfile:
if default:
tmpfile.write(default)
tmpfile.flush()
child_pid = os.fork()
is_child = child_pid == 0
if is_child:
os.execvp(editor, [editor, tmpfile.name])
else:
os.waitpid(child_pid, 0)
tmpfile.seek(0)
return tmpfile.read().strip()
def get_editor():
return (os.environ.get('VISUAL')
or os.environ.get('EDITOR')
or 'vi')
if __name__ == "__main__":
print raw_input_editor('this is a test')
Run Code Online (Sandbox Code Playgroud)
您将数据写入临时文件,然后在编辑器返回时读取它.如果你运行git commit
你会注意到git正在做同样的事情.
没有额外的步骤以交互方式启动程序,只要子进程具有stdin
并stdout
连接到终端,它将是交互式的.
有一个与编辑器合作的问题 - 他们中的许多人将通过在同一目录中写入临时文件并将其移动到旧文件来保存文件.这使得保存操作完全原子化(忽略电源可能会消失),但意味着我们必须在编辑器运行后重新打开临时文件,因为我们的旧文件句柄将指向一个不再属于该文件的文件文件系统(但它仍在磁盘上).
这个问题意味着我们不能使用TemporaryFile
或者NamedTemporaryFile
我们必须使用较低级别的工具,因此我们可以关闭文件描述符并重新打开文件而不删除它.
import tempfile
import subprocess
import os
def edit(data):
fdes = -1
path = None
fp = None
try:
fdes, path = tempfile.mkstemp(suffix='.txt', text=True)
fp = os.fdopen(fdes, 'w+')
fdes = -1
fp.write(data)
fp.close()
fp = None
editor = (os.environ.get('VISUAL') or
os.environ.get('EDITOR') or
'nano')
subprocess.check_call([editor, path])
fp = open(path, 'r')
return fp.read()
finally:
if fp is not None:
fp.close()
elif fdes >= 0:
os.close(fdes)
if path is not None:
try:
os.unlink(path)
except OSError:
pass
text = edit('Hello, World!')
print(text)
Run Code Online (Sandbox Code Playgroud)
Git示例代码非常复杂,因为它没有像Python的subprocess
模块那样使用漂亮的高级库.如果您阅读subprocess
模块源代码,它的大块将看起来像链接的Git源代码(除了用Python而不是C编写).