1+ from rich .console import Console
2+ from rich .panel import Panel
3+ from rich .markdown import Markdown
4+ from rich .layout import Layout
5+ from rich .box import ROUNDED
6+ from rich .text import Text
7+ from rich .align import Align
8+ from bs4 import BeautifulSoup
9+ import json
10+ from dataclasses import dataclass
11+ from typing import List , Dict , Optional
12+
13+ console = Console ()
14+
15+ @dataclass
16+ class FunctionMetadata :
17+ name : str
18+ params : List [Dict [str , str ]]
19+ return_type : str
20+
21+ class ProblemDetails :
22+ def __init__ (self , problem_data : dict ):
23+ self .question_id : int = problem_data ['questionId' ]
24+ self .title : str = problem_data ['title' ]
25+ self .difficulty : str = problem_data ['difficulty' ]
26+ self .content : str = problem_data ['content' ]
27+ self .test_cases : List [str ] = problem_data ['exampleTestcases' ].split ('\n ' )
28+ self .code_snippets : List [Dict ] = problem_data ['codeSnippets' ]
29+
30+ # Parse metadata
31+ self .function_metadata : Optional [FunctionMetadata ] = None
32+ try :
33+ metadata = json .loads (problem_data ['metaData' ])
34+ self .function_metadata = FunctionMetadata (
35+ name = metadata .get ('name' , 'solution' ),
36+ params = metadata .get ('params' , []),
37+ return_type = metadata .get ('return' , {}).get ('type' , 'void' )
38+ )
39+ except Exception :
40+ pass
41+
42+ self ._parse_content ()
43+ self .console_width = console .width
44+
45+ def _parse_content (self ):
46+ """Parse the HTML content into different sections"""
47+ soup = BeautifulSoup (self .content , 'html.parser' )
48+
49+ for code in soup .find_all ('code' ):
50+ code .replace_with (soup .new_string (f'`{ code .text } `' ))
51+
52+ self .description : List [str ] = []
53+ self .examples : List [str ] = []
54+ self .constraints : List [str ] = []
55+
56+ current_section = self .description
57+
58+ for p in soup .find_all ('p' ):
59+ text = p .text .strip ()
60+ if not text :
61+ continue
62+
63+ if 'Example' in text :
64+ current_section = self .examples
65+ current_section .append ('\n ' + text )
66+ elif 'Constraints:' in text :
67+ current_section = self .constraints
68+ current_section .append ('\n ' + text )
69+ elif any (marker in text for marker in ['Input:' , 'Output:' , 'Explanation:' ]):
70+ current_section .append (' ' + text )
71+ elif current_section == self .examples and not text .startswith ('Example' ):
72+ current_section .append (' ' + text )
73+ else :
74+ current_section .append (text )
75+
76+ @property
77+ def formatted_description (self ) -> str :
78+ """Get the formatted problem description"""
79+ sections = [
80+ ' ' .join (self .description ),
81+ * self .examples ,
82+ * self .constraints
83+ ]
84+ return '\n ' .join (line for line in sections if line .strip ())
85+
86+ @property
87+ def available_languages (self ) -> List [str ]:
88+ """Get list of available programming languages"""
89+ return [snippet ['lang' ] for snippet in self .code_snippets ]
90+
91+ @property
92+ def formatted_function_signature (self ) -> str :
93+ """Get the formatted function signature"""
94+ if not self .function_metadata :
95+ return "[red]Error loading function signature[/]"
96+
97+ param_str = ', ' .join (
98+ f"{ p ['name' ]} : { p ['type' ]} "
99+ for p in self .function_metadata .params
100+ )
101+
102+ return (
103+ "[bold blue]Function Signature:[/]\n "
104+ f"[bold cyan]def[/] [yellow]{ self .function_metadata .name } [/](\n "
105+ f" [green]{ param_str } [/]\n "
106+ f") -> [green]{ self .function_metadata .return_type } [/]"
107+ )
108+
109+ def get_code_snippet (self , language : str ) -> Optional [str ]:
110+ """Get code snippet for specific language"""
111+ for snippet in self .code_snippets :
112+ if snippet ['lang' ].lower () == language .lower ():
113+ return snippet ['code' ]
114+ return None
115+
116+ def format_test_case (self , input_str : str , expected_str : str , case_num : int ) -> str :
117+ return (
118+ f"[bold blue]Ex { case_num } :[/] "
119+ f"[bold cyan]In:[/] { input_str } → "
120+ f"[bold green]Out:[/] { expected_str } "
121+ )
122+
123+ def create_header (self ):
124+ difficulty_colors = {
125+ 'Easy' : 'bright_green' ,
126+ 'Medium' : 'yellow' ,
127+ 'Hard' : 'red'
128+ }
129+ difficulty_color = difficulty_colors .get (self .difficulty , 'white' )
130+
131+ header = Text ()
132+ header .append ("🔹 " , style = "blue" )
133+ header .append (f"{ self .question_id } . { self .title } " , style = "bold cyan" )
134+ header .append (" • " , style = "dim" )
135+ header .append (self .difficulty , style = difficulty_color )
136+
137+ return Align .center (header )
138+
139+ def display (self ):
140+ console .clear ()
141+
142+ console .print (self .create_header ())
143+ console .print ()
144+
145+ layout = Layout ()
146+ layout .split_row (
147+ Layout (name = "left_section" ),
148+ Layout (name = "sidebar" , size = self .console_width // 4 )
149+ )
150+
151+ layout ["left_section" ].split_column (
152+ Layout (name = "description" , ratio = 85 ),
153+ Layout (name = "bottom" , ratio = 15 )
154+ )
155+
156+ # Update description panel
157+ layout ["description" ].update (Panel (
158+ Markdown (self .formatted_description , justify = "left" , style = "white" ),
159+ box = ROUNDED ,
160+ title = "[bold blue]Description" ,
161+ border_style = "blue" ,
162+ padding = (1 , 2 ),
163+ expand = True
164+ ))
165+
166+ # Update sidebar panel
167+ sidebar_content = (
168+ f"{ self .formatted_function_signature } \n \n "
169+ "[bold blue]Available Languages:[/]\n "
170+ f"[green]{ self .available_languages } [/]"
171+ )
172+
173+ layout ["sidebar" ].update (Panel (
174+ sidebar_content ,
175+ box = ROUNDED ,
176+ border_style = "blue" ,
177+ padding = (1 , 2 ),
178+ expand = True
179+ ))
180+
181+ # Update test cases panel
182+ test_cases_content = []
183+
184+ for i in range (0 , len (self .test_cases ), 2 ):
185+ if i + 1 < len (self .test_cases ):
186+ case_num = i // 2 + 1
187+ test_case = self .format_test_case (
188+ self .test_cases [i ],
189+ self .test_cases [i + 1 ],
190+ case_num
191+ )
192+ test_cases_content .append (test_case )
193+
194+ layout ["bottom" ].update (Panel (
195+ "\n \n " .join (test_cases_content ),
196+ box = ROUNDED ,
197+ title = "[bold blue]Sample Test Cases" ,
198+ border_style = "blue" ,
199+ padding = (1 , 2 ),
200+ ))
201+
202+ console .print (layout )
0 commit comments