stdin Module Documentation
Overview
The stdin module provides comprehensive terminal input/output control for interactive command-line applications. It enables reading user input, managing terminal modes, controlling cursor position, clearing screens, and handling terminal events. Built on libuv for async I/O, it supports both line-buffered and raw character-by-character input modes.
Import
tumia stdinCore Concepts
Input Modes
- Normal Mode (Line-buffered): Input is buffered until Enter is pressed. Best for command-line prompts and forms.
- Raw Mode: Characters are read immediately as typed. Essential for interactive applications like text editors, games, and custom input handlers.
Event-Driven Model
The module uses an event listener system where you register callbacks for specific events:
data- Input receivedeof- End of input (Ctrl+D / EOF)sigint- Interrupt signal (Ctrl+C)
API Reference
Event Handling
stdin.on(event, callback)
Registers an event listener for stdin events.
| Parameter | Type | Description |
|---|---|---|
event | neno | Event name: "data", "eof", or "sigint" |
callback | kazi | Function called when event occurs |
| Returns | void | - |
Events:
| Event | Trigger | Callback Arguments |
|---|---|---|
"data" | Input received | (buffer: Buffer) - Input data |
"eof" | Ctrl+D or EOF | None |
"sigint" | Ctrl+C | None |
Usage:
tumia stdin
// Normal mode - line-by-line input
stdin.on("data", input => {
data text = input.toString("utf8")
chapisha "You typed:", text
})
stdin.on("eof", () => {
chapisha "End of input"
stdin.close()
})
stdin.on("sigint", () => {
chapisha "\nInterrupted!"
stdin.close()
})Raw Mode Example:
stdin.setRawMode(kweli)
stdin.on("data", input => {
data bytes = input.toArray()
kwa kila byte katika bytes {
kama byte == 27 { // ESC key
chapisha "\nEscape pressed!"
stdin.setRawMode(sikweli)
stdin.close()
} vinginevyo {
chapisha `Key code: ${byte}`
}
}
})Terminal Mode Control
stdin.setRawMode(enabled)
Switches between raw and normal (line-buffered) input modes.
| Parameter | Type | Description |
|---|---|---|
enabled | bool | kweli for raw mode, sikweli for normal mode |
| Returns | void | - |
Raw Mode Characteristics:
- Characters read immediately (no Enter required)
- No line editing (backspace, arrow keys send raw codes)
- Special keys send escape sequences
- Ctrl+C sends byte
0x03(doesn't terminate program)
Usage:
// Enable raw mode for interactive input
stdin.setRawMode(kweli)
stdin.on("data", input => {
data char = input.toArray()[0]
chagua char {
ikiwa 119: // 'w'
chapisha "Move up"
simama
ikiwa 115: // 's'
chapisha "Move down"
simama
ikiwa 113: // 'q'
stdin.setRawMode(sikweli)
stdin.close()
simama
}
})stdin.pause()
Pauses stdin reading. Buffered input is discarded by default.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
chapisha "Processing... input disabled"
stdin.pause()
// Simulate long operation
timers.setTimeout(() => {
stdin.resume()
chapisha "Input re-enabled"
}, 3000)stdin.resume()
Resumes stdin reading after being paused. Re-displays prompt if set.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
stdin.resume()
stdin.prompt("> ") // Re-display promptstdin.setDiscardOnPause(enabled)
Controls whether buffered input is discarded when pausing.
| Parameter | Type | Description |
|---|---|---|
enabled | bool | kweli to discard input on pause (default), sikweli to keep |
| Returns | void | - |
Usage:
// Keep input buffer when pausing
stdin.setDiscardOnPause(sikweli)stdin.close()
Closes stdin, restores terminal to normal mode, and cleans up resources.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
stdin.on("eof", () => {
chapisha "Goodbye!"
stdin.close()
})Prompt Display
stdin.prompt(text)
Displays a prompt message to the user. Useful for interactive CLI applications.
| Parameter | Type | Description |
|---|---|---|
text | neno | Prompt text to display |
| Returns | void | - |
Usage:
stdin.prompt("Enter your name: ")
stdin.on("data", input => {
data name = input.toString("utf8")
chapisha `Hello, ${name}!`
stdin.prompt("Enter command: ")
})stdin.echo(text)
Writes text directly to stdout without newline.
| Parameter | Type | Description |
|---|---|---|
text | neno au Buffer | Text to output |
| Returns | void | - |
Usage:
stdin.echo("Loading")
timers.setInterval(() => {
stdin.echo(".")
}, 500)Terminal Size
stdin.getTermSize()
Retrieves current terminal dimensions.
| Parameter | Type | Description |
|---|---|---|
| Returns | object au null | { width: namba, height: namba } or null if unavailable |
Usage:
data size = stdin.getTermSize()
kama size {
chapisha `Terminal: ${size.width}x${size.height}`
kama size.width < 80 {
chapisha "Warning: Terminal too narrow"
}
} vinginevyo {
chapisha "Could not determine terminal size"
}Cursor Control
stdin.cursorTo(x, y)
Moves cursor to absolute position (0-indexed).
| Parameter | Type | Description |
|---|---|---|
x | namba | Column position (0 = leftmost) |
y | namba | Row position (0 = top) |
| Returns | void | - |
Usage:
stdin.cursorTo(0, 0) // Top-left corner
stdin.echo("Header")
stdin.cursorTo(0, 10) // Row 10
stdin.echo("Footer")stdin.cursorMove(dx, dy)
Moves cursor relative to current position.
| Parameter | Type | Description |
|---|---|---|
dx | namba | Horizontal offset (positive = right, negative = left) |
dy | namba | Vertical offset (positive = down, negative = up) |
| Returns | void | - |
Usage:
stdin.cursorMove(5, 0) // Move 5 columns right
stdin.cursorMove(-3, 0) // Move 3 columns left
stdin.cursorMove(0, -2) // Move 2 rows upstdin.saveCursor()
Saves current cursor position.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
stdin.restoreCursor()
Restores previously saved cursor position.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
stdin.saveCursor()
stdin.cursorTo(0, 20)
stdin.echo("Temporary message")
timers.setTimeout(() => {
stdin.restoreCursor()
stdin.echo("Back to original position")
}, 2000)stdin.hideCursor()
Hides the terminal cursor.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
stdin.hideCursor()
// ... display UI ...
stdin.showCursor() // Always restore on exitstdin.showCursor()
Shows the terminal cursor.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Screen Control
stdin.clearLine(mode?)
Clears the current line.
| Parameter | Type | Description |
|---|---|---|
mode | namba (optional) | 0 = right of cursor, 1 = left of cursor, 2 = entire line (default) |
| Returns | void | - |
Usage:
stdin.clearLine(2) // Clear entire line
stdin.cursorTo(0, stdin.getTermSize().height - 1)
stdin.echo("Status: Ready")stdin.clearScreen(mode?)
Clears the terminal screen.
| Parameter | Type | Description |
|---|---|---|
mode | namba (optional) | 0 = below cursor, 1 = above cursor, 2 = entire screen (default) |
| Returns | void | - |
Usage:
stdin.clearScreen(2) // Clear entire screen
stdin.cursorTo(0, 0)
stdin.echo("Fresh start!")stdin.clearScreenDown()
Clears screen from cursor to bottom.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Scrolling
stdin.scrollUp(lines?)
Scrolls terminal content up by specified lines.
| Parameter | Type | Description |
|---|---|---|
lines | namba (optional) | Number of lines to scroll (default: 1) |
| Returns | void | - |
stdin.scrollDown(lines?)
Scrolls terminal content down by specified lines.
| Parameter | Type | Description |
|---|---|---|
lines | namba (optional) | Number of lines to scroll (default: 1) |
| Returns | void | - |
Usage:
stdin.scrollUp(3) // Scroll up 3 lines
stdin.scrollDown(1) // Scroll down 1 lineAudio Feedback
stdin.beep()
Emits terminal bell/beep sound.
| Parameter | Type | Description |
|---|---|---|
| Returns | void | - |
Usage:
stdin.beep() // Alert user
chapisha "Error: Invalid input"Complete Examples
1. Interactive Password Input
tumia stdin
data password = ""
data thabiti maxLength = 20
stdin.setRawMode(kweli)
stdin.hideCursor()
stdin.prompt("Enter password: ")
stdin.on("data", input => {
data char = input.toArray()[0]
kama char == 13 { // Enter key
stdin.echo("\n")
stdin.showCursor()
stdin.setRawMode(sikweli)
chapisha `Password captured: ${password.idadi} characters`
stdin.close()
rudisha
}
kama char == 127 au char == 8 { // Backspace/Delete
kama password.idadi > 0 {
password = password.slice(0, -1)
stdin.cursorMove(-1, 0)
stdin.echo(" ")
stdin.cursorMove(-1, 0)
}
rudisha
}
kama char >= 32 na char <= 126 { // Printable characters
kama password.idadi < maxLength {
password += String.fromCharCode(char)
stdin.echo("*")
} vinginevyo {
stdin.beep()
}
}
})
stdin.on("sigint", () => {
stdin.echo("\n^C\n")
stdin.showCursor()
stdin.setRawMode(sikweli)
stdin.close()
})2. Progress Bar
tumia stdin
tumia timers
kazi drawProgressBar percent, width {
data filled = Math.floor(width * percent / 100)
data empty = width - filled
data bar = "[" + "=".repeat(filled) + " ".repeat(empty) + "]"
stdin.cursorTo(0, 5)
stdin.clearLine(2)
stdin.echo(`${bar} ${percent}%`)
}
stdin.hideCursor()
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.echo("Downloading file...\n")
data progress = 0
data interval = timers.setInterval(() => {
progress += 2
drawProgressBar(progress, 50)
kama progress >= 100 {
timers.clearInterval(interval)
stdin.cursorTo(0, 7)
stdin.echo("Download complete!\n")
stdin.showCursor()
stdin.close()
}
}, 100)3. Menu Selection System
tumia stdin
data options = ["New Game", "Load Game", "Settings", "Quit"]
data selected = 0
kazi drawMenu {
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.echo("=== GAME MENU ===\n\n")
kwa(data i = 0; i < options.idadi; i++) {
kama i == selected {
stdin.echo(`> ${options[i]} <\n`)
} vinginevyo {
stdin.echo(` ${options[i]}\n`)
}
}
stdin.echo("\nUse arrows to navigate, Enter to select, Q to quit")
}
stdin.setRawMode(kweli)
stdin.hideCursor()
drawMenu()
stdin.on("data", input => {
data bytes = input.toArray()
// Arrow keys send escape sequences: ESC[A (up), ESC[B (down)
kama bytes.idadi == 3 na bytes[0] == 27 na bytes[1] == 91 {
kama bytes[2] == 65 { // Up arrow
selected = (selected - 1 + options.idadi) % options.idadi
drawMenu()
} vinginevyo kama bytes[2] == 66 { // Down arrow
selected = (selected + 1) % options.idadi
drawMenu()
}
rudisha
}
data char = bytes[0]
kama char == 13 { // Enter
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.showCursor()
stdin.setRawMode(sikweli)
chapisha `You selected: ${options[selected]}`
stdin.close()
} vinginevyo kama char == 113 { // 'q'
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.showCursor()
stdin.setRawMode(sikweli)
chapisha "Quit"
stdin.close()
}
})
stdin.on("sigint", () => {
stdin.showCursor()
stdin.setRawMode(sikweli)
stdin.close()
})4. Live Data Dashboard
tumia stdin
tumia timers
data stats = {
cpu: 0,
memory: 0,
network: 0
}
kazi updateStats {
stats.cpu = Math.random() * 100
stats.memory = Math.random() * 100
stats.network = Math.random() * 1000
}
kazi drawDashboard {
data size = stdin.getTermSize()
// Header
stdin.cursorTo(0, 0)
stdin.clearLine(2)
stdin.echo("=== SYSTEM MONITOR ===")
// CPU
stdin.cursorTo(0, 2)
stdin.clearLine(2)
stdin.echo(`CPU: ${stats.cpu.toFixed(1)}%`)
// Memory
stdin.cursorTo(0, 3)
stdin.clearLine(2)
stdin.echo(`Memory: ${stats.memory.toFixed(1)}%`)
// Network
stdin.cursorTo(0, 4)
stdin.clearLine(2)
stdin.echo(`Network: ${stats.network.toFixed(0)} KB/s`)
// Footer
stdin.cursorTo(0, 6)
stdin.clearLine(2)
stdin.echo("Press Q to quit")
// Keep cursor at bottom
stdin.cursorTo(0, size ? size.height - 1 : 10)
}
stdin.setRawMode(kweli)
stdin.hideCursor()
stdin.clearScreen(2)
// Update every second
data interval = timers.setInterval(() => {
updateStats()
drawDashboard()
}, 1000)
// Initial draw
drawDashboard()
stdin.on("data", input => {
data char = input.toArray()[0]
kama char == 113 au char == 81 { // 'q' or 'Q'
timers.clearInterval(interval)
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.showCursor()
stdin.setRawMode(sikweli)
chapisha "Dashboard closed"
stdin.close()
}
})
stdin.on("sigint", () => {
timers.clearInterval(interval)
stdin.showCursor()
stdin.setRawMode(sikweli)
stdin.close()
})5. Simple Text Editor (Line Editor)
tumia stdin
data lines = [""]
data currentLine = 0
data cursorX = 0
kazi drawEditor {
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
stdin.echo("=== TEXT EDITOR ===\n")
stdin.echo("Ctrl+S: Save | Ctrl+Q: Quit\n\n")
kwa(i = 0; i < lines.idadi; i++) {
data prefix = i == currentLine ? "> " : " "
stdin.echo(`${prefix}${lines[i]}\n`)
}
}
stdin.setRawMode(kweli)
drawEditor()
stdin.on("data", input => {
data bytes = input.toArray()
data char = bytes[0]
// Ctrl+S (Save)
kama char == 19 {
stdin.setRawMode(sikweli)
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
chapisha "Saved!"
kwa kila line katika lines {
chapisha line
}
stdin.close()
rudisha
}
// Ctrl+Q (Quit)
kama char == 17 {
stdin.setRawMode(sikweli)
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
chapisha "Quit without saving"
stdin.close()
rudisha
}
// Enter - new line
kama char == 13 {
currentLine++
lines.splice(currentLine, 0, "")
cursorX = 0
drawEditor()
rudisha
}
// Backspace
kama char == 127 au char == 8 {
kama cursorX > 0 {
data line = lines[currentLine]
lines[currentLine] = line.slice(0, cursorX - 1) + line.slice(cursorX)
cursorX--
drawEditor()
}
rudisha
}
// Printable characters
kama char >= 32 na char <= 126 {
data line = lines[currentLine]
data c = String.fromCharCode(char)
lines[currentLine] = line.slice(0, cursorX) + c + line.slice(cursorX)
cursorX++
drawEditor()
}
})
stdin.on("sigint", () => {
stdin.setRawMode(sikweli)
stdin.clearScreen(2)
stdin.cursorTo(0, 0)
chapisha "Interrupted"
stdin.close()
})Use Cases
1. Command-Line Tools
- Interactive prompts for user input
- Configuration wizards
- CLI questionnaires
2. Games
- Terminal-based games (snake, tetris, roguelikes)
- Real-time keyboard controls
- Menu navigation systems
3. System Monitoring
- Live dashboards
- Resource monitors (CPU, memory, network)
- Log viewers with auto-refresh
4. Text Editors
- Simple text editors
- Code snippet editors
- Configuration file editors
5. Progress Indicators
- Download/upload progress bars
- Installation progress
- Build/compile status displays
6. Interactive Forms
- Password input with masking
- Multi-step forms
- Data entry interfaces
7. Terminal UI Applications
- File browsers
- Process managers
- Database query tools
Best Practices
Always Clean Up
// Always restore terminal state
stdin.on("sigint", () => {
stdin.showCursor()
stdin.setRawMode(sikweli)
stdin.close()
})
// Or use error handling
jaribu {
// ... your code ...
} makosa err {
stdin.showCursor()
stdin.setRawMode(sikweli)
stdin.close()
throw err
}Handle Terminal Resize
// Check size before drawing
data size = stdin.getTermSize()
kama size na size.width < 80 {
chapisha "Terminal too narrow (min 80 columns)"
rudisha
}Use Raw Mode Judiciously
// Only enable when needed
stdin.setRawMode(kweli)
// ... capture input ...
stdin.setRawMode(sikweli) // Restore immediately afterBuffer Management
// For text input, convert properly
stdin.on("data", input => {
data text = input.toString("utf8").trim()
// ... process text ...
})Error Handling
All stdin operations throw SwaziError with type "RuntimeError" or "TypeError" on failure:
jaribu {
stdin.setRawMode(kweli)
stdin.cursorTo(100, 100) // May fail on small terminals
} makosa err {
chapisha err.type // "RuntimeError"
chapisha err.message
stdin.setRawMode(sikweli)
}Platform Notes
- ANSI Escape Sequences: All cursor/screen control uses ANSI codes, supported on Unix/Linux/macOS and modern Windows terminals
- Signal Handling: SIGINT, SIGTERM, SIGABRT automatically restore terminal state
- Terminal Requirements: Requires TTY-capable terminal (not file redirects)
- Event Loop: Requires active libuv event loop (automatic in async contexts)