Подтвердить что ты не робот

Как открыть приложение терминала из node.js?

Мне хотелось бы открыть 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

Однако, когда это выполняется, он просто висит на терминале.

Я также пробовал его с exec и получил тот же результат.

Update:

Это осложняется тем, что этот процесс запускается из команды, введенной в командной строке с 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()

То, как он работает, как показано выше, заключается в том, что он показывает приглашение на пару секунд, а затем запускается в Vim, но TTY перепутано. Я могу редактировать и сохранять файл, и содержимое печатается правильно. На выходе также есть куча нежелательной печати, которая также выводится на терминал, а после этого функция Breakline прерывается (стрелка вверх/вниз, не заполняется вкладкой).

Если я раскомментирую строку cli.pause(), тогда TTY в порядке, в Vim, но я застрял в режиме вставки, а ключ Esc не работает. Если я ударил Ctrl-C, он прекратит дочерний процесс и родительский процесс.

4b9b3361

Ответ 1

Обновление: Мой ответ был применен в то время, когда он был создан, но для современных версий 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());
      }
    });
  }
});

Обновление

Я вижу. Я не думаю, что readline совместим со всем этим, как вы хотели бы, к сожалению. Проблема в том, что когда вы создаете интерфейс, node предполагает, что он будет иметь полный контроль над этим потоком с этой точки вперед. Когда мы перенаправляем эти данные в vim, readline все еще обрабатывает нажатия клавиш, но vim также делает то же самое.

Единственный способ, который я вижу, - это вручную отключить все из интерфейса cli, прежде чем вы начнете vim.

Прежде чем вы начнете процесс, нам нужно закрыть интерфейс и, к сожалению, вручную удалить прослушиватель клавиатуры, потому что, по крайней мере, на данный момент node не удаляет его автоматически.

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

Затем в обратном вызове "exit" вам нужно будет снова вызвать createInterface.