Skip to content

Commit 4d079e8

Browse files
committed
fix: add Windows compatibility (msvcrt, no tty/termios)
1 parent de4cf76 commit 4d079e8

1 file changed

Lines changed: 40 additions & 17 deletions

File tree

codex-md.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,16 @@
1818
import json
1919
import glob
2020
import re
21-
import tty
22-
import termios
2321
from datetime import datetime
2422
from pathlib import Path
2523
from typing import List, Dict, Optional, Tuple, Set
2624

25+
# Platform-specific terminal handling
26+
_IS_WINDOWS = sys.platform == 'win32'
27+
if not _IS_WINDOWS:
28+
import tty
29+
import termios
30+
2731
# ──────────────────────────────────────────────────────────────
2832
# Terminal Styling
2933
# ──────────────────────────────────────────────────────────────
@@ -771,27 +775,46 @@ def _cap_text(text: str) -> str:
771775
# ──────────────────────────────────────────────────────────────
772776
# Keyboard Input (raw terminal, single keypress)
773777
# ──────────────────────────────────────────────────────────────
778+
def _clear_screen():
779+
"""Cross-platform screen clear."""
780+
os.system('cls' if _IS_WINDOWS else 'clear')
781+
774782
def read_key() -> str:
775-
fd = sys.stdin.fileno()
776-
old = termios.tcgetattr(fd)
777-
try:
778-
tty.setraw(fd)
779-
ch = sys.stdin.read(1)
780-
if ch == '\x1b':
781-
ch2 = sys.stdin.read(1)
782-
if ch2 == '[':
783-
ch3 = sys.stdin.read(1)
784-
return {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'}.get(ch3, '')
785-
return 'ESC'
783+
"""Read a single keypress cross-platform."""
784+
if _IS_WINDOWS:
785+
import msvcrt
786+
ch = msvcrt.getwch()
786787
if ch in ('\r', '\n'):
787788
return 'ENTER'
788789
if ch == ' ':
789790
return 'SPACE'
790791
if ch == '\x03':
791792
raise KeyboardInterrupt
793+
if ch == '\xe0' or ch == '\x00': # special key prefix on Windows
794+
ext = msvcrt.getwch()
795+
return {'H': 'UP', 'P': 'DOWN', 'M': 'RIGHT', 'K': 'LEFT'}.get(ext, '')
792796
return ch.upper()
793-
finally:
794-
termios.tcsetattr(fd, termios.TCSADRAIN, old)
797+
else:
798+
fd = sys.stdin.fileno()
799+
old = termios.tcgetattr(fd)
800+
try:
801+
tty.setraw(fd)
802+
ch = sys.stdin.read(1)
803+
if ch == '\x1b':
804+
ch2 = sys.stdin.read(1)
805+
if ch2 == '[':
806+
ch3 = sys.stdin.read(1)
807+
return {'A': 'UP', 'B': 'DOWN', 'C': 'RIGHT', 'D': 'LEFT'}.get(ch3, '')
808+
return 'ESC'
809+
if ch in ('\r', '\n'):
810+
return 'ENTER'
811+
if ch == ' ':
812+
return 'SPACE'
813+
if ch == '\x03':
814+
raise KeyboardInterrupt
815+
return ch.upper()
816+
finally:
817+
termios.tcsetattr(fd, termios.TCSADRAIN, old)
795818

796819
# ──────────────────────────────────────────────────────────────
797820
# Interactive Section Filter
@@ -907,7 +930,7 @@ def get_lines_for_state(cap_out: int, cap_user: int, cap_agent: int, cap_reason:
907930
pct = (selected_lines / total_lines * 100) if total_lines > 0 else 0
908931

909932
# ── Render ──
910-
os.system('clear')
933+
_clear_screen()
911934
sessions_label = f"{len(parsers)} session{'s' if len(parsers) > 1 else ''}"
912935
print(f"\n {Style.BOLD}{Style.HEADER}SECTION FILTER{Style.RESET} {Style.DIM}({sessions_label}){Style.RESET}")
913936
print(f" {Style.DIM}{'━' * 62}{Style.RESET}\n")
@@ -1189,7 +1212,7 @@ def process_conversion(indices_str: str, files: List[Path]):
11891212
input(f"\n{Style.DIM}Press Enter to return to menu...{Style.RESET}")
11901213
return
11911214

1192-
os.system('clear')
1215+
_clear_screen()
11931216

11941217
# Ask for export destination
11951218
dest_choice = ''

0 commit comments

Comments
 (0)