¿Cómo abro una aplicación de terminal desde node.js?
vim coffeescript (2)
Me gustaría poder abrir Vim
desde el programa node.js que se ejecuta en el terminal, crear contenido, guardar y salir de Vim
, y luego capturar el contenido del archivo.
Estoy tratando de hacer algo como esto:
filename = ''/tmp/tmpfile-'' + process.pid
editor = process.env[''EDITOR''] ? ''vi''
spawn editor, [filename], (err, stdout, stderr) ->
text = fs.readFileSync filename
console.log text
Sin embargo, cuando esto se ejecuta, simplemente se bloquea el terminal.
También lo he probado con exec
y obtuve el mismo resultado.
Actualizar:
Esto se complica por el hecho de que este proceso se inicia desde un comando escrito en un indicador con línea de readline ejecución. Extraje completamente las partes relevantes de mi última versión en un archivo. Aquí está en su totalidad:
{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()
La forma en que funciona como se muestra arriba, es que muestra un aviso durante un par de segundos y luego se inicia en Vim, pero el TTY está desordenado. Puedo editar y guardar el archivo, y los contenidos se imprimen correctamente. También hay un montón de basura impresa en el terminal al salir, y la funcionalidad de Readline se interrumpe después (no hay flecha arriba / abajo, no se completa la pestaña).
Si cli.pause()
el comentario de la línea cli.pause()
, el TTY está bien en Vim, pero estoy bloqueado en el modo de inserción y la Esc
no funciona. Si presiono Ctrl-C
se cierra el proceso hijo y padre.
Simplemente heredar stdio del proceso principal.
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");
});
más opciones: http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
Actualización: mi respuesta se aplicó en el momento en que se creó, pero para las versiones modernas de Node, vea esta otra respuesta .
En primer lugar, su uso de engendro no es correcto. Aquí están los documentos. http://nodejs.org/docs/latest/api/child_processes.html#child_process.spawn
Su código de muestra hace que parezca que espera que vim aparezca automáticamente y se haga cargo de la terminal, pero no lo hará. Lo importante a recordar es que, aunque puede generar un proceso, depende de usted asegurarse de que los datos del proceso lleguen a su terminal para su visualización.
En este caso, debe tomar los datos de la entrada estándar y enviarlos a vim, y debe tomar los datos de salida de vim y establecerlos en su terminal, de lo contrario no verá nada. También debe configurar tty en modo raw, de lo contrario el nodo interceptará algunas de las secuencias de teclas, por lo que vim no se comportará correctamente.
A continuación, no haga readFileSync. Si te encuentras con un caso en el que crees que necesitas usar un método de sincronización, es probable que estés haciendo algo mal.
Aquí hay un ejemplo rápido que junté. No puedo garantizar que funcione en todos los casos, pero debería cubrir la mayoría de los casos.
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());
}
});
}
});
Actualizar
Yo veo No creo que readline sea tan compatible con todo esto como desearías desafortunadamente. El problema es que cuando crea Interfaz, el nodo asume que tendrá control total sobre esa corriente desde ese punto en adelante. Cuando redirigimos esos datos a vim, readline todavía está procesando pulsaciones de teclas, pero vim también está haciendo lo mismo.
La única forma de evitar esto es ver que se deshabilite manualmente todo desde la interfaz cli
antes de iniciar vim.
Justo antes de generar el proceso, debemos cerrar la interfaz y, lamentablemente, eliminar manualmente el oyente de pulsación de tecla porque, al menos en este momento, el nodo no lo elimina automáticamente.
process.stdin.removeAllListeners ''keypress''
cli.close()
tty.setRawMode true
Luego, en el proceso de ''salir'' de la devolución de llamada, deberá llamar a createInterface nuevamente.