Come posso aprire un’applicazione terminale da node.js?

Mi piacerebbe essere in grado di aprire Vim dal programma node.js in esecuzione nel terminale, creare del contenuto, salvare e uscire da Vim , e quindi prendere il contenuto del file.

Sto provando a fare qualcosa del genere:

 filename = '/tmp/tmpfile-' + process.pid editor = process.env['EDITOR'] ? 'vi' spawn editor, [filename], (err, stdout, stderr) -> text = fs.readFileSync filename console.log text 

Tuttavia, quando viene eseguito, si blocca semplicemente il terminale.

Ho anche provato con exec e ottenuto lo stesso risultato.

Aggiornare:

Ciò è complicato dal fatto che questo processo viene avviato da un comando digitato a un prompt con readline in esecuzione. Ho completamente estrapolato le parti rilevanti della mia ultima versione in un file. Eccolo nella sua interezza:

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

Il modo in cui funziona come mostrato sopra è che mostra un prompt per un paio di secondi, quindi viene avviato in Vim, ma il TTY è incasinato. Posso modificare, e salvare il file, e il contenuto è stampato correttamente. C’è anche un po ‘di junk stampato sul terminale in uscita, e la funzionalità Readline è rotta dopo (nessuna freccia su / giù, nessun tab).

Se cli.pause() la cli.pause() , il TTY è OK in Vim, ma sono bloccato in modalità inserimento e il tasto Esc non funziona. Se premo Ctrl-C si chiude il processo figlio e genitore.

Aggiornamento: la mia risposta è stata applicata nel momento in cui è stata creata, ma per le versioni moderne del nodo, guarda questa altra risposta .

Prima di tutto, l’utilizzo di spawn non è corretto. Ecco i documenti. http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn

Il tuo codice di esempio fa sembrare che ti aspetti che vim compaia automaticamente e prenda il controllo del terminale, ma non lo farà. La cosa importante da ricordare è che anche se è ansible generare un processo, spetta a te accertarti che i dati del processo raggiungano il tuo terminale per la visualizzazione.

In questo caso, devi prendere i dati da stdin e inviarli a vim, e devi prendere i dati in uscita da vim e metterli sul tuo terminale, altrimenti non vedrai nulla. È inoltre necessario impostare la tty in modalità raw, altrimenti il ​​nodo intercetterà alcune sequenze di tasti, quindi vim non si comporterà correttamente.

Quindi, non leggere readFileSync. Se ti imbatti in un caso in cui ritieni di dover utilizzare un metodo di sincronizzazione, è probabile che tu stia facendo qualcosa di sbagliato.

Ecco un rapido esempio che ho messo insieme. Non posso garantire che funzioni in ogni singolo caso, ma dovrebbe coprire la maggior parte dei casi.

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

Aggiornare

Vedo. Non penso che readline sia compatibile con tutto ciò che vorresti sfortunatamente. Il problema è che quando createInterface, il tipo di nodo presuppone che avrà il pieno controllo su quel stream da quel punto in poi. Quando reindirizziamo quei dati a Vim, readline è ancora lì che elabora i tasti, ma anche Vim sta facendo la stessa cosa.

L’unica cosa che vedo è disabilitare manualmente tutto dall’interfaccia cli prima di avviare vim.

Poco prima di generare il processo, è necessario chiudere l’interfaccia e, sfortunatamente, rimuovere manualmente il listener di keypress perché, almeno al momento, il nodo non lo rimuove automaticamente.

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

Quindi, nel processo di richiamata di “uscita”, sarà necessario chiamare di nuovo createInterface.

Basta ereditare stdio dal processo principale.

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

altre opzioni: http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options