الوحدة Readline في Node.js
الاستقرار 2: مستقر
توفّر الوحدة 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) => {
// في قاعدة بيانات (answer) للتنفيذ: سجل الجواب
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
});
حالما تُستدعى هذه الشيفرة، لن ينتهي تطبيق Node.js حتى تُغلَق الواجهة readline.Interface
لأنّها تنتظر أن تُستقبل البيانات في المجرى input
.
الصنف: Interface
أُضيف في الإصدار: 0.1.104.
تُنشَأ نُسَخ الصنف readline.Interface
باستخدام التابع readline.createInterface()
. ترفق كل نسخة مع مجرى الدخل input
الوحيد القابل للقراءة ومجرى الخرج output
الوحيد القابل للكتابة. يُستخدم المجرى output
لطباعة الأوامر التي يدخلها المستخدم والتي تصل وتُقرأ من مجرى input
.
الحدث: 'close'
أُضيف في الإصدار: 0.1.98.
يُطلق الحدث 'close'
عندما يحدث واحد مما يلي:
- يُستدعى التابع
rl.close()
وقد تخلّت نسخةreadline.Interface
عن التحكم بمجريي الدخلinput
والخرجoutput
. - يستقبل المجرى
input
الحدث'end'
الخاص به. - يستقبل مجرى الدخل
input
الإشارة EOT (نهاية الإرسال [end-of-transmission]) عبر ضغط المستخدم على المفتاحين <ctrl>-D
. - يستقبل مجرى الدخل
input
الإشارةSIGINT
عبر ضغط المستخدم على المفتاحينctrl>-C>
ولا يوجد مستمع للحدث'SIGINT'
مُسجَّل على نسخةreadline.Interface
.
تُستدعَى الدالة المستمعة (listener) دون تمرير أي وسائط.
تُنهى النسخة readline.Interface
حالما يُطلق الحدث 'close'
.
الحدث 'line'
أُضيف في الإصدار:0.1.98.
يُطلق الحدث 'line'
كلّما استقبل المجرى input
محرف نهاية السطر (المحرف n\
أو r\
أو \r\n
). هذا يحدث عادةً عندما يضغط المستخدم المفاتيح <Enter>
أو <Return>
.
تُستدعى الدالة المستمعة مع سلسلة نصية متضمنةً سطرًا وحيدًا من الدخل المُستقبل.
rl.on('line', (input) => {
console.log(`Received: ${input}`);
});
الحدث 'pause'
أُضيف في الإصدار: 0.7.5.
يُطلق الحدث 'pause'
عندما يحدث واحد مما يلي:
- يُوقف المجرى
input
مؤقتًا. - لم يُوقف المجرى
input
ولكنه استقبل الحدث'SIGCONT'
. (انظر الحدثين 'SIGTSTP' و 'SIGCONT'.)
تُستدعى الدالة المستمعة دون تمرير أي وسائط.
rl.on('pause', () => {
console.log('Readline paused.');
});
الحدث 'resume'
أضيف في الإصدار: 0.7.5.
يُطلق الحدث 'resume'
عندما يُستأنَف المجرى input
.
تُستدعى الدالة المستمعة دون تمرير أي وسائط.
rl.on('resume', () => {
console.log('Readline resumed.');
});
الحدث 'SIGCONT'
أضيف في الإصدار: 0.7.5.
يُطلق الحدث 'SIGCONT'
عندما تكون عملية Node.js قد انتقلت مسبقًا إلى الخلفية باستخدام المفتاحين <ctrl>-Z
(أي عبر استلام الإشارة SIGTSTP
) ثمَّ أعيدت إلى المقدمة باستخدام الدالة fg(1p).
إذا كان مجرى الدخل input
متوقف مؤقتًا قبل استلام الإشارة SIGTSTP، فلن يُطلق هذا الحدث.
تُستدعى الدالة المستمعة دون تمرير أي وسائط.
rl.on('SIGCONT', () => {
// المجرى تلقائيًا`prompt` سوف تستأنف
rl.prompt();
});
الحدث 'SIGCONT'
ليس مدعومًا على أنظمة ويندوز.
الحدث 'SIGINT'
أضيف في الإصدار: 0.3.0.
يُطلق الحدث 'SIGINT'
عندما يستلم المجرى input
الإشارة SIGINT
عبر الضغط على المفتاحين <ctrl>-C
. إذا لم يوجد هناك أي مستمع مسجل للحدث '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'
أُضيف في الإصدار: 0.7.5.
يُطلق الحدث 'SIGTSTP'
عندما يتلقى المجرى input
الإشارة SIGTSTP
عبر ضغط المفتاحين <ctrl>-Z
. إذا لم يوجد هناك أي مستمع مسجل للحدث 'SIGTSTP'
عندما يتلقى المجرى input
الإشارة SIGTSTP
، فستُرسل عملية Node.js إلى الخلفية.
عندما يُستأنَف البرنامج باستخدام الدالة fg(1p)، سيُطلق الحدثان 'pause'
و 'SIGCONT'
. يمكن استخدام ذلك لاستئناف المجرى input
.
لن يُطلَق الحدثان 'pause'
و'SIGCONT'
إذا أُوقِف المجرى input
قبل أن تُرسَل العملية إلى الخلفية.
تُستدعَى الدالة المستمعة دون تمرير أي وسائط.
rl.on('SIGTSTP', () => {
// ويمنع البرنامج من الذهاب إلى الخلفية SIGTSTP هذا سيتجاهل الإشارة
console.log('Caught SIGTSTP.');
});
الحدث 'SIGTSTP'
ليس مدعومًا على نظام ويندوز.
rl.close()
أضيف في الإصدار: 0.1.98.
يغلق التابع rl.close()
النسخة readline.Interface
ويتخلى عن التحكم بمجريي الدخل input
و الخرج output
. عندما استدعائه، سيُطلَق الحدث 'close'
.
لن يوقف استدعاء التابع rl.close()
إطلاق بقية الأحداث (بما فيها الحدث 'line'
) مباشرةً من قِبَل النسخة readline.Interface
.
rl.pause()
أضيف في الإصدار: 0.3.4.
يوقف التابع rl.pause()
المجرى input مؤقتًا، سامحًا له بالاستئناف لاحقًا عند الحاجة.
لن يوقف استدعاء rl.pause()
إطلاق بقية الأحداث (بما فيها الحدث 'line'
) مباشرةً من قِبَل النسخة readline.Interface
.
rl.prompt([preserveCursor])
أضيف في الإصدار: 0.1.98.
preserveCursor
: <boolean> قيمة منطقية إن كانتtrue
، فستمنع المؤشر من إعادة تعيين موضعه إلى0
(بداية المجرى).
يكتب التابع rl.prompt()
النُسخ readline.Interface
التي ضُبِط فيها المحث prompt
إلى سطر جديد في المجرى output
من أجل تزويد المستخدم بموقع جديد ليدخل البيانات فيه.
عند استدعاء التابع rl.prompt()
، سيستأنف المجرى input
إذا كان قد أُوقف مؤقتًا.
إذا أُنشئت النسخة readline.Interface
مع ضبط المجرى output
إلى القيمة null
أو undefined
، فلن يُكتَب على المحث (prompt).
rl.question(query, callback)
أضيف في الإصدار: 0.3.3.
query
: <string> عبارة أو استعلام يرا كتابتها على المجرى output، مضافةً إلى بداية المِحَث.callback
: <Function> دالة رد نداء التي يراد استدعاؤها مع مدخلات المستخدم عند الاستجابة إلى الاستعلامquery
.
يعرض التابع rl.question()
قيمة الاستعلام query
عن طريق كتابته على المجرى output
، بعد أن ينتظر مدخلات المستخدم ليكتبها على المجرى input
. بعد ذلك، يستدعي التابع دالة رد النداء callback
مُمرّرًا المدخلات المستلمة من الستخدم إليها كأول وسيط.
عند استدعائه، سوف يستأنف rl.question()
المجرى input
إذا كان قد أُوقف مؤقتًا.
ذا أُنشئت النسخة readline.Interface
مع ضبط المجرى output
إلى القيمة null
أو undefined
، فلن يُكتَب الاستعلام query
.
اطلع على المثال التالي الذي يشرح ما سبق:
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()
أضيف في الإصدار: 0.3.4.
يستأنف التابع rl.resume()
المجرى input
إذا أُوقِف مؤقتًا.
rl.setPrompt(prompt)
أضيف في الإصدار: 0.1.98.
Prompt
: <string>
سوف يضبط التابع rl.setPrompt()
المِحَث الذي سيكتب على المجرى output
كلما استدعي التابع rl.prompt()
.
rl.write(data[, key])
أضيف في الإصدار: 0.1.98.
سيكتب التابع rl.write()
إمّا قيمة المعامل data
أو تسلسل المفتاح المعرّف من قبل المعامل key
إلى المجرى output
. الوسيط key
مدعومٌ إذا كانت output
هي TTY طرفية كتابة فقط.
إذا كان المعامل key
مُحددًا، فسيُتجاهَل المعامل data
.
عند استدعاء rl.write()
، سيستأنف المجرى input
إذا كان قد أُوقف مؤقتًا.
إذا أُنشئت النسخة readline.Interface
مع ضبط المجرى output
إلى القيمة null
أو undefined
، فلن تُكتَب قيمة المعامل data
أو المعامل key
.
rl.write('Delete this!');
// لحذف السطر المكتوب سابقًا Ctrl+u محاكي ضغط المفتاحين
rl.write(null, { ctrl: true, name: 'u' });
سوف يكتب التابع rl.write()
البيانات إلى المجرى input
كما أعطيت من قبل المستخدم تمامًا.
readline.clearLine(stream, dir)
أُضيف في الإصدار: 0.7.7.
stream
: [/kjjhhhhgNode.js/stream <stream.Writable>]dir
: <number>1-
: على يسار المؤشر1
: على يمين المؤشر0
: كل السطر
يمسح التابع readline.clearLine()
السطر الحالي من المجرى TTY المُعطى انطلاقًا من مؤضع المؤشر الحالي وباتجاهٍ محدَّدٍ مُعرّف عبر المعامل dir.
readline.clearScreenDown(stream)
أُضيف في الإصدار: 0.7.7.
stream
: [/kjjhhhhgNode.js/stream <stream.Writable>]
يمسح التابع readline.clearScreenDown()
مجرى TTY المعُطى من موقع المؤشر الحالي وبالاتجاه الأسفل.
readline.createInterface(options)
سجل التغييرات
الإصدار | التغييرات |
---|---|
8.3.0, 6.11.4 | إزالة الحدود الأعظمية للخيار crlfDelay .
|
6.6.0 | أصبح الخيار crlfDelay مدعومًا الآن.
|
6.3.0 | أصبح الخيار prompt مدعومًا الآن.
|
6.0.0 | يمكن الآن أن يأخذ الخيار historySize القيمة 0 .
|
0.1.98 | أُضيف هذا التابع. |
options
: <Object>input
: <stream.Readable> المجرى القابل للقراءة المراد الاستماع إليه. هذا الخيار مطلوب.output
: <stream.Writable> المجرى القابل للكتابة لكتابة بيانات سطرية فيه.completer
: <Function> دالة اختيارية تستخدم للإكمال التلقائي عبر الضغط على المفتاح Tap.terminal
: <boolean> قيمة منطقية تكونtrue
إذا كان ينبغي معاملة المجريينoutput
وinput
كأنهما TTY وأن يمتلكا شيفرات الهروب ANSI/VT100 مكتوبة له. القيمة الإفتراضية تكون بناءً على التحقق منisTTY
على المجرىoutput
.historySize
: <number> العدد الأعظمي لأسطر التاريخ المحفوظة. لتعطيل التاريخ، اضبط قيمة هذا الخيار إلى0
. هذا الخيار له معنى فقط إذا كان الخيارterminal
مضبوطًا إلى القيمةtrue
من قبل المستخدم أو من قبل فحص المجرىoutput
الداخلي. فيما عدا ذلك، لن تُهيأ آلية تخزين التاريخ مطلقًا. القيمة الإفتراضية:30
.prompt
: <string> السلسلة النصية المراد استعمالها مع المِحَث. القيمة الإفتراضية:'> '
.crlfDelay
: <number> إذا تجاوز التأخير بين المحرف \r
والمحرف \n
القيمةcrlfDelay
المعطاة بالميلي ثانية، فسيعاملان كمحرفي نهاية سطر منفصلين. لا يجب أن تقل قيمة الخيارcrlfDelay
عن100
وستستعمل هذه القيمة إن كانت القيمة المعطاة أقل منها. يمكن أن يُضبَط الخيار إلى القيمة Infinity (قيمة لا نهائية)؛ في هذه الحالة، سيُعدُّ المحرفr\
عندما يُتبَع بالمحرف\n
سطرًا جديدًا مفردًا دائمًا (هذا قد يكون منطقيًا من أجل قراءة الملفات مع الفاصل السطري\r\n
). القيمة الإفتراضية:100
.removeHistoryDuplicates
: <boolean> قيمة منطقية إذا كانتtrue
، فسيُزال سطر التأريخ القديم من القائمة عندما يضاف سطرٌ جديدٌ مماثل له (أي عند تكراره). القيمة الإفتراضية:false
.
ينشئ التابع 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 مع مدخلتين:
مصفوفة Array
مع مدخلات مطابقة للإكمال، و
السلاسل النصية الفرعية التي استخدمت للمطابقة.
على سبيل المثال: [[substr1, substr2, ...], originalsubstring]
.
function completer(line) {
const completions = '.help .error .exit .quit .q'.split(' ');
const hits = completions.filter((c) => c.startsWith(line));
// تعرض كل احتمالات الإكمال إذا وجدت
return [hits.length ? hits : completions, line];
}
يمكن أن تُستدعَى الدالة completer
بشكل غير متزامن إذا قبلت وسيطين مثل:
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
}
readline.cursorTo(stream, x, y)
أُضيف في الإصدار: 0.7.7.
stream
: <stream.Writable>x
: <number>y
: <number>
ينقل التابع readline.cursorTo()
المؤشر إلى موضع محدد في المجرى stream
المعطى الذي من النوع TTY.
readline.emitKeypressEvents(stream[, interface])
أُضيف في الإصدار: 0.7.7.
stream
: <stream.Readable>interface
: <readline.Interface>
يسبب التابع readline.emitKeypressEvents()
ببدء المجرى القابل للقراءة إطلاق الأحداث 'keypress'
بما يتوافق مع المدخلات المُستقبلَة.
اختياريًّا، يحدِّد المعامل interface
النسخة readline.Interface
التي سيُعطَل الإكمال التلقائي فيها عندما تكتشف عملية نسخٍ ولصقٍ للمدخلات.
إذا كان المجرى stream
من النوع TTY، فيجب حينئذٍ أن تكون في الوضع الخام (raw mode).
يُستدعى هذا التابع تلقائيًا من قبل أية نسخة من النوع readline
على المجرى input
الخاص بها إذا كان المجرى input
هو طرفية. لن يوقف إغلاق النسخة readline
المجرى input
من إطلاق الأحداث 'keypress'
.
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY)
process.stdin.setRawMode(true);
readline.moveCursor(stream, dx, dy)
أُضيف في الإصدار: 0.7.7.
stream
: <stream.Writable>dx
: <number>dy
: <number>
ينقل التابع readline.moveCursor()
المؤشر نسبةً إلى موقعه الحالي في المجرى stream
المعطى الذي من النوع TTY.
أمثلة
واجهة سطر أوامر صغيرة (Tiny CLI)
يوضّح المثال التالي كيفية استخدام الصنف 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
هو قراءة الدخل من مجرًى قابلٍ للقراءة لنظام الملفات سطرًا واحدًا في كل مرة:
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: fs.createReadStream('sample.txt'),
crlfDelay: Infinity
});
rl.on('line', (line) => {
console.log(`Line from file: ${line}`);
});
مصادر