Независимо от того насколько большая ваша любовь к командной строке, согласитесь, что простой и удобный интерфейс консоли, поддержка истории, авто дополнение, простые команды весьма впечатляют. Не вдаваясь в дисскусию о преимуществах и недостатках «темноты», хочу представить на суд Хабра-сообщества свою маленькую поделку из мира Node.js, главной задачей которой является улучшение жизни разработчика, который решился написать консольную утилиту.
Cline — обзор
Cline это маленькая библиотека базирована на нодовском readline модуле, таким образом у нас есть поддержка истории, авто дополнение, опрашивание пользователя и, с моей легкой руки, дополнения в виде маски на ввод пароля, возможности слушать ввод пользователя в виде отдельных команд описанных, как простые или регулярные выражения, вывода справки, упрощенной работы с историей, интерактивного режима.
Со всем этим создание приложения, которое после запуска буде ждать ввода команд от пользователя упрощается в разы.
Пример
Для тех, кому достаточно кода для понимания возможностей библиотеки, вот пример:
var cli = require('cline')();
cli.command('start', 'starts program', function () {
cli.password('Password:', function (str) {
console.log(str);
})
});
cli.command('stop', function () {
cli.confirm('Sure?', function (ok) {
if (ok) {
console.log('done');
}
})
});
cli.command('{string}', '', {string: '[A-Za-z]+'});
cli.command('{number}', '', {number: '\d+'});
cli.on('command', function (input, cmd) {
if ('start' !== cmd && 'stop' != cmd) {
cli.prompt('More details on ' + cmd + ':');
}
});
cli.history(['start', 'stop']);
cli.interact('>');
cli.on('history', function (item) {
console.log('New history item ' + item);
});
cli.on('close', function () {
console.log('History:' + cli.history());
process.exit();
});
Использование
Cline использует в своей работе Interface или что-то на него похожее, если у вас есть своя реализация Interface вы можете передать ее как параметр (поддержка тестирования):
var cli = require('cline')(myInterface);
Центральной возможностью cline является добавление команд.
cli.command(expression, description, parameters, callback);
expression – это выражение, которое мы ждем от пользователя, может вмещать динамические параметры, например, kill {id}, тут id – имя динамического параметра, о нем я напомню позже.
description – дополнительное объяснение для команды, используется для генерации справки.
parameters – объект, содержащий имена динамических параметров упомянутых в выражениях, как ключи, и регулярные выражения, как значения. Например, {id: '\d+'} – id будет значить любое число.
callback – функция, которая будет вызвана, когда пользователь введет строку соответствующую expression. Вызывается она с двумя аргументами: строка от пользователя и объект со значениями динамических параметров.
cli.command('kill {id}', 'kill task by id', {id: '\d{1,3}'}, function (input, args) {
console.log(input) // kill 12
console.log(args.id) // 12
});
Все параметры cli.command, кроме expression, необязательны, при чем можно пропускать как угодно.
cli.command(expression, description, callback);
cli.command(expression, parameters, callback);
cli.command(expression, description);
cli.command(expression, parameters);
Все эти варианты абсолютно валидны.
Взаимодействие с пользователем
Ожидать от пользователя можно 3 вещи:
1.Ввод
cli.prompt('Your turn:');
2.Подтвержение
cli.confirm('Sure?', function (ok) {});
3.Пароль
cli.password('Password:', ‘*’, function (pass) {});
А также можно просто перейти в интерактивный режим
cli.interact('>');
В таком режиме, библиотека ожидает ввода от пользователя и пытается каждую строку проинтерпретировать как команду, ища совпадения в списке описанных команд и после исполнения функции-слушателя на команде, опять ожидает ввода. Повторный вызов интерактивного режима просто изменит строку приглашения.
Системные команды, история и события
Без каких-либо дополнительных манипуляций при использовании cline, сразу доступны 3 команды:
clear или c – очищает экран
help или ? – выводит справку
exit или q – выход
С историей все просто, никаких файлов или потоков, просто заполняем историю так:
cli.history(['start', 'stop']);
порядок элементов соответствует давности, первый элемент в списке будет самым старым.
Ну а прочитать историю можно так:
cli.history();
получим список. Еще можно подписаться на событие добавления элемента в историю. Ну, а дальше вам решать, как этот список сохранять.
Так как cline наследует EventEmitter, тут широко используется событийная модель, вы можете подписываться на такие события:
close – пользователь вызвал команду выхода или остановил процесс использовав Ctrl + C
history – при добавлении нового элемента в историю, новый элемент передается слушателю как параметр.
command – ввод пользователя совпал из одной из команд (кроме системных), строка от пользователя и выражение команды передаются как параметр слушателю.
На последок
Если вы не хотите тихо молчать, когда пользователь вводит что-то, кроме команд которые вы описали, делаем так:
cli.command('*', function (input) {
console.log(input + ' is not correct');
cli.usage();
});
Большое спасибо за внимание, надеюсь вам пригодится cline или может быть даже вдохновит на написание своей консольной утилиты или хотя бы на форк в гитхабе.
P.S. Отдельное спасибо НЛО за инвайт.
Автор: becevka