[英]Python raw_input() replacement that uses a configurable text editor
I'm trying to implement a replacement for raw_input() that would use a configurable text editor like vim as the interface to to the user. 我正在尝试实现raw_input()的替代品,该替代品将使用诸如vim之类的可配置文本编辑器作为用户界面。
The ideal workflow would be like this: 理想的工作流程如下:
If you're familiar with git, this is the experience when using git commit
, where the editor is configured via core.editor . 如果您熟悉git,这就是使用
git commit
时的经验,该编辑器是通过core.editor配置的。 Other utilities like crontab -e
also do this. 其他实用程序,例如
crontab -e
也可以这样做。
Ultimately, I would like this my_raw_input() function to also take an optional string w/ the default input contents, which the user could then edit. 最终,我希望my_raw_input()函数也可以使用带有默认输入内容的可选字符串,然后用户可以对其进行编辑。
-
command-line parameter to read from stdin, but nothing to write to stdout with :w
. -
命令行参数,从标准输入读取,但是没有写入到标准输出与:w
。 Is this possible? 这可能吗?
Good answers so far. 到目前为止,很好的答案。 I also found the mecurial code that's doing the same thing.
我还发现了做相同事情的商业代码 。 I also came up with an example that works from looking at the crontab code , but it looks like it's needlessly complicated compared to some of the responses.
我还想出了一个可以通过查看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')
You write the data to a temporary file, and then read it when the editor returns. 您将数据写入一个临时文件,然后在编辑器返回时读取它。 If you run
git commit
you'll notice that git is doing the same thing. 如果您运行
git commit
,则会注意到git在做同样的事情。
There is no extra step to starting a program interactively, as long as the child process has stdin
and stdout
wired to a terminal it will be interactive. 只要子进程已将
stdin
和stdout
连接到终端,就无需交互启动程序,无需交互操作。
There is a gotcha with working with editors -- many of them will save files by writing a temporary file in the same directory and moving it over the old file. 与编辑器打交道有一个陷阱-他们中的许多人将通过在同一目录中写入临时文件并将其移到旧文件上来保存文件。 This makes the save operation completely atomic (ignoring that the power might go out) but means that we have to re-open the temporary file after the editor runs, since our old file handle will point to a file that is no longer part of the file system (but it's still on disk).
这使保存操作完全原子化(忽略电源可能会耗尽),但意味着我们必须在编辑器运行后重新打开临时文件,因为旧文件句柄将指向不再属于该文件的文件。文件系统(但仍在磁盘上)。
This gotcha means that we can't use TemporaryFile
or NamedTemporaryFile
, we have to use a lower-level facility so we can close the file descriptor and re-open the file without deleting it. 这个陷阱意味着我们不能使用
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)
The Git sample code is so complicated because it's not using a nice high-level library like Python's subprocess
module. Git示例代码非常复杂,因为它没有使用像Python的
subprocess
模块这样的高级库。 If you read the subprocess
module source code, big chunks of it will look like the linked Git source code (except written in Python instead of C). 如果您阅读了
subprocess
模块的源代码,则其中的大块块看起来就像链接的Git源代码(用Python代替C编写的除外)。
You would have to create a temporary file name, for the editor to store its stuff in. You could use tempfile.mkstemp()
for that. 您必须创建一个临时文件名,以便编辑器将其内容存储在其中。您可以使用
tempfile.mkstemp()
。 If you want to put some contents in that file, you can do that. 如果要在该文件中放入一些内容,则可以这样做。
For running the command, subprocess.check_call()
seems like the correct tool for the job, since python waits until this command returns, and raises an exception when the subprocess fails. 对于运行命令,
subprocess.check_call()
似乎是该作业的正确工具,因为python等待该命令返回,并在子进程失败时引发异常。 Roughly: 大致:
import os
import tempfile
import subprocess
def my_raw_input(default=''):
tf, tn = tempfile.mkstemp()
os.close(tf)
with open(tn) as tf:
tf.write(default)
rv = subprocess.check_call(['emacs', tn])
with open(tn) as f:
data = f.read()
os.unlink(tn)
return data
You can of course customize which editor to use, et cetera. 当然,您可以自定义要使用的编辑器等等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.