如何从node.js打开终端应用程序?

mko*_*ala 24 vim terminal readline node.js coffeescript

我希望能够Vim从终端中运行的node.js程序打开,创建一些内容,保存并退出Vim,然后抓取文件的内容.

我正在尝试做这样的事情:

filename = '/tmp/tmpfile-' + process.pid

editor = process.env['EDITOR'] ? 'vi'
spawn editor, [filename], (err, stdout, stderr) ->

  text = fs.readFileSync filename
  console.log text
Run Code Online (Sandbox Code Playgroud)

但是,当它运行时,它只是挂起终端.

我也试过了exec,得到了同样的结果.

更新:

由于在readline运行的提示符下键入的命令启动了此过程,因此这很复杂.我完全将我最新版本的相关部分提取到文件中.这是完整的:

{spawn} = require 'child_process'
fs = require 'fs'
tty = require 'tty'
rl = require 'readline'

cli = rl.createInterface process.stdin, process.stdout, null
cli.prompt()

filename = '/tmp/tmpfile-' + process.pid

proc = spawn 'vim', [filename]

#cli.pause()
process.stdin.resume()

indata = (c) ->
    proc.stdin.write c
process.stdin.on 'data', indata

proc.stdout.on 'data', (c) ->
    process.stdout.write c

proc.on 'exit', () ->
    tty.setRawMode false
    process.stdin.removeListener 'data', indata

    # Grab content from the temporary file and display it
    text = fs.readFile filename, (err, data) ->
        throw err if err?  
        console.log data.toString()

        # Try to resume readline prompt
        cli.prompt()
Run Code Online (Sandbox Code Playgroud)

它的工作方式如上所示,它显示几秒钟的提示,然后启动到Vim,但TTY搞砸了.我可以编辑和保存文件,并正确打印内容.退出时还有一堆垃圾打印到终端,之后Readline功能被破坏(没有向上/向下箭头,没有Tab完成).

如果我取消注释该cli.pause()行,那么Tim在Vim中是正常的,但我陷入了插入模式,并且该Esc键不起作用.如果我点击Ctrl-C它退出子进程和父进程.

Ili*_*nko 41

只是从主进程继承stdio.

var editor = process.env.EDITOR || 'vi';

var child = child_process.spawn(editor, ['/tmp/somefile.txt'], {
    stdio: 'inherit'
});

child.on('exit', function (e, code) {
    console.log("finished");
});
Run Code Online (Sandbox Code Playgroud)

更多选项:http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

  • 这似乎是一个更新,更简单的答案! (4认同)

log*_*yth 11

更新:我的答案在创建时应用,但对于现代版本的Node,请查看其他答案.

首先,你对spawn的使用是不正确的.这是文档.http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn

您的示例代码使您看起来希望vim自动弹出并接管终端,但它不会.需要记住的重要一点是,即使您可能会生成一个进程,也需要确保进程中的数据通过终端进行显示.

在这种情况下,您需要从stdin获取数据并将其发送到vim,您需要通过vim输出数据并将其设置到终端,否则您将看不到任何内容.您还需要将tty设置为原始模式,否则node将拦截某些键序列,因此vim将无法正常运行.

接下来,不要执行readFileSync.如果你遇到一个你认为需要使用同步方法的情况,那么很可能,你做错了什么.

这是我放在一起的一个简单例子.我不能保证它在每一个案例中都有效,但它应该涵盖大多数情况.

var tty = require('tty');
var child_process = require('child_process');
var fs = require('fs');

function spawnVim(file, cb) {
  var vim = child_process.spawn( 'vim', [file])

  function indata(c) {
    vim.stdin.write(c);
  }
  function outdata(c) {
    process.stdout.write(c);
  }

  process.stdin.resume();
  process.stdin.on('data', indata);
  vim.stdout.on('data', outdata);
  tty.setRawMode(true);

  vim.on('exit', function(code) {
    tty.setRawMode(false);
    process.stdin.pause();
    process.stdin.removeListener('data', indata);
    vim.stdout.removeListener('data', outdata);

    cb(code);
  });
}

var filename = '/tmp/somefile.txt';

spawnVim(filename, function(code) {
  if (code == 0) {
    fs.readFile(filename, function(err, data) {
      if (!err) {
        console.log(data.toString());
      }
    });
  }
});
Run Code Online (Sandbox Code Playgroud)

更新

我见.我不认为readline与你想要的所有这些兼容.问题在于,当您创建接口时,节点类型假定它将从该点向前完全控制该流.当我们将该数据重定向到vim时,readline仍然存在处理按键,但vim也在做同样的事情.

我看到的唯一方法是cli在启动vim之前从界面手动禁用所有内容.

在您生成进程之前,我们需要关闭接口,不幸的是手动删除了按键侦听器,因为至少在此刻,节点不会自动删除它.

process.stdin.removeAllListeners 'keypress'
cli.close()
tty.setRawMode true
Run Code Online (Sandbox Code Playgroud)

然后在进程'exit'回调中,您需要再次调用createInterface.