-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontroller.py
More file actions
206 lines (179 loc) · 6.93 KB
/
controller.py
File metadata and controls
206 lines (179 loc) · 6.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import time
import sys
import curses
import engine
import config
from ui.editor import run_editor_session
from ui.utils import OSUtils, suspend_curses
def handle_action(stdscr, action):
"""Executes non-render actions (Messages, Custom Views, Exit)."""
if not action:
return
if isinstance(action, engine.ActionShowMessage):
with suspend_curses(stdscr):
if action.clear_screen:
OSUtils.clear_screen()
# Print Title
if action.type == 'error':
print(f"\n{action.title}")
elif action.title:
print(f"\n{action.title}")
if action.type != 'reset' and action.title: # Reset has its own format in content usually or we standardise
# Original code had different formats.
# Success: Check mark title.
# Error: X mark title.
pass
# Print Content
if action.content:
if action.type in ['solution', 'error', 'info']:
print("-" * 30)
print(action.content)
print("-" * 30)
else:
# Success / Reset
print(action.content)
# Interactions
if action.wait_for_enter:
if action.type == 'error':
input(f"\n{config.UI.PROMPT_RETRY}")
else:
input(f"\n{config.UI.PROMPT_CONTINUE}")
else:
time.sleep(config.Timing.ACTION_WAIT_SUCCESS if action.type == 'success' else config.Timing.ACTION_WAIT_DEFAULT)
elif isinstance(action, engine.ActionCustomView):
if action.view_name == "dev_message":
with suspend_curses(stdscr):
try:
from ui.dev_message import show_developer_message
show_developer_message(stdscr)
except Exception:
pass
elif isinstance(action, engine.ActionExit):
raise KeyboardInterrupt
def validate_terminal_size():
"""Terminal boyutunun en az 20x10 olduğunu kontrol eder."""
try:
import shutil
cols, lines = shutil.get_terminal_size(fallback=(80, 24))
if cols < config.Layout.MIN_WIDTH or lines < config.Layout.MIN_HEIGHT:
print(f"\n❌ TERMINAL BOYUTU ÇOK KÜÇÜK ({cols}x{lines})")
print("Lütfen pencereyi genişletin ve uygulamayı yeniden başlatın.")
print(f"Minimum gerekli boyut: {config.Layout.MIN_WIDTH}x{config.Layout.MIN_HEIGHT}")
input(f"\n{config.UI.PROMPT_EXIT}")
return False
return True
except Exception:
return True
def run_loop(stdscr):
# Initial setup
curses.curs_set(1)
simulation = engine.SimulationEngine()
while True:
# Determine what to show on main UI
action = simulation.get_next_action()
if isinstance(action, engine.ActionExit):
raise KeyboardInterrupt
elif isinstance(action, engine.ActionRenderEditor):
user_code = run_editor_session(
stdscr,
task_info=action.task_info,
hint_text=action.hint_text,
initial_code=action.initial_code,
task_status=action.task_status,
completed_count=action.completed_count,
skipped_count=action.skipped_count
)
# Process input (Code or Command)
result_action = simulation.process_input(user_code)
handle_action(stdscr, result_action)
elif isinstance(action, engine.ActionRenderCelebration):
user_code = run_editor_session(
stdscr,
task_info="",
hint_text="",
initial_code="",
task_status="celebration",
completed_count=action.completed_count,
skipped_count=action.skipped_count,
has_skipped=action.has_skipped
)
result_action = simulation.process_input(user_code)
handle_action(stdscr, result_action)
def check_exit_key():
import os, sys
if os.name == 'nt':
import msvcrt
if msvcrt.kbhit():
key = msvcrt.getch()
if key in (b'\r', b'\n'):
return True
return False
else:
import select
i, _, _ = select.select([sys.stdin], [], [], 0.0)
if i:
try:
char = sys.stdin.read(1)
if char in ('\r', '\n'):
return True
except Exception:
pass
return False
def run_controller():
# Terminal check
if not validate_terminal_size():
return
# macOS spawn fix
import multiprocessing
try:
multiprocessing.set_start_method('spawn', force=True)
except RuntimeError:
pass
try:
curses.wrapper(run_loop)
except curses.error as e:
OSUtils.clear_screen()
print("\n❌ TERMİNAL BAŞLATMA HATASI (curses.error)")
print("-" * 40)
print(f"Hata Detayı: {e}")
print("\nOlası Çözümler:")
print("1. 'TERM' ortam değişkenini kontrol edin (örn: xterm-256color).")
print("2. Windows kullanıyorsanız 'windows-curses' düzgün yüklenmemiş olabilir.")
print("-" * 40)
input(f"\n{config.UI.PROMPT_EXIT}")
sys.exit(1)
except KeyboardInterrupt:
# Ctrl+C Clean exit
OSUtils.clear_screen()
# ANSI Renk Kodları
turquoise = "\033[38;2;64;224;208m"
reset = "\033[0m"
dark_gray = "\033[90m"
print(f"\n{turquoise}{config.UI.MSG_EXIT}{reset}\n\n")
# Geri sayım ve Enter tetikleyicisi
for i in range(10, 0, -1):
sys.stdout.write(f"\r\033[K{dark_gray}Terminal {i:02d} saniye içinde kapanacaktır...{reset}\n")
sys.stdout.write(f"\033[K{dark_gray}Hemen çıkmak için ENTER'a basın.{reset}")
sys.stdout.flush()
interrupted = False
for _ in range(10): # 1 saniyelik bekleyişi 0.1s'lik parçalarda kontrol et
if check_exit_key():
interrupted = True
break
time.sleep(0.1)
if interrupted or i == 1:
break
# Cursor'u 1 satır yukarı al ve satır başına çek
sys.stdout.write("\033[A\r")
print("\n\n")
sys.exit(130)
except Exception as e:
OSUtils.clear_screen()
print("\n❌ BEKLENMEYEN UYGULAMA HATASI")
print("-" * 40)
print(f"Hata: {e}")
import traceback
traceback.print_exc()
print("-" * 40)
input(f"\n{config.UI.PROMPT_EXIT}")
sys.exit(1)