UNPKG

@hhoangphuoc/escape-room-cli

Version:

A CLI for playing AI-generated escape room games. Install globally with: npm install -g @hhoangphuoc/escape-room-cli

131 lines (130 loc) 4.64 kB
// Tab completion utilities for CLI commands and object names import { COMMANDS } from './constants.js'; // Find common prefix of multiple strings export function findCommonPrefix(strings) { if (strings.length === 0) return ''; if (strings.length === 1) return strings[0] || ''; let prefix = strings[0] || ''; for (let i = 1; i < strings.length; i++) { const current = strings[i]; if (!current || !prefix) break; let j = 0; while (j < prefix.length && j < current.length && prefix[j] === current[j]) { j++; } prefix = prefix.substring(0, j); if (prefix === '') break; } return prefix || ''; } // Get command completions for '/' prefixed input export function getCommandCompletions(input) { const availableCommands = Object.keys(COMMANDS); const inputLower = input.toLowerCase(); const suggestions = availableCommands.filter(cmd => cmd.startsWith(inputLower)); const commonPrefix = findCommonPrefix(suggestions); return { suggestions, commonPrefix, hasUniqueMatch: suggestions.length === 1 }; } // Get object name completions for inspect/guess commands export function getObjectCompletions(input, objects) { const inputLower = input.toLowerCase(); const suggestions = objects.filter(obj => obj.toLowerCase().startsWith(inputLower)); const commonPrefix = findCommonPrefix(suggestions); return { suggestions, commonPrefix, hasUniqueMatch: suggestions.length === 1 }; } // Parse command and get appropriate completions export function getCompletions(input, context) { const trimmed = input.trim(); // If input starts with '/', complete commands if (trimmed.startsWith('/')) { const parts = trimmed.split(/\s+/); const command = parts[0] || ''; // If we're still typing the command itself if (parts.length === 1) { return getCommandCompletions(command); } // If we have a complete command, check if it needs object completion if (command === '/inspect' || command === '/guess') { const objectInput = parts[1] || ''; return getObjectCompletions(objectInput, context.currentRoomObjects); } } // No completions available return { suggestions: [], commonPrefix: '', hasUniqueMatch: false }; } // Apply tab completion to current input export function applyTabCompletion(input, context) { const trimmed = input.trim(); const completion = getCompletions(trimmed, context); if (completion.suggestions.length === 0) { return input; // No completions available } const parts = trimmed.split(/\s+/); if (trimmed.startsWith('/')) { if (parts.length === 1) { // Completing command if (completion.hasUniqueMatch) { return completion.suggestions[0] + ' '; } else if (completion.commonPrefix.length > trimmed.length) { return completion.commonPrefix; } } else if (parts.length >= 2 && (parts[0] === '/inspect' || parts[0] === '/guess')) { // Completing object name if (completion.hasUniqueMatch) { const newParts = [...parts]; newParts[1] = completion.suggestions[0] || ''; return newParts.join(' ') + (parts[0] === '/guess' ? ' ' : ''); } else if (completion.commonPrefix.length > (parts[1] || '').length) { const newParts = [...parts]; newParts[1] = completion.commonPrefix; return newParts.join(' '); } } } return input; } // Get suggestion display info for UI export function getCompletionDisplayInfo(input, context) { const completion = getCompletions(input.trim(), context); if (completion.suggestions.length === 0) { return null; } const parts = input.trim().split(/\s+/); let title = ''; let currentMatch = ''; if (input.trim().startsWith('/')) { if (parts.length === 1) { title = 'Available Commands'; currentMatch = parts[0] || ''; } else if (parts.length >= 2 && (parts[0] === '/inspect' || parts[0] === '/guess')) { title = 'Available Objects'; currentMatch = parts[1] || ''; } } return { title, suggestions: completion.suggestions, currentMatch, hasUniqueMatch: completion.hasUniqueMatch }; }