Last active
October 22, 2024 15:59
-
-
Save derammo/ab3de45b7b1a52e6c8b232658b7279c9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const fs = require('fs'); | |
| const readline = require('readline'); | |
| async function parseFile(filePath) { | |
| const fileStream = fs.createReadStream(filePath); | |
| const rl = readline.createInterface({ | |
| input: fileStream, | |
| crlfDelay: Infinity | |
| }); | |
| const sections = []; | |
| let currentSection = null; | |
| const keyCodeMap = { | |
| 0x3B: 'F1', 0x3C: 'F2', 0x3D: 'F3', 0x3E: 'F4', 0x3F: 'F5', 0x40: 'F6', 0x41: 'F7', 0x42: 'F8', 0x43: 'F9', 0x44: 'F10', | |
| 0x57: 'F11', 0x58: 'F12', 0x2: '1', 0x3: '2', 0x4: '3', 0x5: '4', 0x6: '5', 0x7: '6', 0x8: '7', 0x9: '8', 0xA: '9', 0xB: '0', | |
| 0x1E: 'A', 0x30: 'B', 0x2E: 'C', 0x20: 'D', 0x12: 'E', 0x21: 'F', 0x22: 'G', 0x23: 'H', 0x17: 'I', 0x24: 'J', 0x25: 'K', | |
| 0x26: 'L', 0x32: 'M', 0x31: 'N', 0x18: 'O', 0x19: 'P', 0x10: 'Q', 0x13: 'R', 0x1F: 'S', 0x14: 'T', 0x16: 'U', 0x2F: 'V', | |
| 0x11: 'W', 0x2D: 'X', 0x15: 'Y', 0x2C: 'Z', 0x29: '`', 0xC: '-', 0xD: '=', 0x1A: '[', 0x1B: ']', 0x27: ';', 0x28: "'", | |
| 0x2B: '\\', 0x33: ',', 0x34: '.', 0x35: '/', 0x1: 'Esc', 0xF: 'Tab', 0x3A: 'Caps Lock', 0xE: 'Backspace', 0x1C: 'Return', | |
| 0x39: 'Space', 0xB7: 'Print', 0x46: 'Scrl Lock', 0xD2: 'Insert', 0xD3: 'Delete', 0xC7: 'Home', 0xCF: 'End', 0xC9: 'Page Up', | |
| 0xD1: 'Page Dn', 0xC8: 'Up', 0xD0: 'Down', 0xCD: 'Right', 0xCB: 'Left', 0xB5: 'Num /', 0x37: 'Num *', 0x4A: 'Num -', 0x4E: 'Num +', | |
| 0x9C: 'Num Enter', 0x53: 'Num .', 0x52: 'Num 0', 0x4F: 'Num 1', 0x50: 'Num 2', 0x51: 'Num 3', 0x4B: 'Num 4', 0x4C: 'Num 5', | |
| 0x4D: 'Num 6', 0x47: 'Num 7', 0x48: 'Num 8', 0x49: 'Num 9' | |
| }; | |
| for await (const line of rl) { | |
| if (line.startsWith('#')) { | |
| continue; // Skip comment lines | |
| } | |
| if (line.startsWith('SimDoNothing') && line.includes('"==')) { | |
| const sectionTitle = line.match(/"([^"]+)"/)[1]; | |
| const sanitizedTitle = sectionTitle.replace(/=/g, '').replace(/\s+/g, ' '); | |
| currentSection = { | |
| title: sanitizedTitle, | |
| commands: [] | |
| }; | |
| sections.push(currentSection); | |
| } else if (currentSection && line.trim()) { | |
| if (line.startsWith('SimDoNothing')) { | |
| continue; // Skip SimDoNothing lines | |
| } | |
| const parts = line.split('"'); | |
| const command = parts[0].trim(); | |
| // escape markdown special characters | |
| const description = parts[1].replace(/\*/g, '\\*').replace(/_/g, '\\_').trim(); | |
| // drop any extended ASCII characters | |
| const sanitizedDescription = description.replace(/[\x80-\xFF]/g, ''); | |
| const commandParts = command.split(' '); | |
| const commandName = commandParts[0]; | |
| const keyCode = commandParts[3]; | |
| if (/^0[xX][fF][fF][fF][fF]+$/.test(keyCode)) { | |
| currentSection.commands.push({ commandName, sanitizedDescription, keystroke: '(unbound)' }); | |
| continue; | |
| } | |
| const modifierMask = commandParts[4]; | |
| const modifierString = buildModifierString(modifierMask); | |
| const keyName = keyCodeMap[parseInt(keyCode, 16)] || keyCode; | |
| const keystroke = `${modifierString} ${keyName}`.trim(); | |
| currentSection.commands.push({ commandName, sanitizedDescription, keystroke }); | |
| } | |
| } | |
| return sections; | |
| } | |
| const inputFilePath = process.argv[2]; | |
| if (!inputFilePath) { | |
| console.error('Please provide the input file path as a command line argument.'); | |
| console.error('Optional: Provide the output format as a second argument (json, text, csv, md). Default is md.'); | |
| process.exit(1); | |
| } | |
| parseFile(inputFilePath).then(sections => { | |
| const filteredSections = sections.filter(section => section.commands.length > 0); | |
| const outputFormat = process.argv[3] || 'md'; | |
| switch (outputFormat.toLowerCase()) { | |
| case 'json': | |
| printJson(filteredSections); | |
| break; | |
| case 'text': | |
| printText(filteredSections); | |
| break; | |
| case 'csv': | |
| printCSV(filteredSections); | |
| break; | |
| case 'md': | |
| default: | |
| printMarkdown(filteredSections); | |
| break; | |
| } | |
| }).catch(err => { | |
| console.error(err); | |
| }); | |
| function printJson(sections) { | |
| console.log(JSON.stringify(sections, null, 2)); | |
| } | |
| function printMarkdown(sections) { | |
| sections.forEach(section => { | |
| console.log(`# ${section.title}`); | |
| console.log(); | |
| console.log('| Callback | Description | Keyboard Binding |'); | |
| console.log('|----------|-------------|------------------|'); | |
| section.commands.forEach(command => { | |
| console.log(`| ${command.commandName} | ${command.sanitizedDescription} | ${command.keystroke} |`); | |
| }); | |
| console.log(); | |
| }); | |
| } | |
| function printText(sections) { | |
| sections.forEach(section => { | |
| const sectionTitle = section.title.trim(); | |
| console.log(`${sectionTitle}:`) | |
| section.commands.forEach(command => { | |
| if (command.keystroke === '(unbound)') { | |
| console.log(`- "${command.sanitizedDescription}": (no keys bound)`); | |
| } else { | |
| console.log(`- "${command.sanitizedDescription}": Press ${command.keystroke}`); | |
| } | |
| }); | |
| console.log(); | |
| }); | |
| } | |
| function printCSV(sections) { | |
| console.log(`Section, Callback, Description, "Keyboard Binding"`); | |
| sections.forEach(section => { | |
| const sectionTitle = section.title.trim(); | |
| section.commands.forEach(command => { | |
| console.log(`"${sectionTitle}", ${command.commandName}, "${command.sanitizedDescription}", "${command.keystroke}"`); | |
| }); | |
| }); | |
| } | |
| function buildModifierString(modifierMask) { | |
| const modifierKeys = []; | |
| const modifierValue = parseInt(modifierMask, 10); | |
| if (modifierValue & 1) modifierKeys.push('Shift'); | |
| if (modifierValue & 2) modifierKeys.push('Control'); | |
| if (modifierValue & 4) modifierKeys.push('Alt'); | |
| const modifierString = modifierKeys.join(' '); | |
| return modifierString; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment