如何在终端中实现表单?
How to implement forms in a terminal?
我写了很多 bash/zsh/nodejs 脚本,并希望允许一个选项以基于终端的形式交互式地指定一些选项。
例如,假设我 运行 一个像这样的程序:
foo -name=test -dir=/tmp -output=tmp/it.txt
我希望能够显示将这些选项作为默认值的表单,并且可能在列表中包含我可以选择的其他值。
是否有一些已经存在的方法可以做到这一点?
我认为如果我可以在某些 json 中指定这些选项,然后将它们传递给启动我的程序的程序,那就太好了,
例如,在名为 args.json
的文件中使用 json
{
"program": "foo",
"args": {
"name": "test",
"dir": "/tmp",
"output": "tmp/it.txt"
}
}
我可以运行
form_runner args.json
它会显示一个表格,让我在终端中以交互方式填写表格,然后点击 enter
,它会 运行 程序。
如果你想在纯 nodejs 中完成,使用 https://github.com/chjj/blessed 会很容易。
如果你想用 bash 来做,dialog or zenity(需要 X)是一个选项。
下面是使用blessed的示例程序。你可以 运行 它与 npm install blessed
和 node the_script.js args.json
.
var blessed = require('blessed'), fs = require('fs'), child_process = require('child_process');
const TITLE_PROG="program:";
fs.readFile(process.argv[2], function(err,data){
var js = JSON.parse(data)
var screen = blessed.screen({
autoPadding: true,
smartCSR: true
});
var form = blessed.form({
parent: screen,
width: 60,
height: 4,
keys: true
});
blessed.text({
parent: form,
fg: 'cyan',
content: TITLE_PROG
})
var prog = blessed.textbox({
parent: form,
name:'program',
inputOnFocus: true,
value: js['program'],
left: TITLE_PROG.length + 1
})
var texts = Object.keys(js['args']).forEach(function(key,index){
blessed.text({
parent: form,
top: index + 1,
content: key + ':',
fg:'green'
})
blessed.textbox({
parent: form,
inputOnFocus: true,
name: key,
value: js['args'][key],
top: index + 1,
left: key.length + 2
})
})
form.on('submit', function(data){
screen.leave();
var prog = data['program']
delete data['program']
var cmd = prog + ' ' + Object.keys(data).map(function(key){return '-' + key + ' "' + data[key] + '"'}).join(' ')
child_process.exec(cmd,function(error,stdout,stderr){
screen.leave();
console.log('stdout: ' + stdout)
console.log('stderr: ' + stderr)
if(error !== null){
console.log('error: ' + error)
process.exit(error.code);
}
process.exit(0);
})
})
screen.key(['enter'], function(){
form.submit();
});
screen.key(['escape','C-c'], function(){
screen.leave();
process.exit(0);
});
prog.focus()
screen.render();
})
我写了很多 bash/zsh/nodejs 脚本,并希望允许一个选项以基于终端的形式交互式地指定一些选项。
例如,假设我 运行 一个像这样的程序:
foo -name=test -dir=/tmp -output=tmp/it.txt
我希望能够显示将这些选项作为默认值的表单,并且可能在列表中包含我可以选择的其他值。
是否有一些已经存在的方法可以做到这一点?
我认为如果我可以在某些 json 中指定这些选项,然后将它们传递给启动我的程序的程序,那就太好了,
例如,在名为 args.json
{
"program": "foo",
"args": {
"name": "test",
"dir": "/tmp",
"output": "tmp/it.txt"
}
}
我可以运行
form_runner args.json
它会显示一个表格,让我在终端中以交互方式填写表格,然后点击 enter
,它会 运行 程序。
如果你想在纯 nodejs 中完成,使用 https://github.com/chjj/blessed 会很容易。
如果你想用 bash 来做,dialog or zenity(需要 X)是一个选项。
下面是使用blessed的示例程序。你可以 运行 它与 npm install blessed
和 node the_script.js args.json
.
var blessed = require('blessed'), fs = require('fs'), child_process = require('child_process');
const TITLE_PROG="program:";
fs.readFile(process.argv[2], function(err,data){
var js = JSON.parse(data)
var screen = blessed.screen({
autoPadding: true,
smartCSR: true
});
var form = blessed.form({
parent: screen,
width: 60,
height: 4,
keys: true
});
blessed.text({
parent: form,
fg: 'cyan',
content: TITLE_PROG
})
var prog = blessed.textbox({
parent: form,
name:'program',
inputOnFocus: true,
value: js['program'],
left: TITLE_PROG.length + 1
})
var texts = Object.keys(js['args']).forEach(function(key,index){
blessed.text({
parent: form,
top: index + 1,
content: key + ':',
fg:'green'
})
blessed.textbox({
parent: form,
inputOnFocus: true,
name: key,
value: js['args'][key],
top: index + 1,
left: key.length + 2
})
})
form.on('submit', function(data){
screen.leave();
var prog = data['program']
delete data['program']
var cmd = prog + ' ' + Object.keys(data).map(function(key){return '-' + key + ' "' + data[key] + '"'}).join(' ')
child_process.exec(cmd,function(error,stdout,stderr){
screen.leave();
console.log('stdout: ' + stdout)
console.log('stderr: ' + stderr)
if(error !== null){
console.log('error: ' + error)
process.exit(error.code);
}
process.exit(0);
})
})
screen.key(['enter'], function(){
form.submit();
});
screen.key(['escape','C-c'], function(){
screen.leave();
process.exit(0);
});
prog.focus()
screen.render();
})