Remove comments from python files.
This commit is contained in:
parent
daf77f0ba2
commit
00b5d2d903
53
pf.py
Executable file
53
pf.py
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import tokenize
|
||||||
|
import io
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def remove_comments_from_code(source_code):
|
||||||
|
tokens = tokenize.generate_tokens(io.StringIO(source_code).readline)
|
||||||
|
tokens_no_comments = [
|
||||||
|
token for token in tokens if token.type != tokenize.COMMENT
|
||||||
|
]
|
||||||
|
return tokenize.untokenize(tokens_no_comments)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Remove all comments from a Python file using tokenize.'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'input_file',
|
||||||
|
help='Path to the target Python file.'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'output_file',
|
||||||
|
nargs='?',
|
||||||
|
help='Path to save the cleaned Python file. If omitted, prints to stdout.'
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(args.input_file, 'r', encoding='utf-8') as f:
|
||||||
|
source_code = f.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading file: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cleaned_code = remove_comments_from_code(source_code)
|
||||||
|
|
||||||
|
if args.output_file:
|
||||||
|
try:
|
||||||
|
with open(args.output_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(cleaned_code)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error writing file: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print(cleaned_code)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
42
shortcuts.py
42
shortcuts.py
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
"""
|
||||||
vim_terminal_trainer.py – *v2*
|
vim_terminal_trainer.py – *v2*
|
||||||
================================
|
================================
|
||||||
@ -35,7 +35,7 @@ import time
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List, Tuple
|
from typing import Dict, List, Tuple
|
||||||
|
|
||||||
# ------------------- DATA & CONFIG -----------------------------------------
|
|
||||||
|
|
||||||
DEFAULT_QUESTIONS: List[Dict[str, object]] = [
|
DEFAULT_QUESTIONS: List[Dict[str, object]] = [
|
||||||
{"task": "Delete (cut) the current line in Vim", "answers": ["dd"]},
|
{"task": "Delete (cut) the current line in Vim", "answers": ["dd"]},
|
||||||
@ -462,7 +462,7 @@ TIME_LIMIT_SEC = 15
|
|||||||
DATA_DIR = Path.home() / ".vim_terminal_trainer"
|
DATA_DIR = Path.home() / ".vim_terminal_trainer"
|
||||||
SCORE_FILE = DATA_DIR / "score.json"
|
SCORE_FILE = DATA_DIR / "score.json"
|
||||||
|
|
||||||
# ------------------- PERSISTENCE -------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def load_score() -> Dict[str, int]:
|
def load_score() -> Dict[str, int]:
|
||||||
@ -485,7 +485,7 @@ def save_score(high: int, played: int) -> None:
|
|||||||
json.dump({"high_score": high, "games_played": played}, f)
|
json.dump({"high_score": high, "games_played": played}, f)
|
||||||
|
|
||||||
|
|
||||||
# ------------------- CURSES UI HELPERS -------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def draw_centered(
|
def draw_centered(
|
||||||
@ -506,7 +506,7 @@ def render_timer(stdscr: "curses._CursesWindow", remaining: float) -> None:
|
|||||||
stdscr.addstr(0, 0, f"⏰[{bar}] {remaining:4.1f}s")
|
stdscr.addstr(0, 0, f"⏰[{bar}] {remaining:4.1f}s")
|
||||||
|
|
||||||
|
|
||||||
# ------------------- GAMEPLAY ----------------------------------------------
|
|
||||||
def sanitize_question(q):
|
def sanitize_question(q):
|
||||||
"""Return a dict with keys 'task' and 'answers' no matter what comes in."""
|
"""Return a dict with keys 'task' and 'answers' no matter what comes in."""
|
||||||
if isinstance(q, dict):
|
if isinstance(q, dict):
|
||||||
@ -524,20 +524,20 @@ def ask_question_curses(
|
|||||||
idx: int,
|
idx: int,
|
||||||
total: int,
|
total: int,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
q = sanitize_question(q) # ← new – normalise input
|
q = sanitize_question(q)
|
||||||
stdscr.clear()
|
stdscr.clear()
|
||||||
h, w = stdscr.getmaxyx()
|
h, w = stdscr.getmaxyx()
|
||||||
|
|
||||||
# Header
|
|
||||||
header = f"Question {idx}/{total} – Type the command:"
|
header = f"Question {idx}/{total} – Type the command:"
|
||||||
draw_centered(stdscr, 2, header, bold=True)
|
draw_centered(stdscr, 2, header, bold=True)
|
||||||
|
|
||||||
# Task text (wrapped)
|
|
||||||
wrapped = textwrap.fill(q["task"], width=min(70, w - 4))
|
wrapped = textwrap.fill(q["task"], width=min(70, w - 4))
|
||||||
for i, line in enumerate(wrapped.splitlines(), start=4):
|
for i, line in enumerate(wrapped.splitlines(), start=4):
|
||||||
draw_centered(stdscr, i, line)
|
draw_centered(stdscr, i, line)
|
||||||
|
|
||||||
# Input prompt area
|
|
||||||
input_y = 6 + wrapped.count("\n")
|
input_y = 6 + wrapped.count("\n")
|
||||||
stdscr.addstr(input_y, 2, "› ")
|
stdscr.addstr(input_y, 2, "› ")
|
||||||
stdscr.refresh()
|
stdscr.refresh()
|
||||||
@ -558,46 +558,46 @@ def ask_question_curses(
|
|||||||
if remaining <= 0:
|
if remaining <= 0:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Non‑blocking read (100 ms chunks)
|
|
||||||
stdscr.timeout(100)
|
stdscr.timeout(100)
|
||||||
ch = stdscr.getch()
|
ch = stdscr.getch()
|
||||||
if ch == -1:
|
if ch == -1:
|
||||||
continue # no keypress yet
|
continue
|
||||||
if ch in (curses.KEY_BACKSPACE, 127, 8):
|
if ch in (curses.KEY_BACKSPACE, 127, 8):
|
||||||
buffer = buffer[:-1]
|
buffer = buffer[:-1]
|
||||||
continue
|
continue
|
||||||
if ch in (10, 13):
|
if ch in (10, 13):
|
||||||
# User pressed Return anyway – treat as submission
|
|
||||||
break
|
break
|
||||||
if 0 <= ch <= 255:
|
if 0 <= ch <= 255:
|
||||||
buffer += chr(ch)
|
buffer += chr(ch)
|
||||||
|
|
||||||
# Auto‑check
|
|
||||||
norm = " ".join(buffer.split())
|
norm = " ".join(buffer.split())
|
||||||
if norm in valid:
|
if norm in valid:
|
||||||
# Flash feedback
|
|
||||||
curses.curs_set(0)
|
curses.curs_set(0)
|
||||||
stdscr.addstr(input_y + 1, 4, "✅ Correct!", curses.A_BOLD)
|
stdscr.addstr(input_y + 1, 4, "✅ Correct!", curses.A_BOLD)
|
||||||
stdscr.refresh()
|
stdscr.refresh()
|
||||||
time.sleep(0.4)
|
time.sleep(0.4)
|
||||||
return True
|
return True
|
||||||
# Trim oversized buffer to keep UI tidy
|
|
||||||
if len(buffer) > longest + 5:
|
if len(buffer) > longest + 5:
|
||||||
buffer = buffer[-(longest + 5) :]
|
buffer = buffer[-(longest + 5) :]
|
||||||
|
|
||||||
# Manual submission (Return) or timeout
|
|
||||||
norm = " ".join(buffer.split())
|
norm = " ".join(buffer.split())
|
||||||
return norm in valid
|
return norm in valid
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) -> None:
|
def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) -> None:
|
||||||
score_data = load_score()
|
score_data = load_score()
|
||||||
curses.curs_set(0)
|
curses.curs_set(0)
|
||||||
|
|
||||||
# Ask number of questions (simple prompt outside curses because of text input)
|
|
||||||
curses.endwin()
|
curses.endwin()
|
||||||
try:
|
try:
|
||||||
q_default = 10 if len(pool) >= 10 else len(pool)
|
q_default = 10 if len(pool) >= 10 else len(pool)
|
||||||
@ -606,7 +606,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
|
|||||||
num_q = q_default
|
num_q = q_default
|
||||||
num_q = max(1, min(num_q, len(pool)))
|
num_q = max(1, min(num_q, len(pool)))
|
||||||
|
|
||||||
# Back into curses
|
|
||||||
stdscr = curses.initscr()
|
stdscr = curses.initscr()
|
||||||
curses.noecho()
|
curses.noecho()
|
||||||
curses.cbreak()
|
curses.cbreak()
|
||||||
@ -619,7 +619,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
|
|||||||
if ask_question_curses(stdscr, q, idx, num_q):
|
if ask_question_curses(stdscr, q, idx, num_q):
|
||||||
correct += 1
|
correct += 1
|
||||||
|
|
||||||
# Final screen
|
|
||||||
stdscr.clear()
|
stdscr.clear()
|
||||||
result_text = f"You scored {correct}/{num_q}!"
|
result_text = f"You scored {correct}/{num_q}!"
|
||||||
draw_centered(stdscr, 3, result_text, bold=True)
|
draw_centered(stdscr, 3, result_text, bold=True)
|
||||||
@ -640,7 +640,7 @@ def play_game(stdscr: "curses._CursesWindow", pool: List[Dict[str, object]]) ->
|
|||||||
stdscr.getch()
|
stdscr.getch()
|
||||||
|
|
||||||
|
|
||||||
# ------------------- MAIN ---------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
def main_menu() -> None:
|
def main_menu() -> None:
|
||||||
|
Loading…
Reference in New Issue
Block a user