Pull to refresh

Cline и создание интерактивного приложения командной строки

Reading time 4 min
Views 5.8K
Независимо от того насколько большая ваша любовь к командной строке, согласитесь, что простой и удобный интерфейс консоли, поддержка истории, авто дополнение, простые команды весьма впечатляют. Не вдаваясь в дисскусию о преимуществах и недостатках «темноты», хочу представить на суд Хабра-сообщества свою маленькую поделку из мира 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. Отдельное спасибо НЛО за инвайт.
Tags:
Hubs:
+6
Comments 3
Comments Comments 3

Articles