Spaces:
Sleeping
Sleeping
Upload app.py
Browse files
app.py
CHANGED
@@ -1,84 +1,91 @@
|
|
1 |
-
import
|
2 |
-
import
|
|
|
|
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
with open("temp_program.bas", "w") as f:
|
7 |
-
f.write(code)
|
8 |
-
|
9 |
-
# Executa o PCBasic com opções para:
|
10 |
-
# --exec: executar o código,
|
11 |
-
# --ink=green: definir a tinta (texto) como verde,
|
12 |
-
# --paper=black: definir o fundo como preto,
|
13 |
-
# --border=green: definir a borda como verde.
|
14 |
-
output = pcbasic.run(
|
15 |
-
"temp_program.bas",
|
16 |
-
options=["--exec", "--ink=green", "--paper=black", "--border=green"]
|
17 |
-
)
|
18 |
-
return output
|
19 |
|
20 |
-
#
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap');
|
27 |
-
.terminal {
|
28 |
-
background-color: black !important;
|
29 |
-
color: #00FF00 !important;
|
30 |
-
font-family: 'IBM Plex Mono', monospace !important;
|
31 |
-
padding: 10px !important;
|
32 |
-
border: 3px solid #00FF00 !important;
|
33 |
-
border-radius: 5px !important;
|
34 |
-
margin: 0 !important;
|
35 |
-
}
|
36 |
-
/* Customizar a textarea do Streamlit */
|
37 |
-
.stTextArea textarea {
|
38 |
-
background-color: black !important;
|
39 |
-
color: #00FF00 !important;
|
40 |
-
font-family: 'IBM Plex Mono', monospace !important;
|
41 |
-
border: 3px solid #00FF00 !important;
|
42 |
-
border-radius: 5px !important;
|
43 |
-
padding: 10px !important;
|
44 |
-
}
|
45 |
-
/* Remover espaçamentos extras dos contêineres do Streamlit */
|
46 |
-
.stTextArea, .css-18e3th9, .css-1d391kg {
|
47 |
-
margin: 0 !important;
|
48 |
-
padding: 0 !important;
|
49 |
-
}
|
50 |
-
</style>
|
51 |
-
""", unsafe_allow_html=True)
|
52 |
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
</div>
|
62 |
-
""", unsafe_allow_html=True)
|
63 |
-
|
64 |
-
# Área de edição de código com aparência unificada
|
65 |
-
code = st.text_area("Digite o código BASIC", height=200, key="code_input")
|
66 |
-
|
67 |
-
# Botão para executar o código e exibir a saída logo abaixo, sem separação
|
68 |
-
if st.button("Executar Código (RUN)"):
|
69 |
-
if code:
|
70 |
-
result = run_basic_code(code)
|
71 |
-
st.markdown(f"""
|
72 |
-
<div class="terminal">
|
73 |
-
{result}
|
74 |
-
</div>
|
75 |
-
""", unsafe_allow_html=True)
|
76 |
else:
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
""", unsafe_allow_html=True)
|
|
|
1 |
+
import os
|
2 |
+
import pty
|
3 |
+
import subprocess
|
4 |
+
import threading
|
5 |
+
from flask import Flask, render_template_string
|
6 |
+
from flask_sockets import Sockets
|
7 |
|
8 |
+
app = Flask(__name__)
|
9 |
+
sockets = Sockets(app)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
+
# HTML que carrega o xterm.js e conecta via WebSocket
|
12 |
+
HTML = """
|
13 |
+
<!doctype html>
|
14 |
+
<html>
|
15 |
+
<head>
|
16 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css" />
|
17 |
+
<script src="https://cdn.jsdelivr.net/npm/xterm/lib/xterm.js"></script>
|
18 |
+
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit/lib/xterm-addon-fit.js"></script>
|
19 |
+
</head>
|
20 |
+
<body style="margin:0; padding:0; background:black;">
|
21 |
+
<div id="terminal" style="width:100vw; height:100vh;"></div>
|
22 |
+
<script>
|
23 |
+
const term = new Terminal({
|
24 |
+
cols: 80,
|
25 |
+
rows: 24,
|
26 |
+
theme: {
|
27 |
+
background: '#000000',
|
28 |
+
foreground: '#00FF00'
|
29 |
+
}
|
30 |
+
});
|
31 |
+
const fitAddon = new FitAddon.FitAddon();
|
32 |
+
term.loadAddon(fitAddon);
|
33 |
+
term.open(document.getElementById('terminal'));
|
34 |
+
fitAddon.fit();
|
35 |
+
|
36 |
+
const protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
|
37 |
+
const socketUrl = protocol + location.host + "/ws";
|
38 |
+
const socket = new WebSocket(socketUrl);
|
39 |
+
|
40 |
+
socket.onmessage = function(event) {
|
41 |
+
term.write(event.data);
|
42 |
+
};
|
43 |
+
|
44 |
+
term.onData(function(data) {
|
45 |
+
socket.send(data);
|
46 |
+
});
|
47 |
+
</script>
|
48 |
+
</body>
|
49 |
+
</html>
|
50 |
+
"""
|
51 |
|
52 |
+
@app.route("/")
|
53 |
+
def index():
|
54 |
+
return render_template_string(HTML)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
+
@sockets.route("/ws")
|
57 |
+
def echo_socket(ws):
|
58 |
+
# Inicia o PCBasic em um pseudo-terminal
|
59 |
+
pid, fd = pty.fork()
|
60 |
+
if pid == 0:
|
61 |
+
# No processo filho, executa o PCBasic com as opções desejadas
|
62 |
+
# (por exemplo, --run para executar um arquivo, ou apenas iniciar o interpretador interativo)
|
63 |
+
os.execvp("pcbasic", ["pcbasic", "--run"]) # ajuste conforme necessário
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
else:
|
65 |
+
# Em thread, lê do pseudo-terminal e envia via WebSocket
|
66 |
+
def read_and_forward():
|
67 |
+
while True:
|
68 |
+
try:
|
69 |
+
data = os.read(fd, 1024)
|
70 |
+
if not data:
|
71 |
+
break
|
72 |
+
ws.send(data.decode(errors="ignore"))
|
73 |
+
except Exception:
|
74 |
+
break
|
75 |
+
thread = threading.Thread(target=read_and_forward)
|
76 |
+
thread.daemon = True
|
77 |
+
thread.start()
|
78 |
+
|
79 |
+
# Recebe os dados enviados pelo cliente e encaminha para o processo
|
80 |
+
while not ws.closed:
|
81 |
+
message = ws.receive()
|
82 |
+
if message is None:
|
83 |
+
break
|
84 |
+
os.write(fd, message.encode())
|
85 |
+
return
|
86 |
|
87 |
+
if __name__ == "__main__":
|
88 |
+
from gevent import pywsgi
|
89 |
+
from geventwebsocket.handler import WebSocketHandler
|
90 |
+
server = pywsgi.WSGIServer(("", 5000), app, handler_class=WebSocketHandler)
|
91 |
+
server.serve_forever()
|
|