如何从node.js打开终端应用程序? [英] How do I open a terminal application from node.js?

查看:1035
本文介绍了如何从node.js打开终端应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我试图做这样的事情:

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

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

text = fs.readFileSync filename
console.log text





我也尝试过 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

#从临时文件获取内容并显示
text = fs.readFile filename ,(err,data) - >
throw err if err?
console.log data.toString()

#尝试恢复readline提示
cli.prompt()

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



如果我取消注释 cli.pause()行,然后TTY在Vim中确定,但我陷入插入模式,并且 Esc 键不工作。如果我点击 Ctrl-C ,它会退出子进程和父进程。

解决方案

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



您的示例代码似乎希望vim自动弹出并接管终端,但不会。重要的是要记住,即使你可能产生一个过程,它是由你来确保来自过程的数据通过到您的终端显示。



在这种情况下,您需要从stdin中获取数据并将其发送到vim,您需要通过vim获取数据输出并将其设置到终端,否则您将看不到任何内容。你还需要将tty设置为raw模式,否则节点将拦截一些键序列,所以vim将不会正常工作。



接下来,不要做readFileSync 。如果你遇到一个case,你认为你需要使用同步方法,那么很可能是你做错了。



这里是一个简单的例子。

  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 b $ b 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());
}
});
}
}

更新



我看见。我不认为readline与所有这一切兼容,因为你会不幸的是。问题是,当你创建接口时,节点种类假设它将完全控制从那个点向前的流。当我们将数据重定向到vim时,readline仍然存在处理按键,但vim也在做同样的事情。



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



在生成进程之前,接口,并且不幸的是手动删除了按键监听器,因为至少目前节点不会自动删除它。

  .stdin.removeAllListeners'keypress'
cli.close()
tty.setRawMode true

然后在进程退出回调中,您将需要再次调用createInterface。


I would like to be able to open Vim from node.js program running in the terminal, create some content, save and exit Vim, and then grab the contents of the file.

I'm trying to do something like this:

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

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

  text = fs.readFileSync filename
  console.log text

However, when this runs, it just hangs the terminal.

I've also tried it with exec and got the same result.

Update:

This is complicated by the fact that this process is launched from a command typed at a prompt with readline running. I completely extracted the relevant parts of my latest version out to a file. Here is it in its entirety:

{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()

The way it works as show above, is that it shows a prompt for a couple of seconds, and then launches in to Vim, but the TTY is messed up. I can edit, and save the file, and the contents are printed correctly. There is a bunch of junk printed to terminal on exit as well, and Readline functionality is broken afterward (no Up/Down arrow, no Tab completion).

If I uncomment the cli.pause() line, then the TTY is OK in Vim, but I'm stuck in insert mode, and the Esc key doesn't work. If I hit Ctrl-C it quits the child and parent process.

解决方案

First off, your usage of spawn isn't correct. Here are the docs. http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn

Your sample code makes it seem like you expect vim to automatically pop up and take over the terminal, but it won't. The important thing to remember is that even though you may spawn a process, it is up to you to make sure that the data from the process makes it through to your terminal for display.

In this case, you need to take data from stdin and send it to vim, and you need to take data output by vim and set it to your terminal, otherwise you won't see anything. You also need to set the tty into raw mode, otherwise node will intercept some of the key sequences, so vim will not behave properly.

Next, don't do readFileSync. If you come upon a case where you think you need to use a sync method, then chances are, you are doing something wrong.

Here's a quick example I put together. I can't vouch for it working in every single case, but it should cover most cases.

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());
      }
    });
  }
});

Update

I seeee. I don't think readline is as compatible with all of this as you would like unfortunately. The issue is that when you createInterface, node kind of assumes that it will have full control over that stream from that point forward. When we redirect that data to vim, readline is still there processing keypresses, but vim is also doing the same thing.

The only way around this that I see is to manually disable everything from the cli interface before you start vim.

Just before you spawn the process, we need to close the interface, and unfortunately manually remove the keypress listener because, at least at the moment, node does not remove it automatically.

process.stdin.removeAllListeners 'keypress'
cli.close()
tty.setRawMode true

Then in the process 'exit' callback, you will need to call createInterface again.

这篇关于如何从node.js打开终端应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆