Skip to content

Commit 053ffb7

Browse files
committed
fix(cli): improve live input responsiveness
1 parent 84aff03 commit 053ffb7

File tree

1 file changed

+58
-31
lines changed

1 file changed

+58
-31
lines changed

kubernetes_monitoring.py

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,15 @@
3939
POSIX_INPUT_BUFFER: List[str] = []
4040
CURRENT_INPUT_DISPLAY = ""
4141

42+
LIVE_REFRESH_INTERVAL = 2.0 # seconds
43+
INPUT_POLL_INTERVAL = 0.05 # seconds
44+
COMMAND_INPUT_VISIBLE = False
45+
4246

4347
def _set_input_display(text: str) -> None:
44-
global CURRENT_INPUT_DISPLAY
48+
global CURRENT_INPUT_DISPLAY, COMMAND_INPUT_VISIBLE
4549
CURRENT_INPUT_DISPLAY = text
50+
COMMAND_INPUT_VISIBLE = bool(text) and text.startswith(":")
4651

4752

4853
def _clear_input_display() -> None:
@@ -168,6 +173,10 @@ def _read_nonblocking_command() -> Optional[str]:
168173
_clear_input_display()
169174
# Enter 입력 시 CR/LF 잔여 문자를 비움
170175
continue
176+
if char == "\x1b":
177+
WINDOWS_INPUT_BUFFER.clear()
178+
_clear_input_display()
179+
continue
171180
if char in ("\b", "\x7f"):
172181
if WINDOWS_INPUT_BUFFER:
173182
WINDOWS_INPUT_BUFFER.pop()
@@ -205,6 +214,20 @@ def _read_nonblocking_command() -> Optional[str]:
205214
POSIX_INPUT_BUFFER.clear()
206215
_clear_input_display()
207216
break
217+
if char == "\x1b":
218+
POSIX_INPUT_BUFFER.clear()
219+
_clear_input_display()
220+
while True:
221+
readable, _, _ = select.select([fd], [], [], 0)
222+
if not readable:
223+
break
224+
try:
225+
leftover = posix_os.read(fd, 1)
226+
except OSError:
227+
break
228+
if not leftover:
229+
break
230+
continue
208231
if char in ("\x7f", "\b"):
209232
if POSIX_INPUT_BUFFER:
210233
POSIX_INPUT_BUFFER.pop()
@@ -285,13 +308,24 @@ def update(
285308
self.last_frame = None
286309
if frame_key != self.last_frame:
287310
self.live.update(renderable)
311+
self.live.refresh()
288312
self.last_frame = frame_key
289313
if snapshot_markdown is not None:
290314
self.latest_snapshot = snapshot_markdown
291315

292-
def tick(self) -> None:
293-
_tick_iteration(self.live, self.latest_snapshot)
294-
time.sleep(2)
316+
def tick(self, interval: float = LIVE_REFRESH_INTERVAL) -> None:
317+
deadline = time.monotonic() + interval
318+
while True:
319+
previous_input = self.last_input_state
320+
_tick_iteration(self.live, self.latest_snapshot)
321+
current_input = CURRENT_INPUT_DISPLAY
322+
if current_input != previous_input:
323+
self.last_input_state = current_input
324+
self.live.refresh()
325+
remaining = deadline - time.monotonic()
326+
if remaining <= 0:
327+
break
328+
time.sleep(min(INPUT_POLL_INTERVAL, remaining))
295329

296330

297331
def _parse_cpu_to_millicores(value: str) -> int:
@@ -365,33 +399,26 @@ def _command_panel(command: str) -> Panel:
365399
)
366400

367401

368-
class _CommandInputRenderable:
369-
"""현재 입력 버퍼 상태를 실시간으로 렌더링."""
402+
class _CommandInputPanel:
403+
"""COMMAND_INPUT_VISIBLE 상태에 따라 패널을 조건부로 출력."""
370404

371405
def __rich_console__(self, console: Console, options): # type: ignore[override]
406+
if not COMMAND_INPUT_VISIBLE:
407+
return
372408
display = CURRENT_INPUT_DISPLAY
373-
if display:
374-
prompt = display if display.startswith(":") else f":{display}"
375-
style = "bold cyan"
376-
else:
377-
prompt = ":"
378-
style = "dim"
379-
yield Text(prompt, style=style)
380-
381-
382-
def _input_prompt_panel() -> Panel:
383-
"""현재 명령 입력 상태를 표시하는 패널."""
384-
return Panel(
385-
_CommandInputRenderable(),
386-
title="command input",
387-
border_style="cyan",
388-
)
409+
prompt = display if display else ":"
410+
style = "bold cyan" if display else "dim"
411+
yield Panel(
412+
Text(prompt, style=style),
413+
title="command input",
414+
border_style="cyan",
415+
)
389416

390417

391418
def _compose_group(command: str, *renderables: RenderableType) -> Group:
392419
"""메인 콘텐츠와 kubectl 명령을 하단에 배치한 그룹 구성."""
393420
items: List[RenderableType] = []
394-
items.append(_input_prompt_panel())
421+
items.append(_CommandInputPanel())
395422
items.extend(renderables)
396423
items.append(_command_panel(command))
397424
return Group(*items)
@@ -738,7 +765,7 @@ def watch_event_monitoring() -> None:
738765

739766
try:
740767
with suppress_terminal_echo():
741-
with Live(console=console, refresh_per_second=4.0) as live:
768+
with Live(console=console, auto_refresh=False) as live:
742769
tracker = LiveFrameTracker(live)
743770
while True:
744771
stdout, error = _run_shell_command(full_cmd)
@@ -920,7 +947,7 @@ def watch_pod_monitoring_by_creation() -> None:
920947

921948
try:
922949
with suppress_terminal_echo():
923-
with Live(console=console, refresh_per_second=4.0) as live:
950+
with Live(console=console, auto_refresh=False) as live:
924951
tracker = LiveFrameTracker(live)
925952
while True:
926953
stdout, error = _run_shell_command(full_cmd)
@@ -1027,7 +1054,7 @@ def watch_non_running_pod() -> None:
10271054

10281055
try:
10291056
with suppress_terminal_echo():
1030-
with Live(console=console, refresh_per_second=4.0) as live:
1057+
with Live(console=console, auto_refresh=False) as live:
10311058
tracker = LiveFrameTracker(live)
10321059
while True:
10331060
stdout, error = _run_shell_command(full_cmd)
@@ -1125,7 +1152,7 @@ def watch_pod_counts() -> None:
11251152
v1 = client.CoreV1Api()
11261153
try:
11271154
with suppress_terminal_echo():
1128-
with Live(console=console, refresh_per_second=4.0) as live:
1155+
with Live(console=console, auto_refresh=False) as live:
11291156
tracker = LiveFrameTracker(live)
11301157
while True:
11311158
pods = get_pods(v1, ns)
@@ -1221,7 +1248,7 @@ def watch_node_monitoring_by_creation() -> None:
12211248

12221249
try:
12231250
with suppress_terminal_echo():
1224-
with Live(console=console, refresh_per_second=4.0) as live:
1251+
with Live(console=console, auto_refresh=False) as live:
12251252
tracker = LiveFrameTracker(live)
12261253
while True:
12271254
stdout, error = _run_shell_command(full_cmd)
@@ -1341,7 +1368,7 @@ def watch_unhealthy_nodes() -> None:
13411368

13421369
try:
13431370
with suppress_terminal_echo():
1344-
with Live(console=console, refresh_per_second=4.0) as live:
1371+
with Live(console=console, auto_refresh=False) as live:
13451372
tracker = LiveFrameTracker(live)
13461373
while True:
13471374
stdout, error = _run_shell_command(full_cmd)
@@ -1472,7 +1499,7 @@ def watch_node_resources() -> None:
14721499

14731500
try:
14741501
with suppress_terminal_echo():
1475-
with Live(console=console, refresh_per_second=4.0) as live:
1502+
with Live(console=console, auto_refresh=False) as live:
14761503
tracker = LiveFrameTracker(live)
14771504
while True:
14781505
stdout, error = _run_shell_command(full_cmd)
@@ -1605,7 +1632,7 @@ def watch_pod_resources() -> None:
16051632

16061633
try:
16071634
with suppress_terminal_echo():
1608-
with Live(console=console, refresh_per_second=4.0) as live:
1635+
with Live(console=console, auto_refresh=False) as live:
16091636
tracker = LiveFrameTracker(live)
16101637
while True:
16111638
metrics, error, kubectl_cmd = _get_kubectl_top_pod(namespace)

0 commit comments

Comments
 (0)