🌐
index_copy.html
Back
📝 Html ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>Paste Editor • Navigator + Bring In</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.32.9/ace.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <style> :root{--bg:#0f172a;--panel:#111827;--text:#e5e7eb;--muted:#94a3b8;--border:#243244;--accent:#60a5fa} *{box-sizing:border-box} html,body{height:100%} html{scroll-behavior:auto} body{margin:0;background:var(--bg);color:var(--text);font:14px/1.5 ui-sans-serif,system-ui,Segoe UI,Inter,Roboto,sans-serif;display:flex;flex-direction:column;overscroll-behavior-y:none} body.no-scroll{overflow:hidden} .bar{display:flex;gap:.75rem;align-items:center;padding:.6rem 1rem;background:var(--panel);border-bottom:1px solid var(--border)} .bar select{background:#0b1220;color:var(--text);border:1px solid var(--border);border-radius:6px;padding:.35rem .5rem} .bar .btn{margin-left:.5rem} .hint{margin-left:auto;color:var(--muted);font-size:.9rem} .toolbar{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;padding:.5rem 1rem;background:#0b1220;border-bottom:1px solid var(--border)} .find-mode,.find-input,.btn{border:1px solid var(--border);background:#0b1220;color:var(--text);border-radius:6px} .find-mode{padding:.4rem .5rem} .find-input{padding:.4rem .6rem;min-width:250px} .btn{padding:.45rem .7rem;cursor:pointer} .btn[disabled]{opacity:.5;cursor:not-allowed} .btn-accent{border-color:var(--accent); background:rgba(96,165,250,.12)} .count{color:var(--muted);margin-left:.25rem;font-size:.9rem} .badge{margin-left:.75rem;color:#cbd5e1;font-size:.85rem} .pane{flex:1;min-height:0} #editor{width:100%;height:100%} .ace_selected_block{position:absolute;background:rgba(80,160,255,.18);border:1px solid rgba(80,160,255,.35)} /* Overlay */ .overlay{position:fixed;inset:0;display:none;align-items:center;justify-content:center;z-index:9999;background:rgba(0,0,0,.55);backdrop-filter:saturate(120%) blur(2px)} .overlay.open{display:flex} .sheet{background:#0b1220;border:1px solid var(--border);border-radius:12px;box-shadow:0 10px 40px rgba(0,0,0,.35);width:min(960px,94vw);max-height:88vh;display:flex;flex-direction:column} .sheet-head{display:flex;align-items:center;justify-content:space-between;padding:.8rem 1rem;border-bottom:1px solid var(--border)} .sheet-title{font-weight:600} .sheet-close{background:transparent;border:1px solid var(--border);border-radius:8px;color:var(--text);width:34px;height:34px;cursor:pointer} .sheet-body{padding:1rem;overflow:auto} .sheet-body textarea{width:100%;height:50vh;min-height:200px;background:#0a101b;color:var(--text);border:1px solid var(--border);border-radius:10px;padding:.75rem;resize:vertical} .sheet-foot{display:flex;gap:.5rem;flex-wrap:wrap;justify-content:flex-end;padding:1rem;border-top:1px solid var(--border)} .sheet-foot .btn{min-width:120px} .btn-ghost{background:transparent} .btn-primary{background:#0f172a;border-color:var(--accent)} .btn-primary:hover{background:#132036} </style> </head> <body> <div class="bar"> <strong>Paste Editor</strong> <label>Mode: <select id="modeSel" title="Syntax mode"> <option value="javascript">JavaScript</option> <option value="typescript">TypeScript</option> <option value="php">PHP</option> <option value="python">Python</option> <option value="html">HTML</option> <option value="css">CSS</option> <option value="json">JSON</option> <option value="sql">SQL</option> <option value="markdown">Markdown</option> <option value="sh">Shell</option> <option value="text">Plain Text</option> </select> </label> <button id="bringBtn" class="btn btn-accent" type="button" title="Analyze snippet and locate">Bring In</button> <span id="detectedBadge" class="badge"></span> <div class="hint">Paste (Ctrl/Cmd-V) • Ctrl/Cmd-F finds • Esc clears search</div> </div> <div class="toolbar"> <select id="findMode" class="find-mode" title="Search mode"> <option value="normal">Normal text</option> <option value="function">Function</option> <option value="tag">Tag (HTML)</option> <option value="variable">Variable</option> <option value="attribute">Attribute / ID</option> </select> <input id="findInput" class="find-input" placeholder="Query (blank = browse all in current mode)" /> <button class="btn" id="prevBtn" type="button" title="Previous (Shift+Enter)">▲</button> <button class="btn" id="nextBtn" type="button" title="Next (Enter)">▼</button> <button class="btn" id="clearBtn" type="button" title="Clear search">Clear</button> <span class="count" id="countHint"></span> </div> <div class="pane"><div id="editor"> // Paste code or HTML here. // Modes: // • Function: blank = all functions; type to filter. // • Tag: blank = browse <div>; type tag name (e.g., span). // • Variable: blank = all declarations; type to filter. // • Attribute: blank = elements with id; filters: #id, .class, [attr], [attr=value], [attr*=substr]. </div></div> <!-- Overlay --> <div id="overlay" class="overlay" aria-hidden="true"> <div class="sheet" role="dialog" aria-modal="true" aria-labelledby="sheetTitle"> <div class="sheet-head"> <div id="sheetTitle" class="sheet-title">Bring In</div> <button id="sheetClose" class="sheet-close" type="button" aria-label="Close">×</button> </div> <div class="sheet-body"> <textarea id="bringText" placeholder="Paste a snippet to analyze (editor content will NOT change unless you press Paste/Replace)…&#10;Examples:&#10;• function saveUser() { … }&#10;• let userName = '…'&#10;• &lt;div id=&quot;hero&quot; class=&quot;card&quot;&gt;…&#10;• #hero or .card or [data-role=nav]"></textarea> </div> <div class="sheet-foot"> <button id="locateBtn" class="btn btn-primary" type="button" title="Analyze and jump (Ctrl/Cmd+Enter)">Locate</button> <button id="pasteBtn" class="btn btn-primary" type="button" title="Insert at cursor">Paste at Cursor</button> <button id="replaceBtn" class="btn btn-primary" type="button" title="Replace selection or current highlighted block">Replace Block/Selection</button> <button id="cancelBtn" class="btn btn-ghost" type="button">Close</button> </div> </div> </div> <script> /* ================== ACE setup ================== */ const editor = ace.edit("editor"); editor.setTheme("ace/theme/monokai"); editor.session.setMode("ace/mode/javascript"); // default editor.setOptions({ wrap:true, tabSize:2, useSoftTabs:true, showPrintMargin:false, enableBasicAutocompletion:true, enableLiveAutocompletion:true, highlightActiveLine:true, highlightGutterLine:true, fontSize:14 }); const modeSel = document.getElementById("modeSel"); modeSel.addEventListener("change", e => editor.session.setMode("ace/mode/" + e.target.value)); /* ================== Bring In overlay ================== */ const overlay = document.getElementById('overlay'); const bringBtn = document.getElementById('bringBtn'); const closeBtn = document.getElementById('sheetClose'); const cancelBtn = document.getElementById('cancelBtn'); const locateBtn = document.getElementById('locateBtn'); const pasteBtn = document.getElementById('pasteBtn'); const replaceBtn = document.getElementById('replaceBtn'); const bringText = document.getElementById('bringText'); const detectedBadge = document.getElementById('detectedBadge'); function lockScroll(lock){ document.body.classList.toggle('no-scroll', !!lock); } function openOverlay(){ overlay.classList.add('open'); overlay.setAttribute('aria-hidden','false'); lockScroll(true); // avoid page jumping: focus after frame requestAnimationFrame(()=>bringText.focus()); } function closeOverlay(){ overlay.classList.remove('open'); overlay.setAttribute('aria-hidden','true'); lockScroll(false); editor.focus(); } bringBtn.addEventListener('click', openOverlay); closeBtn.addEventListener('click', closeOverlay); cancelBtn.addEventListener('click', closeOverlay); overlay.addEventListener('click', (e) => { if (e.target === overlay) closeOverlay(); }); overlay.addEventListener('keydown', (e) => { if (e.key === 'Escape') { e.preventDefault(); closeOverlay(); } if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'enter') { e.preventDefault(); locateBtn.click(); } }); /* ================== Navigator state ================== */ const findInput = document.getElementById('findInput'); const findMode = document.getElementById('findMode'); const prevBtn = document.getElementById('prevBtn'); const nextBtn = document.getElementById('nextBtn'); const clearBtn = document.getElementById('clearBtn'); const countHint = document.getElementById('countHint'); let term = ''; let matches = []; let idx = -1; let cache = { function:null, tag:null, variable:null, attribute:null }; let lastBlockRange = null; // store highlighted block to support replace editor._blockMarkers = []; function clearHighlights(){ if (editor._blockMarkers.length) { editor._blockMarkers.forEach(id => editor.session.removeMarker(id)); editor._blockMarkers = []; } lastBlockRange = null; } function selectBlock(m){ if (!m) return; clearHighlights(); const Range = ace.require('ace/range').Range; const range = new Range(m.startLine, m.startColumn || 0, m.endLine || m.startLine, m.endColumn || (editor.session.getLine(m.endLine || m.startLine) || '').length); const id = editor.session.addMarker(range, 'ace_selected_block', 'text'); editor._blockMarkers.push(id); editor.selection.setRange(range, false); editor.scrollToLine(m.startLine, true, true, ()=>{}); lastBlockRange = range.clone(); } /* ================== Scanners ================== */ function scanFunctions(filter) { const lines = editor.getValue().split('\n'); const out = [], f = (filter||'').toLowerCase(), has = !!f; const pats = [ /^\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/, /^\s*(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>\s*{/, /^\s*(?:public|private|protected|static|\s)*function\s+(\w+)\s*\(/, /^\s*def\s+(\w+)\s*\(/, /^\s*(\w[\w\d_]*)\s*\([^)]*\)\s*\{/ ]; for (let i=0;i<lines.length;i++){ const line=lines[i]; let name=null, isPy=false, braces=false; for (const re of pats){ const m=line.match(re); if(m){ name=m[1]||''; isPy=/^\s*def\s+/.test(line); braces=/{/.test(line)||!isPy; break; } } if (name===null) continue; if (has && !name.toLowerCase().includes(f)) continue; let end=i; if (braces){ let b=0, opened=false; for (let j=i;j<lines.length;j++){ for (const ch of lines[j]){ if(ch==='{' ){b++;opened=true;} if(ch==='}'){b--;} } if (opened && b===0){ end=j; break; } if (j===lines.length-1) end=j; } } else { const base=(line.match(/^\s*/)||[''])[0].length; for (let j=i+1;j<lines.length;j++){ const L=lines[j], ind=(L.match(/^\s*/)||[''])[0].length; if (L.trim() && ind<=base){ end=j-1; break; } if (j===lines.length-1) end=j; } } out.push({kind:'function', name, startLine:i, endLine:end, startColumn:0, endColumn:(lines[end]||'').length}); } return out; } function scanTags(filter) { const lines = editor.getValue().split('\n'); const out = []; const tagFilterRaw = (filter||'').trim().toLowerCase(); const want = tagFilterRaw || 'div'; const voids = new Set(['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr']); const openRe = /<([a-zA-Z][\w:-]*)\b([^>]*?)>/g; for (let i=0;i<lines.length;i++){ const line=lines[i]; openRe.lastIndex=0; let m; while ((m=openRe.exec(line))!==null){ const tag=m[1].toLowerCase(); if (tagFilterRaw ? (tag!==want) : (tag!=='div')) continue; const selfClosing=/\/>\s*$/.test(m[0]) || voids.has(tag); if (selfClosing){ out.push({kind:'tag', name:tag, startLine:i, endLine:i, startColumn:m.index, endColumn:m.index+m[0].length}); continue; } let depth=1, end=i; for (let j=i;j<lines.length;j++){ const L=lines[j]; if (j===i){ const rest=L.slice(m.index+m[0].length); depth+=(rest.match(new RegExp(`<${tag}\\b`,'gi'))||[]).length; depth-=(rest.match(new RegExp(`</${tag}\\s*>`,'gi'))||[]).length; } else { depth+=(L.match(new RegExp(`<${tag}\\b`,'gi'))||[]).length; depth-=(L.match(new RegExp(`</${tag}\\s*>`,'gi'))||[]).length; } if (depth===0){ end=j; break; } if (j===lines.length-1) end=j; } out.push({kind:'tag', name:tag, startLine:i, endLine:end, startColumn:0, endColumn:(lines[end]||'').length}); } } return out; } function scanVariables(filter) { const lines = editor.getValue().split('\n'); const out = [], f=(filter||'').toLowerCase(), has=!!f; for (let i=0;i<lines.length;i++){ const line=lines[i]; if (/^\s*(def|class)\b/.test(line)) continue; let m=line.match(/^\s*(?:var|let|const)\s+([^;]+)/); if (m){ const names=m[1].split(',').map(s=>s.trim().replace(/^(\{|\[)/,'').replace(/=.*$/,'').trim()); for (const raw of names){ const name=(raw.match(/[$A-Za-z_][\w$]*/)||[])[0]; if(!name) continue; if (has && !name.toLowerCase().includes(f)) continue; out.push({kind:'variable', name, startLine:i, endLine:i, startColumn:0, endColumn:line.length}); } continue; } m=line.match(/^\s*\$([A-Za-z_]\w*)\s*=/); if (m){ const name=m[1]; if(!has||name.toLowerCase().includes(f)) out.push({kind:'variable', name, startLine:i, endLine:i, startColumn:0, endColumn:line.length}); continue; } m=line.match(/^\s*([A-Za-z_]\w*)\s*=\s*[^=]/); if (m){ const name=m[1]; if(!has||name.toLowerCase().includes(f)) out.push({kind:'variable', name, startLine:i, endLine:i, startColumn:0, endColumn:line.length}); continue; } m=line.match(/^\s*(?:unsigned\s+|signed\s+)?[A-Za-z_]\w*(?:\s*\*+)?\s+([A-Za-z_]\w*)\s*(?:[=;,\)])/); if (m){ const name=m[1]; if(!has||name.toLowerCase().includes(f)) out.push({kind:'variable', name, startLine:i, endLine:i, startColumn:0, endColumn:line.length}); continue; } } return out; } function parseAttrs(attrStr){ const attrs={}; const re=/([:@A-Za-z_][\w:.-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g; let m; while ((m=re.exec(attrStr))!==null){ const key=m[1].toLowerCase(); const val=m[2]??m[3]??m[4]??''; attrs[key]=val; if (key==='class' && val) attrs.classList=val.split(/\s+/).filter(Boolean); } return attrs; } function matchesAttrFilter(attrs, filterRaw){ if (!filterRaw) return !!attrs.id; const s=filterRaw.trim(); if (s.startsWith('#')) return (attrs.id||'').toLowerCase()===s.slice(1).toLowerCase(); if (s.startsWith('.')) return (attrs.classList||[]).map(c=>c.toLowerCase()).includes(s.slice(1).toLowerCase()); if (s.startsWith('[') && s.endsWith(']')){ const inner=s.slice(1,-1).trim(); const starEq=inner.split('*='); if (starEq.length===2){ const key=starEq[0].trim().toLowerCase(); const val=starEq[1].replace(/^['"]|['"]$/g,'').toLowerCase(); return (attrs[key]||'').toLowerCase().includes(val); } const eq=inner.split('='); if (eq.length===2){ const key=eq[0].trim().toLowerCase(); const val=eq[1].replace(/^['"]|['"]$/g,'').toLowerCase(); return (attrs[key]||'').toLowerCase()===val; } return inner in attrs; } const key=s.toLowerCase(); if (key in attrs) return true; return Object.keys(attrs).some(k=>String(attrs[k]).toLowerCase().includes(key)); } function scanAttributes(filter){ const lines = editor.getValue().split('\n'); const out=[]; const voids=new Set(['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr']); const openRe=/<([a-zA-Z][\w:-]*)\b([^>]*?)>/g; for (let i=0;i<lines.length;i++){ const line=lines[i]; openRe.lastIndex=0; let m; while ((m=openRe.exec(line))!==null){ const tag=m[1].toLowerCase(); const attrs=parseAttrs(m[2]||''); if (!matchesAttrFilter(attrs, filter)) continue; const selfClosing=/\/>\s*$/.test(m[0]) || voids.has(tag); if (selfClosing){ out.push({kind:'attribute', name:(attrs.id||attrs.class||tag||''), startLine:i, endLine:i, startColumn:m.index, endColumn:m.index+m[0].length}); continue; } let depth=1, end=i; for (let j=i;j<lines.length;j++){ const L=lines[j]; if (j===i){ const rest=L.slice(m.index+m[0].length); depth+=(rest.match(new RegExp(`<${tag}\\b`,'gi'))||[]).length; depth-=(rest.match(new RegExp(`</${tag}\\s*>`,'gi'))||[]).length; } else { depth+=(L.match(new RegExp(`<${tag}\\b`,'gi'))||[]).length; depth-=(L.match(new RegExp(`</${tag}\\s*>`,'gi'))||[]).length; } if (depth===0){ end=j; break; } if (j===lines.length-1) end=j; } out.push({kind:'attribute', name:(attrs.id||attrs.class||tag||''), startLine:i, endLine:end, startColumn:0, endColumn:(lines[end]||'').length}); } } return out; } /* ================== Search driver ================== */ function rebuildCache(kind){ if (kind==='function') cache.function = scanFunctions(''); else if (kind==='tag') cache.tag = scanTags(''); else if (kind==='variable') cache.variable = scanVariables(''); else if (kind==='attribute') cache.attribute = scanAttributes(''); } function updateButtons(){ const mode=findMode.value, hasTerm=!!term, usingAll=(mode!=='normal' && !hasTerm); const list = hasTerm ? matches : (cache[mode] || []); const at = (idx>=0 && list.length) ? (idx+1) : ''; prevBtn.disabled = (mode==='normal') ? !hasTerm : (list.length===0); nextBtn.disabled = prevBtn.disabled; clearBtn.disabled = !(hasTerm || (usingAll && list.length)); let label = mode==='normal'?'text': (mode==='function'?'function': mode==='tag'?'tag': mode==='variable'?'variable':'element'); countHint.textContent = (mode==='normal') ? (hasTerm ? 'Text search (use editor next/prev)' : '') : (list.length ? `${list.length} ${label}${list.length!==1?'s':''}${at?` • at ${at}`:''}` : `No ${label}s found`); } function doSearch(){ term = findInput.value.trim(); const mode=findMode.value; if (mode==='normal'){ clearHighlights(); if (term) editor.find(term, {backwards:false, wrap:true, caseSensitive:false, wholeWord:false, regExp:false}); else { editor.find(''); editor.selection.clearSelection(); } matches=[]; idx=-1; updateButtons(); return; } if (!term){ if (!cache[mode]) rebuildCache(mode); const list = cache[mode] || []; if (list.length && idx<0) idx = 0; selectBlock(list[idx]); matches=[]; updateButtons(); return; } if (mode==='function') matches = scanFunctions(term); else if (mode==='tag') matches = scanTags(term); else if (mode==='variable') matches = scanVariables(term); else if (mode==='attribute') matches = scanAttributes(term); if (matches.length){ idx=0; selectBlock(matches[0]); } else { clearHighlights(); idx=-1; } updateButtons(); } function step(delta){ const mode=findMode.value; if (mode==='normal'){ if (term) (delta>0?editor.findNext():editor.findPrevious()); return; } const list = term ? matches : (cache[mode] || []); if (!list.length) return; idx = ((idx<0?0:idx) + delta + list.length) % list.length; selectBlock(list[idx]); updateButtons(); } let debounce; findInput.addEventListener('input', () => { clearTimeout(debounce); debounce=setTimeout(()=>{ idx=-1; doSearch(); }, 180); }); findMode.addEventListener('change', () => { idx=-1; doSearch(); }); nextBtn.addEventListener('click', () => step(+1)); prevBtn.addEventListener('click', () => step(-1)); clearBtn.addEventListener('click', () => { findInput.value=''; term=''; matches=[]; idx=-1; doSearch(); editor.focus(); }); function scheduleCacheReset(){ cache={function:null, tag:null, variable:null, attribute:null}; if (findMode.value!=='normal' && !term){ idx=-1; updateButtons(); } } let rebuildTimer; editor.session.on('change', () => { clearTimeout(rebuildTimer); rebuildTimer = setTimeout(scheduleCacheReset, 250); }); editor.commands.addCommand({ name:'focusFind', bindKey:{win:'Ctrl-F',mac:'Command-F'}, exec:()=>{ findInput.focus(); findInput.select(); } }); // initial doSearch(); // Prevent pull-to-refresh on touch (function(){ let prevent=false, startY=0; window.addEventListener('touchstart', e=>{ startY=e.touches[0].clientY; prevent=(window.scrollY===0); }, {passive:true}); window.addEventListener('touchmove', e=>{ if(prevent){ const dy=e.touches[0].clientY-startY; if(dy>10) e.preventDefault(); } }, {passive:false}); })(); /* ================== Detection (Bring In) ================== */ function detectLanguage(text){ const t = text.trim(); if (/^<!DOCTYPE html>|^<html[\s>]|^<\w+[\s>]/i.test(t)) return 'html'; if (/^<\?php/i.test(t)) return 'php'; if (/^\s*#!/.test(t) && /python/.test(t)) return 'python'; if (/^\s*(def\s+\w+\s*\(|class\s+\w+)/.test(t)) return 'python'; if (/^\s*(import\s+\w+|from\s+\w+\s+import)/.test(t)) return 'python'; if (/^\s*(public|private|protected|class)\b/.test(t)) return 'java'; if (/^\s*(#include\b|int\s+main\s*\()/.test(t)) return 'c_cpp'; if (/^\s*(let|const|var)\s+/.test(t) || /\bfunction\s+\w+\s*\(/.test(t) || /=>\s*\{/.test(t)) return 'javascript'; if (/^\s*\{[\s\S]*\}\s*$/.test(t) && /:/.test(t)) return 'json'; return null; } function detectEntity(text){ const firstLine = text.split('\n').find(l => l.trim().length) || ''; const trimmed = firstLine.trim(); if (/^<\w+[\s>]/.test(trimmed)) { const m = trimmed.match(/^<([a-zA-Z][\w:-]*)\b([^>]*?)>?/); if (m) { const tag = (m[1]||'').toLowerCase(); const attrStr = m[2] || ''; const id = (attrStr.match(/\bid=["']?([^"'\s>]+)["']?/i) || [])[1]; const cls = (attrStr.match(/\bclass=["']([^"']+)["']/i) || [])[1]; if (id) return {mode:'attribute', query:'#'+id, label:`id: ${id}`}; if (cls) { const firstClass = cls.split(/\s+/).filter(Boolean)[0]; if (firstClass) return {mode:'attribute', query:'.'+firstClass, label:`class: ${firstClass}`}; } if (tag) return {mode:'tag', query:tag, label:`tag: ${tag}`}; } } const fn = trimmed.match(/^\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/) || trimmed.match(/^\s*(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>\s*\{/) || trimmed.match(/^\s*(?:public|private|protected|static|\s)*function\s+(\w+)\s*\(/) || trimmed.match(/^\s*def\s+(\w+)\s*\(/) || trimmed.match(/^\s*(\w[\w\d_]*)\s*\([^)]*\)\s*\{/); if (fn) return {mode:'function', query:fn[1], label:`function: ${fn[1]}`}; const v = trimmed.match(/^\s*(?:var|let|const)\s+([$A-Za-z_][\w$]*)/) || trimmed.match(/^\s*\$([A-Za-z_]\w*)\s*=/) || trimmed.match(/^\s*([A-Za-z_]\w*)\s*=\s*[^=]/) || trimmed.match(/^\s*(?:unsigned\s+|signed\s+)?[A-Za-z_]\w*(?:\s*\*+)?\s+([A-Za-z_]\w*)\s*(?:[=;,\)])/); if (v) return {mode:'variable', query:v[1], label:`variable: ${v[1]}`}; if (/^#[-\w:]+$/.test(trimmed) || /^\.[-\w:]+$/.test(trimmed) || /^\[[^\]]+\]$/.test(trimmed)) { return {mode:'attribute', query:trimmed, label:`selector: ${trimmed}`}; } return null; } function applyDetectionAndSearch(fromText, shouldClose=true){ const lang = detectLanguage(fromText); if (lang) { const aceMode = (lang==='c_cpp' ? 'c_cpp' : lang); modeSel.value = aceMode; editor.session.setMode('ace/mode/' + aceMode); } const ent = detectEntity(fromText); if (ent) { findMode.value = ent.mode; findInput.value = ent.query || ''; term = ent.query || ''; idx = -1; doSearch(); detectedBadge.textContent = `Detected ${ent.label}`; } else { detectedBadge.textContent = 'No specific entity detected'; } if (shouldClose) closeOverlay(); } locateBtn.addEventListener('click', () => { applyDetectionAndSearch(bringText.value, true); }); pasteBtn.addEventListener('click', () => { const txt = bringText.value; if (!txt) { closeOverlay(); return; } const pos = editor.getCursorPosition(); editor.session.insert(pos, txt); scheduleCacheReset(); closeOverlay(); }); replaceBtn.addEventListener('click', () => { const txt = bringText.value; if (!txt) { closeOverlay(); return; } const sel = editor.getSelectionRange(); if (!editor.session.getTextRange(sel)) { // no selection: try replacing the currently highlighted block if (lastBlockRange) { editor.session.replace(lastBlockRange, txt); } else { // fallback: replace current line const row = editor.getCursorPosition().row; const line = editor.session.getLine(row); const Range = ace.require('ace/range').Range; editor.session.replace(new Range(row, 0, row, line.length), txt); } } else { editor.session.replace(sel, txt); } scheduleCacheReset(); closeOverlay(); }); </script> </body> </html>