Spaces:
Paused
Paused
Update file-manager/app.py
Browse files- file-manager/app.py +21 -32
file-manager/app.py
CHANGED
|
@@ -112,46 +112,35 @@ button{{background:#F46821;color:#fff;border:0;padding:8px 14px;border-radius:4p
|
|
| 112 |
@app.route("/term")
|
| 113 |
def term_page():
|
| 114 |
body = """
|
| 115 |
-
<div class="bar"><b>Live
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
<
|
| 119 |
-
<
|
| 120 |
-
placeholder="type a command or input, then Enter">
|
| 121 |
-
<button onclick="send()">Send</button>
|
| 122 |
-
<button onclick="ctrlc()">Ctrl-C</button>
|
| 123 |
-
<button onclick="reset()">Restart</button>
|
| 124 |
<script>
|
| 125 |
-
const
|
| 126 |
-
const
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
await fetch('/fm/term_in', {method:'POST',
|
| 133 |
headers:{'Content-Type':'application/json'},
|
| 134 |
-
body: JSON.stringify({data:
|
| 135 |
-
}
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
headers:{'Content-Type':'application/json'},
|
| 139 |
-
body: JSON.stringify({data: "\\u0003"})}); // Ctrl-C
|
| 140 |
-
}
|
| 141 |
-
async function reset(){
|
| 142 |
-
await fetch('/fm/term_reset', {method:'POST'});
|
| 143 |
-
out.textContent = '';
|
| 144 |
-
}
|
| 145 |
-
// Poll for new output every 300ms — reliable through the proxy
|
| 146 |
async function poll(){
|
| 147 |
try{
|
| 148 |
const r = await fetch('/fm/term_out');
|
| 149 |
-
const
|
| 150 |
-
if(
|
| 151 |
}catch(e){}
|
| 152 |
-
setTimeout(poll,
|
| 153 |
}
|
| 154 |
-
line.addEventListener('keydown', e => { if(e.key==='Enter'){ e.preventDefault(); send(); }});
|
| 155 |
poll();
|
| 156 |
</script>"""
|
| 157 |
return Response(PAGE.format(body=body))
|
|
|
|
| 112 |
@app.route("/term")
|
| 113 |
def term_page():
|
| 114 |
body = """
|
| 115 |
+
<div class="bar"><b>Live terminal (xterm.js)</b> — full color, progress bars, prompts.</div>
|
| 116 |
+
<div id="term" style="height:65vh;background:#000;border-radius:6px"></div>
|
| 117 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css"/>
|
| 118 |
+
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js"></script>
|
| 119 |
+
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
<script>
|
| 121 |
+
const term = new Terminal({convertEol:false, cursorBlink:true, fontFamily:'monospace', fontSize:13});
|
| 122 |
+
const fit = new FitAddon.FitAddon();
|
| 123 |
+
term.loadAddon(fit);
|
| 124 |
+
term.open(document.getElementById('term'));
|
| 125 |
+
fit.fit();
|
| 126 |
+
window.addEventListener('resize', () => fit.fit());
|
| 127 |
|
| 128 |
+
// Send every keystroke straight to the PTY (real interactive terminal)
|
| 129 |
+
term.onData(d => {
|
| 130 |
+
fetch('/fm/term_in', {method:'POST',
|
|
|
|
| 131 |
headers:{'Content-Type':'application/json'},
|
| 132 |
+
body: JSON.stringify({data: d})});
|
| 133 |
+
});
|
| 134 |
+
|
| 135 |
+
// Poll for new PTY output and write it raw — xterm.js renders the ANSI codes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
async function poll(){
|
| 137 |
try{
|
| 138 |
const r = await fetch('/fm/term_out');
|
| 139 |
+
const j = await r.json();
|
| 140 |
+
if(j.data) term.write(j.data);
|
| 141 |
}catch(e){}
|
| 142 |
+
setTimeout(poll, 200);
|
| 143 |
}
|
|
|
|
| 144 |
poll();
|
| 145 |
</script>"""
|
| 146 |
return Response(PAGE.format(body=body))
|