Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>KickLang CLI Simulator</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| body { | |
| font-family: 'Courier New', monospace; | |
| } | |
| .blink { | |
| animation: blink 1s infinite; | |
| } | |
| @keyframes blink { | |
| 0%, 50%, 100% { opacity: 1; } | |
| 25%, 75% { opacity: 0; } | |
| } | |
| .terminal { | |
| height: 100vh; | |
| overflow-y: auto; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-black text-green-400 p-4"> | |
| <div id="app" class="max-w-3xl mx-auto flex flex-col h-screen"> | |
| <div id="output" class="flex-grow overflow-y-auto terminal p-4"></div> | |
| <div class="flex items-center mt-2"> | |
| <span id="prompt" class="mr-2">$</span> | |
| <input id="input" class="bg-transparent outline-none flex-grow" autofocus /> | |
| <span class="blink">|</span> | |
| </div> | |
| </div> | |
| <script> | |
| const output = document.getElementById('output'); | |
| const input = document.getElementById('input'); | |
| const prompt = document.getElementById('prompt'); | |
| // Simulated file system (in-memory object) | |
| const vfs = { | |
| '/': { | |
| type: 'dir', | |
| children: { | |
| 'home': { | |
| type: 'dir', | |
| children: { | |
| 'user': { | |
| type: 'dir', | |
| children: { | |
| 'README.md': { | |
| type: 'file', | |
| content: 'Welcome to KickLang CLI Simulator!' | |
| }, | |
| 'projects': { | |
| type: 'dir', | |
| children: {} | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }; | |
| let currentPath = '/home/user'; | |
| let history = []; | |
| let historyIndex = 0; | |
| const commands = { | |
| help: () => { | |
| return `Available commands:\n- help\n- ls\n- cd <dir>\n- cat <file>\n- echo <text>\n- clear\n- history\n- mkdir <dir>\n- touch <file>\n- rm <file|dir>\n- generate kicklang`; | |
| }, | |
| ls: () => { | |
| const node = getNode(currentPath); | |
| if (!node || node.type !== 'dir') return 'Not a directory'; | |
| return Object.keys(node.children).join(' '); | |
| }, | |
| cd: (args) => { | |
| if (!args[0]) return `Usage: cd <dir>`; | |
| const target = resolvePath(currentPath, args[0]); | |
| const node = getNode(target); | |
| if (!node || node.type !== 'dir') return `No such directory: ${args[0]}`; | |
| currentPath = target; | |
| prompt.textContent = `${currentPath}$`; | |
| return ''; | |
| }, | |
| cat: (args) => { | |
| if (!args[0]) return `Usage: cat <file>`; | |
| const path = resolvePath(currentPath, args[0]); | |
| const node = getNode(path); | |
| if (!node || node.type !== 'file') return `No such file: ${args[0]}`; | |
| return node.content; | |
| }, | |
| echo: (args) => { | |
| return args.join(' '); | |
| }, | |
| clear: () => { | |
| output.innerHTML = ''; | |
| return ''; | |
| }, | |
| history: () => { | |
| return history.join('\n'); | |
| }, | |
| mkdir: (args) => { | |
| if (!args[0]) return `Usage: mkdir <dir>`; | |
| const path = resolvePath(currentPath, args[0]); | |
| const parentPath = path.split('/').slice(0, -1).join('/') || '/'; | |
| const dirName = path.split('/').pop(); | |
| const parent = getNode(parentPath); | |
| if (!parent || parent.type !== 'dir') return `Invalid parent directory`; | |
| if (parent.children[dirName]) return `Directory already exists: ${dirName}`; | |
| parent.children[dirName] = { type: 'dir', children: {} }; | |
| return ''; | |
| }, | |
| touch: (args) => { | |
| if (!args[0]) return `Usage: touch <file>`; | |
| const path = resolvePath(currentPath, args[0]); | |
| const parentPath = path.split('/').slice(0, -1).join('/') || '/'; | |
| const fileName = path.split('/').pop(); | |
| const parent = getNode(parentPath); | |
| if (!parent || parent.type !== 'dir') return `Invalid path`; | |
| if (parent.children[fileName]) return `File already exists: ${fileName}`; | |
| parent.children[fileName] = { type: 'file', content: '' }; | |
| return ''; | |
| }, | |
| rm: (args) => { | |
| if (!args[0]) return `Usage: rm <file|dir>`; | |
| const path = resolvePath(currentPath, args[0]); | |
| const parentPath = path.split('/').slice(0, -1).join('/') || '/'; | |
| const name = path.split('/').pop(); | |
| const parent = getNode(parentPath); | |
| if (!parent || parent.type !== 'dir') return `Invalid path`; | |
| if (!parent.children[name]) return `No such file or directory: ${name}`; | |
| delete parent.children[name]; | |
| return ''; | |
| }, | |
| generate: (args) => { | |
| if (args[0] !== 'kicklang') return 'Usage: generate kicklang'; | |
| return generateKickLangScript(); | |
| } | |
| }; | |
| function getNode(path) { | |
| const parts = path.split('/').filter(p => p); | |
| let node = vfs['/']; | |
| for (let part of parts) { | |
| if (!node || node.type !== 'dir' || !node.children[part]) return null; | |
| node = node.children[part]; | |
| } | |
| return node; | |
| } | |
| function resolvePath(base, relative) { | |
| if (relative.startsWith('/')) return relative; | |
| const baseParts = base.split('/').filter(p => p); | |
| const relParts = relative.split('/').filter(p => p); | |
| for (let part of relParts) { | |
| if (part === '..') baseParts.pop(); | |
| else if (part !== '.') baseParts.push(part); | |
| } | |
| return '/' + baseParts.join('/'); | |
| } | |
| function addOutput(lines, className = '') { | |
| const div = document.createElement('div'); | |
| div.className = className; | |
| div.textContent = lines; | |
| output.appendChild(div); | |
| output.scrollTop = output.scrollHeight; | |
| } | |
| function executeCommand(cmd) { | |
| const [command, ...args] = cmd.trim().split(' '); | |
| const handler = commands[command]; | |
| if (handler) { | |
| const result = handler(args); | |
| return result; | |
| } else { | |
| return `Command not found: ${command}`; | |
| } | |
| } | |
| function generateKickLangScript() { | |
| const script = []; | |
| script.push('// KickLang Script Template\n'); | |
| script.push(`// Initial VFS State\nconst vfs = ${JSON.stringify(vfs, null, 2)};`); | |
| script.push('\n// KickLang Simulation Logic\nfunction simulateCLI() {'); | |
| script.push(' let currentPath = "' + currentPath + '";'); | |
| script.push(' let history = ' + JSON.stringify(history) + ';\n'); | |
| script.push(' // Define commands here...\n'); | |
| script.push(' // Add logic to simulate CLI behavior...\n'); | |
| script.push(' console.log("KickLang simulation started");'); | |
| script.push('}'); | |
| script.push('\nsimulateCLI();'); | |
| return script.join('\n'); | |
| } | |
| input.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter') { | |
| const cmd = input.value; | |
| if (cmd.trim()) { | |
| history.push(`$ ${cmd}`); | |
| addOutput(`$ ${cmd}`); | |
| const result = executeCommand(cmd); | |
| if (result) addOutput(result); | |
| historyIndex = history.length; | |
| } | |
| input.value = ''; | |
| } else if (e.key === 'ArrowUp') { | |
| if (historyIndex > 0) { | |
| historyIndex--; | |
| input.value = history[historyIndex].replace(/^\$ /, ''); | |
| } | |
| } else if (e.key === 'ArrowDown') { | |
| if (historyIndex < history.length) { | |
| historyIndex++; | |
| input.value = historyIndex < history.length | |
| ? history[historyIndex].replace(/^\$ /, '') | |
| : ''; | |
| } | |
| } | |
| }); | |
| // Initial prompt | |
| addOutput('Welcome to KickLang CLI Simulator. Type "help" to get started.'); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=dokii/cli-sim-2-kl" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |