cloud-compiler

A real-time, low-latency code ...
Log | Files | Refs | README | LICENSE

cpp.html (44046B)


      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
      6     <title>Amit Dutta // C++ Compiler</title>
      7     <link rel="icon" type="image/x-icon" href="https://compiler.aranag.site/logo.png">
      8     
      9     <!-- Fonts & Icons -->
     10     <link rel="preconnect" href="https://fonts.googleapis.com">
     11     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
     12     <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
     13     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
     14     
     15     <!-- Tailwind CSS -->
     16     <script src="https://cdn.tailwindcss.com"></script>
     17     
     18     <!-- CodeMirror 5 (Professional Editor) -->
     19     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
     20     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/theme/dracula.min.css">
     21     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
     22     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/clike/clike.min.js"></script>
     23     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/closebrackets.min.js"></script>
     24     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/matchbrackets.min.js"></script>
     25     <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/selection/active-line.min.js"></script>
     26 
     27     <!-- Xterm.js -->
     28     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" />
     29     <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
     30     <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
     31 
     32     <style>
     33         :root {
     34             --bg-main: #050505;
     35             --accent: #bef264; /* Lime 300 */
     36             --text-muted: #737373;
     37             --border-color: rgba(255, 255, 255, 0.1);
     38         }
     39 
     40         body {
     41             font-family: 'Inter', sans-serif;
     42             background-color: var(--bg-main);
     43             color: #f5f5f5;
     44             height: 100vh;
     45             height: 100dvh;
     46             overflow: hidden;
     47             display: flex;
     48             flex-direction: column;
     49         }
     50 
     51         /* Portfolio Aesthetic */
     52         .font-mono { font-family: 'JetBrains Mono', monospace; }
     53         .font-heading { font-family: 'Space Grotesk', sans-serif; }
     54         
     55         /* Noise Overlay */
     56         .bg-noise {
     57             position: fixed; top: 0; left: 0; width: 100%; height: 100%;
     58             pointer-events: none; z-index: 0; opacity: 0.03;
     59             background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
     60         }
     61 
     62         /* CRT Scanline */
     63         .crt-scanline {
     64             position: fixed; top: 0; left: 0; width: 100%; height: 2px;
     65             background: rgba(190, 242, 100, 0.1); opacity: 0.5;
     66             pointer-events: none; z-index: 50;
     67             animation: scanline 8s linear infinite;
     68         }
     69         @keyframes scanline { 0% { top: -10vh; } 100% { top: 110vh; } }
     70 
     71         /* CodeMirror Customization */
     72         .CodeMirror {
     73             height: 100% !important;
     74             font-family: 'JetBrains Mono', monospace;
     75             font-size: 13px;
     76             background-color: #0c0f16 !important; /* Slightly lighter than pure black */
     77             color: #f8f8f2;
     78         }
     79         .CodeMirror-gutters {
     80             background-color: #0c0f16 !important;
     81             border-right: 1px solid rgba(255,255,255,0.05) !important;
     82         }
     83         .CodeMirror-linenumber {
     84             color: #555 !important;
     85         }
     86         .CodeMirror-cursor {
     87             border-left: 2px solid var(--accent) !important;
     88         }
     89         .CodeMirror-selected {
     90             background: rgba(190, 242, 100, 0.2) !important;
     91         }
     92         .cm-s-dracula .CodeMirror-activeline-background {
     93             background: rgba(255, 255, 255, 0.03) !important;
     94         }
     95 
     96         /* Scrollbar styling */
     97         .CodeMirror-scroll::-webkit-scrollbar, 
     98         .xterm-viewport::-webkit-scrollbar,
     99         .custom-scrollbar::-webkit-scrollbar { 
    100             width: 6px; height: 6px; 
    101         }
    102         .CodeMirror-scroll::-webkit-scrollbar-track, 
    103         .xterm-viewport::-webkit-scrollbar-track,
    104         .custom-scrollbar::-webkit-scrollbar-track { 
    105             background: #050505; 
    106         }
    107         .CodeMirror-scroll::-webkit-scrollbar-thumb, 
    108         .xterm-viewport::-webkit-scrollbar-thumb,
    109         .custom-scrollbar::-webkit-scrollbar-thumb { 
    110             background: #333; border-radius: 3px; 
    111         }
    112 
    113         /* Mobile Helper Bar */
    114         #mobile-helper-bar {
    115             display: none; /* Shown via JS on mobile */
    116             background: #151515;
    117             border-top: 1px solid rgba(255,255,255,0.1);
    118             padding: 8px;
    119             overflow-x: auto;
    120             white-space: nowrap;
    121             -webkit-overflow-scrolling: touch;
    122         }
    123         @media (max-width: 768px) {
    124             #mobile-helper-bar { display: flex; gap: 8px; }
    125         }
    126         .helper-key {
    127             background: rgba(255,255,255,0.1);
    128             color: var(--accent);
    129             border: 1px solid rgba(255,255,255,0.1);
    130             border-radius: 4px;
    131             padding: 6px 12px;
    132             font-family: 'JetBrains Mono', monospace;
    133             font-size: 12px;
    134             font-weight: bold;
    135             cursor: pointer;
    136             user-select: none;
    137         }
    138         .helper-key:active { background: var(--accent); color: black; }
    139 
    140         /* Toast Notification */
    141         .toast {
    142             position: fixed;
    143             bottom: 2rem;
    144             left: 50%;
    145             transform: translateX(-50%) translateY(100px);
    146             background: #1a1a1a;
    147             border: 1px solid var(--accent);
    148             color: var(--accent);
    149             padding: 0.5rem 1.5rem;
    150             border-radius: 9999px;
    151             font-family: 'JetBrains Mono', monospace;
    152             font-size: 0.8rem;
    153             transition: transform 0.3s ease;
    154             z-index: 100;
    155         }
    156         .toast.show { transform: translateX(-50%) translateY(0); }
    157         
    158         /* Connection Dot Pulse */
    159         .pulse-dot {
    160             width: 8px;
    161             height: 8px;
    162             border-radius: 50%;
    163             display: inline-block;
    164             box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7);
    165             animation: pulse-white 2s infinite;
    166         }
    167         .pulse-dot.connected {
    168             background-color: #bef264; /* Lime */
    169             box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7);
    170             animation: pulse-lime 2s infinite;
    171         }
    172         .pulse-dot.disconnected {
    173             background-color: #ef4444; /* Red */
    174             box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7);
    175             animation: pulse-red 2s infinite;
    176         }
    177         
    178         @keyframes pulse-lime {
    179             0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0.7); }
    180             70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(190, 242, 100, 0); }
    181             100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(190, 242, 100, 0); }
    182         }
    183         @keyframes pulse-red {
    184             0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
    185             70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }
    186             100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
    187         }
    188 
    189         /* AI Text Overlay */
    190         .ai-overlay {
    191             position: absolute;
    192             bottom: 10px;
    193             right: 20px;
    194             background: rgba(20, 20, 20, 0.9);
    195             border: 1px solid #ef4444;
    196             color: #fca5a5;
    197             padding: 8px 12px;
    198             border-radius: 6px;
    199             font-family: 'JetBrains Mono', monospace;
    200             font-size: 12px;
    201             z-index: 60;
    202             display: none;
    203             backdrop-filter: blur(4px);
    204             animation: slideIn 0.3s ease-out;
    205             box-shadow: 0 4px 12px rgba(0,0,0,0.5);
    206         }
    207         .ai-overlay.visible { display: flex; align-items: center; gap: 8px; }
    208         
    209         .ai-link {
    210             color: #fff;
    211             text-decoration: underline;
    212             text-decoration-style: dotted;
    213             text-underline-offset: 4px;
    214             cursor: pointer;
    215             font-weight: bold;
    216             transition: color 0.2s;
    217         }
    218         .ai-link:hover { color: #bef264; text-decoration-style: solid; }
    219 
    220         @keyframes slideIn {
    221             from { transform: translateY(20px); opacity: 0; }
    222             to { transform: translateY(0); opacity: 1; }
    223         }
    224 
    225         /* Modals (AI & Clear) */
    226         .modal-overlay {
    227             position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    228             background: rgba(0,0,0,0.8); backdrop-filter: blur(5px);
    229             z-index: 200; display: none; align-items: center; justify-content: center;
    230         }
    231         .modal-overlay.open { display: flex; }
    232 
    233         .modal-content {
    234             background: #0f0f0f;
    235             border: 1px solid var(--accent);
    236             width: 90%; max-width: 600px;
    237             border-radius: 12px;
    238             display: flex; flex-direction: column;
    239             box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
    240             overflow: hidden;
    241             animation: modalPop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    242         }
    243 
    244         @keyframes modalPop {
    245             0% { transform: scale(0.9); opacity: 0; }
    246             100% { transform: scale(1); opacity: 1; }
    247         }
    248 
    249         /* Editor Toolbar Buttons */
    250         .editor-btn {
    251             background: rgba(255,255,255,0.05);
    252             border: 1px solid rgba(255,255,255,0.1);
    253             color: #737373;
    254             width: 32px;
    255             height: 32px;
    256             display: flex;
    257             align-items: center;
    258             justify-content: center;
    259             border-radius: 4px;
    260             transition: all 0.2s;
    261             cursor: pointer;
    262         }
    263         .editor-btn:hover {
    264             background: rgba(255,255,255,0.1);
    265             color: #fff;
    266             border-color: rgba(255,255,255,0.3);
    267         }
    268         .editor-btn.danger:hover {
    269             background: rgba(239, 68, 68, 0.1);
    270             color: #ef4444;
    271             border-color: #ef4444;
    272         }
    273     </style>
    274 </head>
    275 <body class="antialiased selection:bg-lime-300 selection:text-black">
    276 
    277     <div class="bg-noise"></div>
    278     <div class="crt-scanline"></div>
    279     <div id="toast" class="toast">Link Copied to Clipboard!</div>
    280 
    281     <!-- AI Overlay in Terminal -->
    282     <div id="ai-suggestion" class="ai-overlay">
    283         <i class="fas fa-exclamation-triangle text-red-500"></i>
    284         <span>Error detected. <span id="ask-ai-link" class="ai-link">Ask AI</span> to fix it.</span>
    285     </div>
    286 
    287     <!-- Clear Confirmation Modal -->
    288     <div id="clear-modal" class="modal-overlay">
    289         <div class="modal-content max-w-[320px] p-0 border-red-500/50">
    290             <div class="bg-red-500/10 px-6 py-4 border-b border-red-500/20">
    291                 <h3 class="font-heading font-bold text-lg text-red-500 flex items-center gap-2">
    292                     <i class="fas fa-exclamation-circle"></i> CLEAR CODE
    293                 </h3>
    294             </div>
    295             <div class="p-6 text-center">
    296                 <p class="text-neutral-300 text-sm font-sans mb-6">Are you sure you want to clear the editor? This action will remove all current code.</p>
    297                 <div class="flex justify-center gap-3">
    298                     <button id="cancel-clear-btn" class="px-4 py-2 rounded text-xs font-mono font-bold uppercase text-neutral-400 hover:text-white hover:bg-white/10 transition-all border border-transparent">Cancel</button>
    299                     <button id="confirm-clear-btn" class="bg-red-500/10 hover:bg-red-500 hover:text-black text-red-500 border border-red-500/20 px-4 py-2 rounded text-xs font-mono font-bold uppercase transition-all flex items-center gap-2">
    300                         <i class="fas fa-trash-alt"></i> Confirm
    301                     </button>
    302                 </div>
    303             </div>
    304         </div>
    305     </div>
    306 
    307     <!-- AI Fix Modal -->
    308     <div id="ai-modal" class="modal-overlay">
    309         <div class="modal-content max-h-[80vh]">
    310             <!-- Modal Header -->
    311             <div class="bg-white/5 px-6 py-4 border-b border-white/10 flex justify-between items-center">
    312                 <h3 class="font-heading font-bold text-lg text-lime-300 flex items-center gap-2">
    313                     <i class="fas fa-robot"></i> AI Diagnosis
    314                 </h3>
    315                 <button id="close-modal" class="text-neutral-500 hover:text-white transition-colors">
    316                     <i class="fas fa-times"></i>
    317                 </button>
    318             </div>
    319             
    320             <!-- Modal Body -->
    321             <div class="p-6 overflow-y-auto custom-scrollbar flex-1">
    322                 <div id="ai-loading" class="hidden flex flex-col items-center justify-center py-8 gap-4">
    323                     <div class="pulse-dot connected" style="width: 12px; height: 12px;"></div>
    324                     <p class="font-mono text-neutral-400 text-sm animate-pulse">Analyzing compile error...</p>
    325                 </div>
    326 
    327                 <div id="ai-result" class="hidden space-y-4">
    328                     <div>
    329                         <h4 class="font-mono text-xs uppercase text-neutral-500 mb-2">Explanation</h4>
    330                         <p id="ai-explanation" class="text-sm text-neutral-200 leading-relaxed font-sans"></p>
    331                     </div>
    332                     
    333                     <div>
    334                         <h4 class="font-mono text-xs uppercase text-neutral-500 mb-2">Suggested Fix</h4>
    335                         <div class="relative group">
    336                             <pre id="ai-code-preview" class="bg-black/30 border border-white/10 p-3 rounded text-xs font-mono text-lime-100 overflow-x-auto custom-scrollbar"></pre>
    337                         </div>
    338                     </div>
    339                 </div>
    340                 
    341                 <div id="ai-error-msg" class="hidden text-red-400 text-sm font-mono text-center py-4"></div>
    342             </div>
    343 
    344             <!-- Modal Footer -->
    345             <div class="bg-white/5 px-6 py-4 border-t border-white/10 flex justify-end gap-3">
    346                 <button id="cancel-fix-btn" class="px-4 py-2 rounded text-xs font-mono font-bold uppercase text-neutral-400 hover:text-white hover:bg-white/10 transition-all">Dismiss</button>
    347                 <button id="apply-fix-btn" disabled class="bg-lime-300/10 hover:bg-lime-300 hover:text-black text-lime-300 border border-lime-300/20 px-4 py-2 rounded text-xs font-mono font-bold uppercase transition-all flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed">
    348                     <i class="fas fa-check"></i> Apply Fix
    349                 </button>
    350             </div>
    351         </div>
    352     </div>
    353 
    354     <!-- Header (Responsive) -->
    355     <header class="h-auto md:h-16 flex flex-col md:flex-row items-center justify-between px-4 py-3 md:px-6 shrink-0 border-b border-white/10 z-20 bg-neutral-900/50 backdrop-blur-md gap-3 md:gap-4">
    356         
    357         <!-- Top Row: Title & Editor Tools -->
    358         <div class="flex items-center justify-between w-full md:w-auto gap-6">
    359             <h1 class="text-lg md:text-xl font-heading font-bold text-white tracking-tight flex items-center">
    360                 <span class="text-lime-300 mr-2">//</span>CPP.COMPILER
    361                 <span id="conn-dot" class="pulse-dot disconnected ml-3" title="Disconnected"></span>
    362             </h1>
    363             
    364             <!-- Editor Tools -->
    365             <div class="flex items-center gap-2">
    366                 <button id="undo-btn" class="editor-btn" title="Undo (Ctrl+Z)">
    367                     <i class="fas fa-undo text-xs"></i>
    368                 </button>
    369                 <button id="redo-btn" class="editor-btn" title="Redo (Ctrl+Y)">
    370                     <i class="fas fa-redo text-xs"></i>
    371                 </button>
    372                 <div class="w-px h-4 bg-white/10 mx-1"></div>
    373                 <button id="clear-code-btn" class="editor-btn danger" title="Clear Code">
    374                     <i class="fas fa-times text-xs"></i>
    375                 </button>
    376             </div>
    377             
    378             <!-- Mobile Only: Exit Link -->
    379             <a href="./index.html" class="md:hidden font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors ml-auto">[ EXIT ]</a>
    380         </div>
    381         
    382         <!-- Middle: Connection Text -->
    383         <div class="hidden md:flex items-center gap-2 font-mono text-xs text-neutral-500">
    384              <span id="connection-status">Connecting to server...</span>
    385         </div>
    386 
    387         <!-- Bottom/Right: Buttons -->
    388         <div class="flex items-center gap-2 w-full md:w-auto justify-end">
    389             <a href="./index.html" class="hidden md:inline font-mono text-[10px] text-neutral-500 hover:text-white uppercase tracking-wider transition-colors mr-2">[ EXIT ]</a>
    390             
    391             <button id="download-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Download .cpp">
    392                 <i class="fas fa-download"></i>
    393             </button>
    394             
    395             <button id="reset-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Reset Terminal">
    396                 <i class="fas fa-rotate-left"></i>
    397             </button>
    398 
    399             <button id="share-btn" class="bg-white/5 hover:bg-neutral-800 text-white border border-white/10 px-3 py-2 rounded font-mono text-[10px] font-bold uppercase tracking-wider flex items-center justify-center transition-all" title="Share Code">
    400                 <i class="fas fa-share-alt"></i>
    401             </button>
    402             
    403             <button id="run-btn" disabled class="bg-white/5 hover:bg-lime-300 hover:text-black disabled:opacity-50 disabled:cursor-not-allowed text-white border border-white/10 px-4 py-2 rounded font-mono text-xs font-bold uppercase tracking-wider flex items-center gap-2 transition-all flex-1 md:flex-none justify-center shadow-lg shadow-black/50">
    404                 <i class="fas fa-play text-[10px]"></i> <span class="md:hidden lg:inline">EXECUTE</span><span class="hidden md:inline lg:hidden">RUN</span>
    405             </button>
    406         </div>
    407     </header>
    408 
    409     <!-- Main Workspace -->
    410     <div class="flex-1 flex flex-col md:flex-row min-h-0 z-10 relative">
    411         
    412         <!-- Code Editor -->
    413         <div class="flex-1 flex flex-col h-[60%] md:h-auto min-h-0 border-b md:border-b-0 md:border-r border-white/10 relative group">
    414             <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0">
    415                 <span>SRC // main.cpp</span>
    416                 <span class="text-neutral-600">G++ 9.4.0</span>
    417             </div>
    418             
    419             <!-- CodeMirror Container -->
    420             <div id="editor-container" class="relative bg-[#0c0f16] flex-1 overflow-hidden">
    421                 <textarea id="code-input" class="hidden">#include <iostream>
    422 
    423 int main() {
    424     std::cout << "Hello C++ Compiler!" << std::endl;
    425     return 0;
    426 }</textarea>
    427             </div>
    428             
    429             <!-- Mobile Helper Bar -->
    430             <div id="mobile-helper-bar">
    431                 <div class="helper-key" data-char="    ">Tab</div>
    432                 <div class="helper-key" data-char=";">;</div>
    433                 <div class="helper-key" data-char="=">=</div>
    434                 <div class="helper-key" data-char="()">()</div>
    435                 <div class="helper-key" data-char="[]">[]</div>
    436                 <div class="helper-key" data-char="{}">{}</div>
    437                 <div class="helper-key" data-char='""'>""</div>
    438                 <div class="helper-key" data-char="''">''</div>
    439                 <div class="helper-key" data-char="#">#</div>
    440                 <div class="helper-key" data-char="<<">&lt;&lt;</div>
    441                 <div class="helper-key" data-char=">>">&gt;&gt;</div>
    442                 <div class="helper-key" data-char="cout">cout</div>
    443             </div>
    444         </div>
    445 
    446         <!-- Terminal -->
    447         <div class="flex-1 flex flex-col h-[40%] md:h-auto min-h-0 bg-[#050505]">
    448             <div class="bg-black/20 px-4 py-2 text-[10px] font-mono text-lime-300 uppercase border-b border-white/10 flex justify-between items-center shrink-0">
    449                 <span>OUT // TERMINAL</span>
    450                 <div class="flex gap-2">
    451                     <button id="copy-btn" class="text-neutral-500 hover:text-white transition-colors" title="Copy Output"><i class="fas fa-copy"></i></button>
    452                     <span class="text-neutral-600">XTERM.JS</span>
    453                 </div>
    454             </div>
    455             <div class="flex-1 relative">
    456                 <div id="terminal-container" class="absolute inset-0 w-full h-full p-2 overflow-hidden"></div>
    457             </div>
    458         </div>
    459     </div>
    460 
    461     <script type="module">
    462         import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js";
    463         import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js";
    464         import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth.js";
    465 
    466         // --- Firebase Config ---
    467         const firebaseConfig = {
    468             apiKey: "AIzaSyC8U49NgW7EtYBeKL0Sw08-QvM_Bl59zDw",
    469             authDomain: "compiler-aranag-site.firebaseapp.com",
    470             projectId: "compiler-aranag-site",
    471             storageBucket: "compiler-aranag-site.firebasestorage.app",
    472             messagingSenderId: "558890639400",
    473             appId: "1:558890639400:web:125525d10ab51696a5951d",
    474             measurementId: "G-KH9BGSRRGY"
    475         };
    476 
    477         // Initialize Firebase
    478         const app = initializeApp(firebaseConfig);
    479         const db = getFirestore(app);
    480         const auth = getAuth(app);
    481 
    482         // Attempt initial sign-in
    483         signInAnonymously(auth).catch((error) => {
    484             console.warn("Auto-Auth failed. App will try unauthenticated access.", error.code);
    485         });
    486 
    487         // --- Helper: Generate ID ---
    488         function generateId(length = 7) {
    489             const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    490             let result = '';
    491             for (let i = 0; i < length; i++) {
    492                 result += chars.charAt(Math.floor(Math.random() * chars.length));
    493             }
    494             return result;
    495         }
    496 
    497         // --- DOM Elements ---
    498         const runBtn = document.getElementById('run-btn');
    499         const resetBtn = document.getElementById('reset-btn');
    500         const shareBtn = document.getElementById('share-btn');
    501         const copyBtn = document.getElementById('copy-btn');
    502         const downloadBtn = document.getElementById('download-btn');
    503         const connDot = document.getElementById('conn-dot');
    504         const connectionStatus = document.getElementById('connection-status');
    505         const toast = document.getElementById('toast');
    506         
    507         // Editor Tool Elements
    508         const undoBtn = document.getElementById('undo-btn');
    509         const redoBtn = document.getElementById('redo-btn');
    510         const clearCodeBtn = document.getElementById('clear-code-btn');
    511         const clearModal = document.getElementById('clear-modal');
    512         const cancelClearBtn = document.getElementById('cancel-clear-btn');
    513         const confirmClearBtn = document.getElementById('confirm-clear-btn');
    514 
    515         // AI Elements
    516         const aiSuggestion = document.getElementById('ai-suggestion');
    517         const askAiLink = document.getElementById('ask-ai-link');
    518         const aiModal = document.getElementById('ai-modal');
    519         const closeModal = document.getElementById('close-modal');
    520         const cancelFixBtn = document.getElementById('cancel-fix-btn');
    521         const applyFixBtn = document.getElementById('apply-fix-btn');
    522         const aiLoading = document.getElementById('ai-loading');
    523         const aiResult = document.getElementById('ai-result');
    524         const aiExplanation = document.getElementById('ai-explanation');
    525         const aiCodePreview = document.getElementById('ai-code-preview');
    526         const aiErrorMsg = document.getElementById('ai-error-msg');
    527 
    528         // --- State ---
    529         let socket = null;
    530         let currentLine = ""; 
    531         let startTime = 0;
    532         let lastSuggestedCode = "";
    533         let outputBuffer = "";
    534 
    535         // --- CodeMirror Setup ---
    536         const editor = CodeMirror.fromTextArea(document.getElementById("code-input"), {
    537             mode: "text/x-c++src",
    538             theme: "dracula",
    539             lineNumbers: true,
    540             indentUnit: 4,
    541             matchBrackets: true,
    542             autoCloseBrackets: true,
    543             styleActiveLine: true,
    544             inputStyle: "contenteditable",
    545             viewportMargin: Infinity,
    546             extraKeys: {
    547                 "Backspace": function(cm) {
    548                     if (cm.somethingSelected()) {
    549                         cm.execCommand("delCharBefore");
    550                         return;
    551                     }
    552                     var cursor = cm.getCursor();
    553                     var line = cm.getLine(cursor.line);
    554                     // If cursor is not at start, and everything before it is whitespace
    555                     if (cursor.ch > 0 && /^\s+$/.test(line.slice(0, cursor.ch))) {
    556                         cm.execCommand("indentLess");
    557                     } else {
    558                         cm.execCommand("delCharBefore");
    559                     }
    560                 }
    561             },
    562         });
    563 
    564         // Fix resize issues
    565         window.addEventListener('resize', () => editor.refresh());
    566 
    567         // Local Auto-Save
    568         const LOCAL_STORAGE_KEY = 'cpp_compiler_code_autosave';
    569         editor.on('change', () => {
    570             localStorage.setItem(LOCAL_STORAGE_KEY, editor.getValue());
    571         });
    572 
    573         // Load Auto-Save on Start (if not shared)
    574         const savedCode = localStorage.getItem(LOCAL_STORAGE_KEY);
    575         if (savedCode && !window.location.search.includes('share') && !window.location.search.includes('code')) {
    576             editor.setValue(savedCode);
    577         }
    578 
    579         // --- Editor Toolbar Logic ---
    580         undoBtn.addEventListener('click', () => { editor.undo(); editor.focus(); });
    581         redoBtn.addEventListener('click', () => { editor.redo(); editor.focus(); });
    582 
    583         clearCodeBtn.addEventListener('click', () => {
    584             clearModal.classList.add('open');
    585         });
    586 
    587         cancelClearBtn.addEventListener('click', () => {
    588             clearModal.classList.remove('open');
    589         });
    590 
    591         confirmClearBtn.addEventListener('click', () => {
    592             editor.setValue('');
    593             editor.clearHistory();
    594             editor.focus();
    595             clearModal.classList.remove('open');
    596             showToast("Editor Cleared");
    597         });
    598 
    599         clearModal.addEventListener('click', (e) => {
    600             if (e.target === clearModal) clearModal.classList.remove('open');
    601         });
    602 
    603         // --- Mobile Helper Bar ---
    604         document.querySelectorAll('.helper-key').forEach(key => {
    605             key.addEventListener('click', (e) => {
    606                 const char = key.getAttribute('data-char');
    607                 const doc = editor.getDoc();
    608                 const cursor = doc.getCursor();
    609                 
    610                 if (char === '()') {
    611                     doc.replaceRange('()', cursor);
    612                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    613                 } else if (char === '[]') {
    614                     doc.replaceRange('[]', cursor);
    615                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    616                 } else if (char === '{}') {
    617                     doc.replaceRange('{}', cursor);
    618                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    619                 } else if (char === '""') {
    620                     doc.replaceRange('""', cursor);
    621                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    622                 } else if (char === "''") {
    623                     doc.replaceRange("''", cursor);
    624                     doc.setCursor({line: cursor.line, ch: cursor.ch + 1});
    625                 } else if (char === "cout") {
    626                     doc.replaceRange('cout << ', cursor);
    627                     doc.setCursor({line: cursor.line, ch: cursor.ch + 8});
    628                 } else {
    629                     doc.replaceRange(char, cursor);
    630                 }
    631                 editor.focus();
    632             });
    633         });
    634 
    635         // --- Download Button ---
    636         downloadBtn.addEventListener('click', () => {
    637             const code = editor.getValue();
    638             const blob = new Blob([code], { type: 'text/x-c++src' });
    639             const url = window.URL.createObjectURL(blob);
    640             const a = document.createElement('a');
    641             a.href = url;
    642             a.download = 'main.cpp';
    643             document.body.appendChild(a);
    644             a.click();
    645             window.URL.revokeObjectURL(url);
    646             document.body.removeChild(a);
    647             showToast("Downloaded main.cpp");
    648         });
    649 
    650         window.addEventListener('load', async () => {
    651             const params = new URLSearchParams(window.location.search);
    652             const shareId = params.get('share');
    653             const sharedCodeOld = params.get('code');
    654 
    655             if (shareId) {
    656                 // Fetch from Firebase
    657                 try {
    658                     toast.textContent = "Loading shared code...";
    659                     toast.classList.add('show');
    660                     
    661                     const docRef = doc(db, "shares", shareId);
    662                     const docSnap = await getDoc(docRef);
    663 
    664                     if (docSnap.exists()) {
    665                         const data = docSnap.data();
    666                         editor.setValue(data.code);
    667                         
    668                         // Restore Output if it exists
    669                         if (data.output && term) {
    670                             term.write('\r\n\x1b[38;2;115;115;115m> PREVIOUS OUTPUT:\x1b[0m\r\n');
    671                             term.write(data.output.replace(/\n/g, '\r\n'));
    672                             term.write('\r\n\x1b[38;2;115;115;115m> ----------------\x1b[0m\r\n');
    673                         }
    674 
    675                         toast.textContent = "Code loaded successfully";
    676                     } else {
    677                         toast.textContent = "Shared code not found";
    678                     }
    679                     setTimeout(() => toast.classList.remove('show'), 3000);
    680                 } catch (e) {
    681                     console.error("Fetch error:", e);
    682                     if (e.code === 'permission-denied') {
    683                          toast.textContent = "Error: Database Access Denied";
    684                     } else {
    685                          toast.textContent = "Error loading code";
    686                     }
    687                     setTimeout(() => toast.classList.remove('show'), 3000);
    688                 }
    689             } else if (sharedCodeOld) {
    690                 // Fallback for Base64
    691                 try { editor.setValue(atob(sharedCodeOld)); } 
    692                 catch(e) {}
    693             }
    694             setTimeout(connect, 500); 
    695         });
    696 
    697         // --- Terminal Setup ---
    698         const term = new Terminal({
    699             theme: {
    700                 background: '#050505',
    701                 foreground: '#f5f5f5',
    702                 cursor: '#bef264',
    703                 selectionBackground: 'rgba(190, 242, 100, 0.3)',
    704                 black: '#050505',
    705                 green: '#bef264', 
    706                 yellow: '#facc15',
    707                 red: '#ef4444',
    708             },
    709             fontFamily: "'JetBrains Mono', monospace",
    710             fontSize: 12, 
    711             cursorBlink: true,
    712             convertEol: true
    713         });
    714         const fitAddon = new FitAddon.FitAddon();
    715         term.loadAddon(fitAddon);
    716         term.open(document.getElementById('terminal-container'));
    717         fitAddon.fit();
    718         window.addEventListener('resize', () => fitAddon.fit());
    719 
    720         // Helper: Get Clean Terminal Output
    721         function getTerminalContent() {
    722             if (!term) return "";
    723             const buffer = term.buffer.active;
    724             let text = "";
    725             for (let i = 0; i < buffer.length; i++) {
    726                 const line = buffer.getLine(i);
    727                 if (line) {
    728                     let lineText = line.translateToString(true);
    729                     // Filter system messages
    730                     if(lineText.trim().startsWith("> [") || 
    731                        lineText.includes("SYSTEM READY") || 
    732                        lineText.includes("ATTEMPTING") || 
    733                        lineText.includes("CONNECTION") || 
    734                        lineText.includes("PREVIOUS OUTPUT") || 
    735                        lineText.includes("> ----------------") ||
    736                        lineText.includes("> ./a.out")
    737                        ) {
    738                         continue;
    739                     }
    740                     text += lineText + "\n";
    741                 }
    742             }
    743             return text.trim();
    744         }
    745 
    746         // Custom Key Handler for Ctrl+C Copy
    747         term.attachCustomKeyEventHandler((arg) => {
    748             if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") {
    749                 const selection = term.getSelection();
    750                 if (selection) {
    751                     fallbackCopyTextToClipboard(selection);
    752                     return false; 
    753                 }
    754             }
    755             return true;
    756         });
    757 
    758         term.write('\x1b[38;2;115;115;115m> SYSTEM READY.\r\n> ATTEMPTING CONNECTION...\x1b[0m\r\n');
    759 
    760         // --- WebSocket Logic ---
    761         function connect() {
    762             const url = "wss://compiler-z4x4.onrender.com"; 
    763             try { socket = new WebSocket(url); } catch (e) {
    764                 term.write(`\r\n\x1b[31m> INVALID URL.\x1b[0m\r\n`);
    765                 return;
    766             }
    767 
    768             socket.onopen = () => {
    769                 connDot.className = "pulse-dot connected ml-3";
    770                 if(connectionStatus) connectionStatus.textContent = "Connected to Server";
    771                 if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-lime-300";
    772                 
    773                 term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`);
    774                 runBtn.disabled = false;
    775             };
    776 
    777             socket.onclose = () => {
    778                 connDot.className = "pulse-dot disconnected ml-3";
    779                 if(connectionStatus) connectionStatus.textContent = "Disconnected";
    780                 if(connectionStatus) connectionStatus.className = "hidden md:flex items-center gap-2 font-mono text-xs text-red-500";
    781                 
    782                 term.write(`\r\n\x1b[31m> CONNECTION LOST. RECONNECTING...\x1b[0m\r\n`);
    783                 runBtn.disabled = true;
    784                 setTimeout(connect, 3000); 
    785                 socket = null;
    786             };
    787 
    788             socket.onmessage = (event) => {
    789                 const msg = JSON.parse(event.data);
    790                 if (msg.type === 'stdout') {
    791                     let text = msg.data;
    792                     outputBuffer += text;
    793 
    794                     // Trigger AI Overlay on Error
    795                     if (outputBuffer.toLowerCase().includes("error") || outputBuffer.toLowerCase().includes("warning")) {
    796                         aiSuggestion.classList.add('visible');
    797                     }
    798 
    799                     if (!text.includes('\r')) {
    800                          text = text.replace(/\n/g, '\r\n');
    801                     }
    802                     term.write(text);
    803                 } else if (msg.type === 'status') {
    804                     if (msg.msg.includes("Program finished")) {
    805                         const duration = (Date.now() - startTime) / 1000;
    806                         term.write(`\r\n\x1b[38;2;115;115;115m[Finished in ${duration.toFixed(3)}s]\x1b[0m\r\n`);
    807                     }
    808                 } else if (msg.type === 'ai_response') {
    809                     handleAiResponse(msg.data);
    810                 } else if (msg.type === 'ai_error') {
    811                     showAiError(msg.msg);
    812                 }
    813             };
    814         }
    815 
    816         // --- Run Logic ---
    817         runBtn.addEventListener('click', () => {
    818             if (!socket || socket.readyState !== WebSocket.OPEN) return;
    819             if (document.activeElement) document.activeElement.blur();
    820             
    821             term.reset();
    822             currentLine = ""; 
    823             outputBuffer = ""; 
    824             aiSuggestion.classList.remove('visible'); 
    825             
    826             let code = editor.getValue();
    827             code = code.replace(/\u00A0/g, " ").replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"');
    828             
    829             startTime = Date.now();
    830             term.write('\x1b[32m> g++ main.cpp -o main && ./main\x1b[0m\r\n');
    831 
    832             socket.send(JSON.stringify({
    833                 type: 'run',
    834                 code: code,
    835                 language: 'cpp'
    836             }));
    837             
    838             term.focus();
    839         });
    840 
    841         // --- AI Feature Logic ---
    842         askAiLink.addEventListener('click', () => {
    843             const errorContext = getTerminalContent();
    844             const currentCode = editor.getValue();
    845             
    846             aiModal.classList.add('open');
    847             aiLoading.classList.remove('hidden');
    848             aiResult.classList.add('hidden');
    849             aiErrorMsg.classList.add('hidden');
    850             applyFixBtn.disabled = true;
    851 
    852             socket.send(JSON.stringify({
    853                 type: 'ai_fix',
    854                 code: currentCode,
    855                 error: errorContext,
    856                 language: 'cpp'
    857             }));
    858         });
    859 
    860         function handleAiResponse(data) {
    861             aiLoading.classList.add('hidden');
    862             aiResult.classList.remove('hidden');
    863             aiExplanation.textContent = data.explanation;
    864             aiCodePreview.textContent = data.fixed_code;
    865             lastSuggestedCode = data.fixed_code;
    866             applyFixBtn.disabled = false;
    867         }
    868 
    869         function showAiError(msg) {
    870             aiLoading.classList.add('hidden');
    871             aiErrorMsg.textContent = msg;
    872             aiErrorMsg.classList.remove('hidden');
    873         }
    874 
    875         applyFixBtn.addEventListener('click', () => {
    876             if (lastSuggestedCode) {
    877                 editor.setValue(lastSuggestedCode);
    878                 closeAiModal();
    879                 showToast("Fix Applied Successfully!");
    880                 aiSuggestion.classList.remove('visible');
    881             }
    882         });
    883 
    884         function closeAiModal() {
    885             aiModal.classList.remove('open');
    886         }
    887         closeModal.addEventListener('click', closeAiModal);
    888         cancelFixBtn.addEventListener('click', closeAiModal);
    889         aiModal.addEventListener('click', (e) => {
    890             if (e.target === aiModal) closeAiModal();
    891         });
    892 
    893         // --- Reset Logic ---
    894         resetBtn.addEventListener('click', () => {
    895             term.reset();
    896             currentLine = "";
    897             outputBuffer = ""; 
    898             aiSuggestion.classList.remove('visible');
    899             term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`);
    900         });
    901 
    902         // --- Share Functionality with Firebase ---
    903         shareBtn.addEventListener('click', async () => {
    904             const originalIcon = shareBtn.innerHTML;
    905             shareBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
    906             shareBtn.disabled = true;
    907 
    908             try {
    909                 if (!auth.currentUser) {
    910                     try {
    911                         await signInAnonymously(auth);
    912                     } catch (authError) {
    913                         console.warn("Anonymous auth failed:", authError.code);
    914                     }
    915                 }
    916 
    917                 const code = editor.getValue();
    918                 const output = getTerminalContent();
    919                 const shareId = generateId();
    920                 
    921                 await setDoc(doc(db, "shares", shareId), {
    922                     code: code,
    923                     language: 'cpp',
    924                     output: output,
    925                     createdAt: new Date().toISOString()
    926                 });
    927 
    928                 const url = new URL(window.location.href);
    929                 url.searchParams.delete('code');
    930                 url.searchParams.set('share', shareId);
    931                 const shareUrl = url.toString();
    932 
    933                 if (navigator.share) {
    934                     try {
    935                         await navigator.share({
    936                             title: document.title,
    937                             text: 'Check out my C++ code!',
    938                             url: shareUrl
    939                         });
    940                     } catch (err) {
    941                         fallbackCopyTextToClipboard(shareUrl);
    942                     }
    943                 } else {
    944                     fallbackCopyTextToClipboard(shareUrl);
    945                 }
    946             } catch (error) {
    947                 console.error("Share failed:", error);
    948                 if (error.code === 'permission-denied') {
    949                     showToast("Share Failed: Access Denied");
    950                 } else {
    951                     showToast("Share Failed: " + error.message);
    952                 }
    953             } finally {
    954                 shareBtn.innerHTML = originalIcon;
    955                 shareBtn.disabled = false;
    956             }
    957         });
    958 
    959         function showToast(msg) {
    960             toast.textContent = msg;
    961             toast.classList.add('show');
    962             setTimeout(() => toast.classList.remove('show'), 3000);
    963         }
    964 
    965         // --- Smart Copy Function ---
    966         copyBtn.addEventListener('click', () => {
    967             const text = getTerminalContent();
    968             fallbackCopyTextToClipboard(text);
    969         });
    970 
    971         function fallbackCopyTextToClipboard(text) {
    972             const textArea = document.createElement("textarea");
    973             textArea.value = text;
    974             textArea.style.position = "fixed";
    975             textArea.style.top = "0";
    976             textArea.style.left = "0";
    977             textArea.style.opacity = "0"; 
    978             document.body.appendChild(textArea);
    979             textArea.focus();
    980             textArea.select();
    981             try {
    982                 document.execCommand('copy');
    983                 showToast("Copied to Clipboard!");
    984             } catch (err) {
    985                 showToast("Copy Failed");
    986             }
    987             document.body.removeChild(textArea);
    988         }
    989 
    990         // Terminal Input
    991         term.onData((data) => {
    992             if (!socket || socket.readyState !== WebSocket.OPEN) return;
    993 
    994             if (data === '\r') { 
    995                 term.write('\r\n'); 
    996                 socket.send(JSON.stringify({ type: 'input', data: currentLine + '\n' }));
    997                 currentLine = "";
    998             } else if (data === '\x7f' || data === '\b') { 
    999                 if (currentLine.length > 0) {
   1000                     currentLine = currentLine.slice(0, -1);
   1001                     term.write('\b \b'); 
   1002                 }
   1003             } else { 
   1004                 currentLine += data;
   1005                 term.write(data); 
   1006             }
   1007         });
   1008     </script>
   1009 </body>
   1010 </html>
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror