Readline
Исходный код: lib/readline.js
Модуль readline предоставляет интерфейс для чтения данных из потока Readable (такого как process.stdin) по одной строке за раз. К нему можно получить доступ следующим образом:
const readline = require('readline'); Следующий простой пример демонстрирует базовое использование модуля readline.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('What do you think of Node.js? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
}); После вызова этого кода приложение Node.js не завершится до тех пор, пока не будет закрыт поток readline.Interface, так как интерфейс ожидает получения данных из потока input.
Класс: Interface
- Расширяет: <EventEmitter>
Экземпляры класса readline.Interface создаются с помощью метода readline.createInterface(). Каждый экземпляр связан с одним потоком input Readable и одним потоком output Writable. Поток output используется для отображения запросов на ввод пользователя, которые поступают и считываются из потока input.
Событие: 'close'
Событие 'close' генерируется при следующих обстоятельствах:
- Вызов метода
rl.close()и экземплярreadline.Interfaceотказался от управления потокамиinputиoutput; - Поток
inputполучает событие'end'; - Поток
inputполучает<ctrl>-D, сигнализируя об окончании передачи (EOT); - Поток
inputполучает<ctrl>-C, сигнализируя об окончании и отсутствии обработчика события'SIGINT'на экземпляреreadline.Interface.
Функция-обработчик вызывается без передачи аргументов.
Экземпляр readline.Interface завершается, когда генерируется событие 'close'.
Событие: 'line'
Событие 'line' генерируется всякий раз, когда поток input получает ввод по окончании строки (\n, \r, или \r\n). Обычно это происходит при нажатии пользователем клавиш <Enter>, или <Return>.
Функция-обработчик вызывается со строкой, содержащей полученную строку ввода.
rl.on('line', (input) => {
console.log(`Received: ${input}`);
}); Событие: 'pause'
Событие 'pause' генерируется при следующих обстоятельствах:
- Поток
inputприостановлен. - Поток
inputне приостановлен и получает событие'SIGCONT'. (См. события'SIGTSTP'и'SIGCONT'.)
Функция-обработчик вызывается без передачи аргументов.
rl.on('pause', () => {
console.log('Readline paused.');
}); Событие: 'resume'
Событие 'resume' генерируется всякий раз, когда поток input возобновляется.
Функция-обработчик вызывается без передачи аргументов.
rl.on('resume', () => {
console.log('Readline resumed.');
}); Событие: 'SIGCONT'
Событие 'SIGCONT' генерируется, когда процесс Node.js, ранее переведённый в фоновый режим с помощью <ctrl>-Z (т.е. SIGTSTP), возвращается в фоновый режим с помощью fg(1p).
Если поток input был приостановлен до запроса SIGTSTP, это событие не будет сгенерировано.
Функция-обработчик вызывается без передачи аргументов.
rl.on('SIGCONT', () => {
// `prompt` will automatically resume the stream
rl.prompt();
}); Событие 'SIGCONT' не поддерживается в Windows.
Событие: 'SIGINT'
Событие 'SIGINT' генерируется всякий раз, когда поток input получает ввод <ctrl>-C, обычно называемый SIGINT. Если нет обработчиков событий 'SIGINT' зарегистрированных, когда поток input получает SIGINT, то событие 'pause' будет сгенерировано.
Функция-обработчик вызывается без передачи аргументов.
rl.on('SIGINT', () => {
rl.question('Are you sure you want to exit? ', (answer) => {
if (answer.match(/^y(es)?$/i)) rl.pause();
});
}); Событие: 'SIGTSTP'
Событие 'SIGTSTP' генерируется, когда поток input получает ввод <ctrl>-Z, обычно называемый SIGTSTP. Если нет обработчиков событий 'SIGTSTP' зарегистрированных, когда поток input получает SIGTSTP, процесс Node.js будет переведён в фоновый режим.
При возобновлении программы с помощью fg(1p), будут сгенерированы события 'pause' и 'SIGCONT'. Их можно использовать для возобновления потока input.
События 'pause' и 'SIGCONT' не будут сгенерированы, если поток input был приостановлен перед переходом процесса в фоновый режим.
Функция-обработчик вызывается без передачи аргументов.
rl.on('SIGTSTP', () => {
// This will override SIGTSTP and prevent the program from going to the
// background.
console.log('Caught SIGTSTP.');
}); Событие 'SIGTSTP' не поддерживается в Windows.
rl.close()
Метод rl.close() закрывает экземпляр readline.Interface и отказывается от управления потоками input и output. При вызове генерируется событие 'close'.
Вызов rl.close() не останавливает немедленно другие события (включая 'line'), генерируемые экземпляром readline.Interface.
rl.pause()
Метод rl.pause() приостанавливает поток input, позволяя его возобновить впоследствии при необходимости.
Вызов rl.pause() не останавливает немедленно другие события (включая 'line'), генерируемые экземпляром readline.Interface.
rl.prompt([preserveCursor])
-
preserveCursor<boolean> Еслиtrue, предотвращает сброс курсора к0.
Метод rl.prompt() записывает запрошенную строку экземпляра readline.Interface в новую строку в output, чтобы предоставить пользователю новое место для ввода.
При вызове rl.prompt() возобновит поток input если он был приостановлен.
Если экземпляр readline.Interface был создан с output установленным в null или undefined, запрос не будет выведен.
rl.question(query, callback)
-
query<string> Выражение или запрос, которые будут записаны вoutput, добавленные перед запросом. -
callback<Function> Функция-обработчик, которая вызывается с вводом пользователя в ответ наquery.
Метод rl.question() отображает query записью в output, ожидает ввода пользователя в input, а затем вызывает функцию callback, передавая полученный ввод в качестве первого аргумента.
При вызове rl.question() возобновит поток input если он был приостановлен.
Если экземпляр readline.Interface был создан с output установленным в null или undefined, запрос не будет выведен.
Пример использования:
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
}); Функция callback передаваемая в rl.question() не следует стандартному шаблону приема объекта Error или null в качестве первого аргумента. Функция callback вызывается с предоставленным ответом в качестве единственного аргумента.
rl.resume()
Метод rl.resume() возобновляет поток input если он был приостановлен.
rl.setPrompt(prompt)
-
prompt<string>
Метод rl.setPrompt() устанавливает запрос, который будет записываться в output всякий раз, когда вызывается rl.prompt().
rl.write(data[, key])
Метод rl.write() запишет либо data, либо последовательность клавиш, определённую key, в output. Аргумент key поддерживается только если output это текстовый терминал TTY. См. Настройки клавиш TTY для списка комбинаций клавиш.
Если key указан, data игнорируется.
При вызове rl.write() возобновит поток input если он был приостановлен.
Если readline.Interface был создан с output, установленным в null или undefined, то data и key не записываются.
rl.write('Delete this!');
// Simulate Ctrl+u to delete the line written previously
rl.write(null, { ctrl: true, name: 'u' }); Метод rl.write() запишет данные в readline Interface's input как будто они были предоставлены пользователем.
rl[Symbol.asyncIterator]()
- Возвращает: <AsyncIterator>
Создает объект AsyncIterator, который итерируется по каждой строке в потоке ввода как строка. Этот метод позволяет асинхронную итерацию по объектам readline.Interface с помощью циклов for await...of.
Ошибки в потоке ввода не передаются.
Если цикл прерван с помощью break, throw, или return, будет вызван rl.close(). Другими словами, итерация по readline.Interface всегда полностью потребляет поток ввода.
Производительность не соответствует традиционному API событий 'line'. Используйте 'line' для приложений, чувствительных к производительности.
async function processLineByLine() {
const rl = readline.createInterface({
// ...
});
for await (const line of rl) {
// Each line in the readline input will be successively available here as
// `line`.
}
} rl.line
Текущие данные ввода, обрабатываемые узлом.
Это можно использовать при сборе ввода из потока TTY для получения текущего значения, которое было обработано до сих пор, до того, как будет выведено событие line. После того, как событие line будет выведено, это свойство будет пустой строкой.
Обратите внимание, что изменение значения во время выполнения экземпляра может иметь непредвиденные последствия, если не контролировать также rl.cursor.
Если вы не используете поток TTY для ввода, используйте событие 'line'.
Один из возможных вариантов использования:
const values = ['lorem ipsum', 'dolor sit amet'];
const rl = readline.createInterface(process.stdin);
const showResults = debounce(() => {
console.log(
'\n',
values.filter((val) => val.startsWith(rl.line)).join(' ')
);
}, 300);
process.stdin.on('keypress', (c, k) => {
showResults();
}); rl.cursor
Положение курсора относительно rl.line.
Это отслеживает, где находится текущий курсор в строке ввода при чтении ввода из потока TTY. Положение курсора определяет часть строки ввода, которая будет изменена при обработке ввода, а также колонку, в которой будет отображен терминальный курсор.
rl.getCursorPos()
- Возвращает: <Объект>
Возвращает реальное положение курсора по отношению к подсказке ввода + строке. В расчёты включены длинные строки ввода (перенос) и подсказки, занимающие несколько строк.
readline.clearLine(stream, dir[, callback])
-
stream<stream.Writable> -
dir<число>-
-1: влево от курсора -
1: вправо от курсора -
0: вся строка
-
-
callback<Функция> Вызывается по завершении операции. - Возвращает: <boolean>
false, еслиstreamхочет, чтобы вызывающий код ждал, пока будет выведено событие'drain', прежде чем продолжить запись дополнительных данных; в противном случаеtrue.
Метод readline.clearLine() очищает текущую строку заданного потока TTY в указанном направлении, определённом значением dir.
readline.clearScreenDown(stream[, callback])
-
stream<stream.Writable> -
callback<Функция> Вызывается по завершении операции. - Возвращает: <boolean>
false, еслиstreamхочет, чтобы вызывающий код ждал, пока будет выведено событие'drain', прежде чем продолжить запись дополнительных данных; в противном случаеtrue.
Метод readline.clearScreenDown() очищает заданный поток TTY с текущего положения курсора вниз.
readline.createInterface(options)
-
options<Объект>-
input<stream.Readable> Поток Readable для прослушивания. Этот параметр обязателен. -
output<stream.Writable> Поток Writable для записи данных readline. -
completer<Функция> Необязательная функция, используемая для автозаполнения Tab. -
terminal<boolean>true, если потокиinputиoutputдолжны обрабатываться как TTY и к ним должны записываться escape-коды ANSI/VT100. По умолчанию: проверяетсяisTTYв потокеoutputпри создании экземпляра. -
historySize<число> Максимальное количество сохранённых строк истории. Чтобы отключить историю, установите это значение в0. Этот параметр имеет смысл только еслиterminalустановлено вtrueпользователем или внутренним контролемoutput, в противном случае механизм кеширования истории не инициализируется. По умолчанию:30. -
prompt<строка> Строка подсказки, которую нужно использовать. По умолчанию:'> '. -
crlfDelay<число> Если задержка между\rи\nпревышаетcrlfDelayмиллисекунд, то\rи\nбудут обрабатываться как отдельный ввод по окончанию строки.crlfDelayбудет приведено к числу не меньше100. Его можно установить вInfinity, в этом случае\r, за которым следует\n, всегда будет рассматриваться как один символ новой строки (что может быть уместно для чтения файлов с разделителем строк\r\n). По умолчанию:100. -
removeHistoryDuplicates<boolean> Еслиtrue, когда новая строка ввода добавляется в список истории и дублирует более раннюю, то более ранняя строка удаляется из списка. По умолчанию:false. -
escapeCodeTimeout<число> Длительность ожиданияreadlineсимвола (при чтении неоднозначной последовательности клавиш в миллисекундах, которая может либо сформировать полную последовательность клавиш, используя прочитанный ввод, либо потребовать дополнительного ввода для завершения более длинной последовательности клавиш). По умолчанию:500.
-
Метод readline.createInterface() создаёт новый экземпляр readline.Interface.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
}); После создания экземпляра readline.Interface, наиболее частым случаем является прослушивание события 'line'.
rl.on('line', (line) => {
console.log(`Received: ${line}`);
}); Если terminal равно true для этого экземпляра, то поток output получит лучшую совместимость, если он определит свойство output.columns и выведет событие 'resize' в потоке output, если или когда столбцы изменятся (process.stdout делает это автоматически, когда это TTY).
Использование функции completer
Функция completer принимает текущую строку, введенную пользователем, в качестве аргумента и возвращает массив Array с 2 элементами:
- Массив
Arrayс соответствующими записями для автодополнения. - Подстрока, которая использовалась для соответствия.
Например: [[substr1, substr2, ...], originalsubstring].
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// Show all completions if none found
return [hits.length ? hits : completions, line];
} Функция completer может быть вызвана асинхронно, если она принимает два аргумента:
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
} readline.cursorTo(stream, x[, y][, callback])
-
stream<stream.Writable> -
x<число> -
y<число> -
callback<Функция> Вызывается после завершения операции. - Возвращает: <логическое>
falseеслиstreamжелает, чтобы вызывающий код ждал, пока событие'drain'не будет выпущено, прежде чем продолжить запись дополнительных данных; в противном случаеtrue.
Метод readline.cursorTo() перемещает курсор в указанную позицию в заданном TTY stream.
readline.emitKeypressEvents(stream[, interface])
-
stream<stream.Readable> -
interface<readline.Interface>
Метод readline.emitKeypressEvents() заставляет заданный поток Readable начать излучение событий 'keypress', соответствующих полученному вводу.
Необязательно, interface указывает экземпляр readline.Interface, для которого отключение автодополнения, когда обнаруживается вставленный в буфер ввода.
Если stream является TTY, то он должен быть в режиме raw.
Это автоматически вызывается любым экземпляром readline для своего input, если input является терминалом. Закрытие экземпляра readline не останавливает input от излучения событий 'keypress'.
readline.emitKeypressEvents(process.stdin); if (process.stdin.isTTY) process.stdin.setRawMode(true);
readline.moveCursor(stream, dx, dy[, callback])
-
stream<stream.Writable> -
dx<число> -
dy<число> -
callback<Функция> Вызывается после завершения операции. - Возвращает: <логическое>
falseеслиstreamжелает, чтобы вызывающий код ждал, пока событие'drain'не будет выпущено, прежде чем продолжить запись дополнительных данных; в противном случаеtrue.
Метод readline.moveCursor() перемещает курсор относительно его текущей позиции в заданном TTY stream.
Пример: Мини-консоль
Следующий пример демонстрирует использование класса readline.Interface для реализации небольшой командной строки:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'OHAI> '
});
rl.prompt();
rl.on('line', (line) => {
switch (line.trim()) {
case 'hello':
console.log('world!');
break;
default:
console.log(`Say what? I might have heard '${line.trim()}'`);
break;
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
}); Пример: Чтение файла потока построчно
Распространенным случаем использования readline является обработка входного файла по одной строке за раз. Самый простой способ сделать это — использовать API fs.ReadStream, а также цикл for await...of.
const fs = require('fs');
const readline = require('readline');
async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
}
}
processLineByLine(); В качестве альтернативы, можно использовать событие 'line':
const fs = require('fs');
const readline = require('readline');
const rl = readline.createInterface({
input: fs.createReadStream('sample.txt'),
crlfDelay: Infinity
});
rl.on('line', (line) => {
console.log(`Line from file: ${line}`);
}); В настоящее время цикл for await...of может быть немного медленнее. Если важность async / await потока и скорости, можно применить смешанный подход:
const { once } = require('events');
const { createReadStream } = require('fs');
const { createInterface } = require('readline');
(async function processLineByLine() {
try {
const rl = createInterface({
input: createReadStream('big-file.txt'),
crlfDelay: Infinity
});
rl.on('line', (line) => {
// Process the line.
});
await once(rl, 'close');
console.log('File processed.');
} catch (err) {
console.error(err);
}
})(); Сопоставления клавиш TTY
| Сопоставления клавиш | Описание | Примечания |
|---|---|---|
ctrl + shift + backspace
| Удалить строку слева | Не работает в Linux, Mac и Windows |
ctrl + shift + delete
| Удалить строку справа | Не работает в Mac |
ctrl + c
| Вызвать SIGINT или закрыть экземпляр readline | |
ctrl + h
| Удалить слева | |
ctrl + d
| Удалить справа или закрыть экземпляр readline, если текущая строка пуста / EOF | Не работает в Windows |
ctrl + u
| Удалить от текущей позиции до начала строки | |
ctrl + k
| Удалить от текущей позиции до конца строки | |
ctrl + a
| Перейти к началу строки | |
ctrl + e
| Перейти к концу строки | |
ctrl + b
| Назад на один символ | |
ctrl + f
| Вперед на один символ | |
ctrl + l
| Очистить экран | |
ctrl + n
| Следующий элемент истории | |
ctrl + p
| Предыдущий элемент истории | |
ctrl + z
| Перемещает запущенный процесс в фоновый режим. Введите fg и нажмите enter, чтобы вернуться. | Не работает в Windows |
ctrl + w или ctrl + backspace
| Удалить символ назад до границы слова |
ctrl + backspace Не работает в Linux, Mac и Windows |
ctrl + delete
| Удалить символ вперед до границы слова | Не работает в Mac |
ctrl + left или meta + b
| Слово влево |
ctrl + left Не работает в Mac |
ctrl + right или meta + f
| Слово вправо |
ctrl + right Не работает в Mac |
meta + d или meta + delete
| Удалить слово вправо |
meta + delete Не работает в Windows |
meta + backspace
| Удалить слово влево | Не работает в Mac |
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v12.x/docs/api/readline.html