Skip to content

Instantly share code, notes, and snippets.

@agoalofalife
Last active March 28, 2026 11:47
Show Gist options
  • Select an option

  • Save agoalofalife/1d79166f206679c3cfbf993963c92efd to your computer and use it in GitHub Desktop.

Select an option

Save agoalofalife/1d79166f206679c3cfbf993963c92efd to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
const readline = require('readline');
const { execSync } = require('child_process');
// Enable these key bindings for word navigation (Alt+Left/Right)
const customKeyBindings = {
// Alt+Left (move word left) - various terminal escape sequences
'\x1bb': 'wordLeft', // Meta+b (Option as Meta)
'\x1b[1;3D': 'wordLeft', // Alt+Left
'\x1b[1;9D': 'wordLeft', // Alt+Left (iTerm2)
// Alt+Right (move word right)
'\x1bf': 'wordRight', // Meta+f (Option as Meta)
'\x1b[1;3C': 'wordRight', // Alt+Right
'\x1b[1;9C': 'wordRight', // Alt+Right (iTerm2)
// Cmd+V paste (Terminal sends this when "Use Option as Meta" is off)
'\x16': 'paste', // Ctrl+V fallback
};
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: ''
});
// Clipboard functions for macOS
function copyToClipboard(text) {
try {
execSync('pbcopy', { input: text });
return true;
} catch (e) {
return false;
}
}
function pasteFromClipboard() {
try {
return execSync('pbpaste', { encoding: 'utf8' });
} catch (e) {
return '';
}
}
// Handle custom key bindings
process.stdin.on('keypress', (char, key) => {
if (!key) return;
const seq = key.sequence;
const binding = customKeyBindings[seq];
if (binding === 'wordLeft') {
// Move cursor to previous word boundary
const line = rl.line;
const cursor = rl.cursor;
let newCursor = cursor;
// Skip spaces, then skip word characters
while (newCursor > 0 && line[newCursor - 1] === ' ') newCursor--;
while (newCursor > 0 && line[newCursor - 1] !== ' ') newCursor--;
// Move cursor
process.stdout.write(`\x1b[${cursor - newCursor}D`);
rl.cursor = newCursor;
}
if (binding === 'wordRight') {
const line = rl.line;
const cursor = rl.cursor;
let newCursor = cursor;
// Skip word characters, then skip spaces
while (newCursor < line.length && line[newCursor] !== ' ') newCursor++;
while (newCursor < line.length && line[newCursor] === ' ') newCursor++;
if (newCursor > cursor) {
process.stdout.write(`\x1b[${newCursor - cursor}C`);
rl.cursor = newCursor;
}
}
if (binding === 'paste' || (key.ctrl && key.name === 'v')) {
const clipboard = pasteFromClipboard();
if (clipboard) {
// Insert clipboard content at cursor position
const before = rl.line.slice(0, rl.cursor);
const after = rl.line.slice(rl.cursor);
const firstLine = clipboard.split('\n')[0]; // Only first line
rl.line = before + firstLine + after;
rl.cursor = before.length + firstLine.length;
// Redraw line
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
process.stdout.write(rl.line);
process.stdout.cursorTo(rl.cursor);
}
}
});
// Enable keypress events
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY) {
process.stdin.setRawMode(true);
}
console.log("Start typing (Ctrl+C to exit):");
console.log(" Alt+← / Alt+→ - Jump by word");
console.log(" Ctrl+V - Paste from clipboard\n");
rl.on('line', (line) => {
process.stdout.write('\x1b[1A\x1b[2K');
const timestamp = new Date().toLocaleTimeString();
console.log(`[${timestamp}] ${line}`);
// Copy output to clipboard automatically (optional)
// copyToClipboard(line);
});
rl.on('close', () => {
console.log('\nExiting...');
process.exit(0);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment