Skip to content

Commit 138daf0

Browse files
feat: error fix, save problem to md file..
1 parent 83c8aa5 commit 138daf0

File tree

6 files changed

+180
-51
lines changed

6 files changed

+180
-51
lines changed

src/commands/daily.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,35 @@
55
def daily(
66
lang: str = typer.Argument("py", help="Programming language to use."),
77
editor: str = typer.Option("vim", '-e', help="Code editor to use."),
8+
no_editor: bool = typer.Option(False, "--no-editor", help="Skip opening editor"),
89
):
9-
"""Check the daily problem."""
10+
"""
11+
Get and work on today's LeetCode daily challenge.
12+
13+
Fetches the daily coding challenge, displays problem details,
14+
and opens it in your preferred editor.
15+
"""
1016
from .show import show
1117

18+
typer.echo(typer.style("Welcome to LeetCode Daily!", fg=typer.colors.GREEN))
1219
if editor not in ['code', 'vim', 'nano']:
1320
typer.echo(typer.style(f"❌ Unsupported editor: {editor}", fg=typer.colors.RED))
1421
raise typer.Exit(1)
1522

16-
result = get_daily_question()
17-
question = result['data']['activeDailyCodingChallengeQuestion']
23+
typer.echo(typer.style("Fetching daily challenge...", fg=typer.colors.GREEN), nl=False)
24+
try:
25+
result = get_daily_question()
26+
question = result['data']['activeDailyCodingChallengeQuestion']
27+
typer.echo("\r" + " " * 30 + "\r", nl=False)
28+
except Exception as e:
29+
typer.echo("\n" + typer.style(f"❌ Failed to fetch daily question: {str(e)}", fg=typer.colors.RED))
30+
raise typer.Exit(1)
1831

1932
show(problem=question['question']['titleSlug'], layout=True)
2033

21-
if editor:
22-
edit(problem=question['question']['titleSlug'], lang=lang, editor=editor)
34+
if not no_editor and editor:
35+
try:
36+
edit(problem=question['question']['titleSlug'], lang=lang, editor=editor)
37+
except Exception as e:
38+
typer.echo(typer.style(f"❌ Failed to open editor: {str(e)}", fg=typer.colors.RED))
39+
raise typer.Exit(1)

src/commands/edit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
def edit(
1010
problem: str = typer.Argument(..., help="Problem name or id."),
1111
lang: str = typer.Argument("cpp", help="Programming language to use."),
12-
editor: str = typer.Option("vim", '-e', '--editor', help="vim editor to use."),
12+
editor: str = typer.Option("vim", '-e', '--editor', help="Editor to use for code editing."),
1313
):
1414
"""Solves a problem by passing lang param and open it with your code editor."""
1515
question_data = solution_manager.get_question_data(problem).get('data', {}).get('question')

src/commands/login.py

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,36 @@ def login():
1111
typer.echo(typer.style(f"Already logged in as {saved_session['user_name']}!", fg=typer.colors.GREEN))
1212
return
1313

14-
typer.echo(typer.style("To login, you'll need both CSRF and LEETCODE_SESSION tokens:", fg=typer.colors.YELLOW))
15-
typer.echo("\n1. Open LeetCode in your browser")
16-
typer.echo("2. Press F12 to open Developer Tools")
17-
typer.echo("3. Go to Application tab > Cookies > leetcode.com")
18-
typer.echo("4. Find and copy both 'csrftoken' and 'LEETCODE_SESSION' values\n")
19-
20-
csrf_token = typer.prompt("Please enter your CSRF token")
21-
csrf_result = auth_manager.verify_csrf_token(csrf_token)
22-
23-
if not csrf_result["success"]:
24-
typer.echo(typer.style(f"\n✗ CSRF verification failed: {csrf_result['message']}", fg=typer.colors.RED))
25-
return
14+
instruction = f"""
15+
📝 To get your login tokens:
16+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
17+
1️ Open LeetCode in your browser
18+
2️ Press F12 to open Developer Tools
19+
3️ Go to Application tab → Cookies → leetcode.com
20+
4️ Find and copy both 'csrftoken' and 'LEETCODE_SESSION'
21+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
22+
"""
23+
24+
typer.echo(typer.style(instruction, fg=typer.colors.BRIGHT_BLACK))
25+
26+
while True:
27+
csrf_token = typer.prompt("Please enter your CSRF token")
28+
csrf_result = auth_manager.verify_csrf_token(csrf_token)
29+
30+
if not csrf_result["success"]:
31+
typer.echo(typer.style(f"\n✗ CSRF verification failed: {csrf_result['message']}", fg=typer.colors.RED))
32+
return
2633

27-
leetcode_session = typer.prompt("Please enter your LEETCODE_SESSION token")
28-
result = auth_manager.login_with_session(csrf_token, leetcode_session)
34+
leetcode_session = typer.prompt("Please enter your LEETCODE_SESSION token")
35+
result = auth_manager.login_with_session(csrf_token, leetcode_session)
2936

30-
if result["success"]:
31-
typer.echo(typer.style(f"\n✓ Successfully logged in as {result['user_name']}!", fg=typer.colors.GREEN))
32-
else:
33-
typer.echo(typer.style(f"\n✗ Login failed: {result['message']}", fg=typer.colors.RED))
37+
if result["success"]:
38+
typer.echo(typer.style(f"\n✓ Successfully logged in as {result['user_name']}!", fg=typer.colors.GREEN))
39+
break
40+
else:
41+
typer.echo(typer.style(f"\n✗ Login failed: {result['message']}", fg=typer.colors.RED))
42+
if not typer.confirm("Do you want to try again?", abort=True):
43+
break
3444

3545
def logout():
3646
"""Logout from LeetCode"""

src/commands/show.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import typer
2+
import os
23
from rich.console import Console
34
from ..lib.problem_ui import ProblemDetails
45
from ..server.auth import Auth
@@ -8,19 +9,52 @@
89
solution_manager = SolutionManager(auth_manager.get_session())
910
console = Console()
1011

11-
def show(problem: str = typer.Argument(..., help="Problem slug or number (e.g., 'two-sum' or '1')"), layout: bool = False):
12-
"""Show problem details including description and test cases"""
12+
def show(
13+
problem: str = typer.Argument(..., help="Problem slug or number (e.g., 'two-sum' or '1')"),
14+
compact: bool = typer.Option(False, "--compact", "-c", help="Display in compact layout"),
15+
save: bool = typer.Option(False, "--save", "-s", help="Save problem description to a file")
16+
):
17+
"""
18+
Show problem details including description and test cases
19+
20+
Fetches and displays the problem statement, examples, and metadata.
21+
Use --compact for a condensed view or --save to export to a file.
22+
"""
1323

1424
if not auth_manager.is_authenticated:
1525
typer.echo(typer.style("❌ Please login first using the login command", fg=typer.colors.RED))
1626
raise typer.Exit(1)
1727

18-
data = solution_manager.get_question_data(problem)
19-
if not data.get('data', {}).get('question'):
20-
typer.echo(typer.style(f"❌ Problem '{problem}' not found", fg=typer.colors.RED))
28+
try:
29+
data = solution_manager.get_question_data(problem)
30+
if not data.get('data', {}).get('question'):
31+
typer.echo(typer.style(f"❌ Problem '{problem}' not found", fg=typer.colors.RED))
32+
raise typer.Exit(1)
33+
34+
question = data.get('data', {}).get('question')
35+
problem_details = ProblemDetails(question)
36+
37+
if save:
38+
_save_problem_to_file(question)
39+
40+
if compact:
41+
problem_details.display()
42+
else:
43+
problem_details.display_full()
44+
45+
except Exception as e:
46+
typer.echo(typer.style(f"❌ Error: {str(e)}", fg=typer.colors.RED))
2147
raise typer.Exit(1)
2248

23-
if not layout:
24-
ProblemDetails(data.get('data', {}).get('question')).display_full()
25-
else:
26-
ProblemDetails(data.get('data', {}).get('question')).display()
49+
def _save_problem_to_file(question_data):
50+
"""Save the problem statement to a markdown file"""
51+
title_slug = question_data.get('titleSlug', 'problem')
52+
title = question_data.get('title', 'Untitled Problem')
53+
54+
filename = f"{title_slug}.md"
55+
with open(filename, 'w') as f:
56+
f.write(f"# {title}\n\n")
57+
f.write(f"**Difficulty:** {question_data.get('difficulty', 'Unknown')}\n\n")
58+
f.write(question_data.get('content', ''))
59+
60+
typer.echo(typer.style(f"✅ Problem saved to {os.path.abspath(filename)}", fg=typer.colors.GREEN))

src/commands/submit.py

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
import typer
2+
import os
23
from pathlib import Path
4+
from typing import Optional
35
from ..server.auth import Auth
46
from ..server.solution_manager import SolutionManager
57

68
auth_manager = Auth()
79
solution_manager = SolutionManager(auth_manager.get_session())
810

11+
LANGUAGE_MAP = {
12+
'.py': 'python3',
13+
'.cpp': 'cpp',
14+
'.c': 'c',
15+
'.java': 'java',
16+
'.js': 'javascript',
17+
'.ts': 'typescript',
18+
'.go': 'golang',
19+
'.rs': 'rust',
20+
'.rb': 'ruby',
21+
'.cs': 'csharp',
22+
'.swift': 'swift',
23+
'.php': 'php',
24+
}
25+
926
def submit(
10-
problem: str = typer.Argument(..., help="Problem slug (e.g., 'two-sum')"),
27+
problem: str = typer.Argument(..., help="Problem slug or number (e.g., 'two-sum' or '1')"),
1128
file: Path = typer.Argument(..., help="Path to solution file"),
12-
lang: str = typer.Option("python3", help="Programming language")
29+
lang: Optional[str] = typer.Option(None, help="Programming language (auto-detected if not specified)"),
30+
force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation prompt")
1331
):
14-
"""Submit a solution to LeetCode"""
32+
"""
33+
Submit a solution to LeetCode
34+
35+
Uploads your solution file to LeetCode and returns the verdict.
36+
Language is auto-detected from file extension if not specified.
37+
"""
1538
if not auth_manager.is_authenticated:
1639
typer.echo(typer.style("❌ Please login first using the login command", fg=typer.colors.RED))
1740
raise typer.Exit(1)
@@ -20,17 +43,50 @@ def submit(
2043
typer.echo(typer.style(f"❌ File not found: {file}", fg=typer.colors.RED))
2144
raise typer.Exit(1)
2245

23-
with open(file, 'r') as f:
24-
code = f.read()
46+
try:
47+
# Auto-detect language from file extension if not provided
48+
if not lang:
49+
extension = os.path.splitext(file)[1].lower()
50+
if extension in LANGUAGE_MAP:
51+
lang = LANGUAGE_MAP[extension]
52+
typer.echo(typer.style(f"🔍 Auto-detected language: {lang}", fg=typer.colors.BLUE))
53+
else:
54+
typer.echo(typer.style(f"❌ Could not detect language for {extension} files. Please specify with --lang", fg=typer.colors.RED))
55+
raise typer.Exit(1)
56+
57+
with open(file, 'r') as f:
58+
code = f.read()
59+
60+
# Confirm submission unless forced
61+
if not force:
62+
typer.echo(typer.style(f"Problem: {problem}", fg=typer.colors.BLUE))
63+
typer.echo(typer.style(f"Language: {lang}", fg=typer.colors.BLUE))
64+
typer.echo(typer.style(f"File: {file}", fg=typer.colors.BLUE))
65+
if not typer.confirm("Do you want to submit this solution?"):
66+
typer.echo(typer.style("Submission canceled", fg=typer.colors.YELLOW))
67+
raise typer.Exit(0)
68+
69+
typer.echo(typer.style("📤 Submitting solution...", fg=typer.colors.YELLOW))
70+
result = solution_manager.submit_solution(problem, code, lang)
71+
72+
if result["success"]:
73+
status = result['status']
74+
status_color = (
75+
typer.colors.GREEN if status == "Accepted"
76+
else typer.colors.YELLOW if status == "Runtime Error" or status == "Time Limit Exceeded"
77+
else typer.colors.RED
78+
)
79+
80+
typer.echo(typer.style(f"\n✨ Status: {status}", fg=status_color))
81+
typer.echo(f"⏱️ Runtime: {result['runtime']}")
82+
typer.echo(f"💾 Memory: {result['memory']}")
83+
typer.echo(f"✅ Passed: {result['passed_testcases']}/{result['total_testcases']} test cases")
2584

26-
typer.echo(typer.style("📤 Submitting solution...", fg=typer.colors.YELLOW))
27-
result = solution_manager.submit_solution(problem, code, lang)
85+
if status != "Accepted":
86+
typer.echo(typer.style(f"\n❗ Error message: {result.get('error_message', 'No details available')}", fg=typer.colors.RED))
87+
else:
88+
typer.echo(typer.style(f"\n❌ Submission failed: {result['error']}", fg=typer.colors.RED))
2889

29-
if result["success"]:
30-
status_color = typer.colors.GREEN if result["status"] == "Accepted" else typer.colors.RED
31-
typer.echo(typer.style(f"\n✨ Status: {result['status']}", fg=status_color))
32-
typer.echo(f"⏱️ Runtime: {result['runtime']}")
33-
typer.echo(f"💾 Memory: {result['memory']}")
34-
typer.echo(f"✅ Passed: {result['passed_testcases']}/{result['total_testcases']} test cases")
35-
else:
36-
typer.echo(typer.style(f"\n❌ Submission failed: {result['error']}", fg=typer.colors.RED))
90+
except Exception as e:
91+
typer.echo(typer.style(f"❌ Error: {str(e)}", fg=typer.colors.RED))
92+
raise typer.Exit(1)

src/commands/test.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@
1010
"py": "python3",
1111
"java": "java",
1212
"js": "javascript",
13+
"ts": "typescript",
1314
"c": "c",
14-
"cpp": "cpp"
15+
"cpp": "cpp",
16+
"cs": "csharp",
17+
"go": "golang",
18+
"rb": "ruby",
19+
"swift": "swift",
20+
"rs": "rust",
21+
"php": "php"
1522
}
1623

1724
def test(
@@ -33,17 +40,22 @@ def test(
3340
lang = map_lang.get(file.suffix[1:])
3441
if not lang:
3542
typer.echo(typer.style(f"❌ Unsupported file extension: {file.suffix}", fg=typer.colors.RED))
43+
typer.echo(f"Supported extensions: {', '.join(map_lang.keys())}")
3644
raise typer.Exit(1)
3745

3846
typer.echo(typer.style("🧪 Testing solution with LeetCode test cases...", fg=typer.colors.YELLOW))
39-
result = solution_manager.test_solution(problem, code, lang)
47+
try:
48+
result = solution_manager.test_solution(problem, code, lang)
49+
except Exception as e:
50+
typer.echo(typer.style(f"❌ Error connecting to LeetCode: {str(e)}", fg=typer.colors.RED))
51+
raise typer.Exit(1)
4052

4153
if result["success"]:
4254
status_color = typer.colors.GREEN if result["status"] == "Accepted" else typer.colors.RED
4355
status_prefix = "✨" if result['status'] == "Accepted" else "❌"
4456
typer.echo(typer.style(f"\n{status_prefix} Status: {result['status']}", fg=status_color))
4557
if "runtime" in result:
46-
typer.echo(f"⏱️ Runtime: {result['runtime']}")
58+
typer.echo(f"⏱️Runtime: {result['runtime']}")
4759
if "memory" in result:
4860
typer.echo(f"💾 Memory: {result['memory']}")
4961
typer.echo("\nTest Case Results:\n")

0 commit comments

Comments
 (0)