checkpoint: massive refactor
This commit is contained in:
@@ -2,60 +2,54 @@ import ast
|
||||
from pathlib import Path
|
||||
|
||||
class CodeOutliner:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def outline(self, code: str) -> str:
|
||||
code = code.lstrip(chr(0xFEFF))
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
return f"ERROR parsing code: {e}"
|
||||
def outline(self, code: str) -> str:
|
||||
code = code.lstrip(chr(0xFEFF))
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
return f"ERROR parsing code: {e}"
|
||||
output = []
|
||||
|
||||
output = []
|
||||
def get_docstring(node):
|
||||
doc = ast.get_docstring(node)
|
||||
if doc:
|
||||
return doc.splitlines()[0]
|
||||
return None
|
||||
|
||||
def get_docstring(node):
|
||||
doc = ast.get_docstring(node)
|
||||
if doc:
|
||||
return doc.splitlines()[0]
|
||||
return None
|
||||
|
||||
def walk(node, indent=0):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
start_line = node.lineno
|
||||
end_line = getattr(node, "end_lineno", start_line)
|
||||
output.append(f"{' ' * indent}[Class] {node.name} (Lines {start_line}-{end_line})")
|
||||
doc = get_docstring(node)
|
||||
if doc:
|
||||
output.append(f"{' ' * (indent + 1)}\"\"\"{doc}\"\"\"")
|
||||
for item in node.body:
|
||||
walk(item, indent + 1)
|
||||
|
||||
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
start_line = node.lineno
|
||||
end_line = getattr(node, "end_lineno", start_line)
|
||||
prefix = "[Async Func]" if isinstance(node, ast.AsyncFunctionDef) else "[Func]"
|
||||
|
||||
# Check if it's a method
|
||||
# We can check the indent or the parent, but in AST walk we know if we are inside a ClassDef
|
||||
# Let's use a simpler heuristic for the outline: if indent > 0, it's likely a method.
|
||||
if indent > 0:
|
||||
prefix = "[Method]"
|
||||
|
||||
output.append(f"{' ' * indent}{prefix} {node.name} (Lines {start_line}-{end_line})")
|
||||
doc = get_docstring(node)
|
||||
if doc:
|
||||
output.append(f"{' ' * (indent + 1)}\"\"\"{doc}\"\"\"")
|
||||
|
||||
for node in tree.body:
|
||||
walk(node)
|
||||
|
||||
return "\n".join(output)
|
||||
def walk(node, indent=0):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
start_line = node.lineno
|
||||
end_line = getattr(node, "end_lineno", start_line)
|
||||
output.append(f"{' ' * indent}[Class] {node.name} (Lines {start_line}-{end_line})")
|
||||
doc = get_docstring(node)
|
||||
if doc:
|
||||
output.append(f"{' ' * (indent + 1)}\"\"\"{doc}\"\"\"")
|
||||
for item in node.body:
|
||||
walk(item, indent + 1)
|
||||
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
start_line = node.lineno
|
||||
end_line = getattr(node, "end_lineno", start_line)
|
||||
prefix = "[Async Func]" if isinstance(node, ast.AsyncFunctionDef) else "[Func]"
|
||||
# Check if it's a method
|
||||
# We can check the indent or the parent, but in AST walk we know if we are inside a ClassDef
|
||||
# Let's use a simpler heuristic for the outline: if indent > 0, it's likely a method.
|
||||
if indent > 0:
|
||||
prefix = "[Method]"
|
||||
output.append(f"{' ' * indent}{prefix} {node.name} (Lines {start_line}-{end_line})")
|
||||
doc = get_docstring(node)
|
||||
if doc:
|
||||
output.append(f"{' ' * (indent + 1)}\"\"\"{doc}\"\"\"")
|
||||
for node in tree.body:
|
||||
walk(node)
|
||||
return "\n".join(output)
|
||||
|
||||
def get_outline(path: Path, code: str) -> str:
|
||||
suffix = path.suffix.lower()
|
||||
if suffix == ".py":
|
||||
outliner = CodeOutliner()
|
||||
return outliner.outline(code)
|
||||
else:
|
||||
return f"Outlining not supported for {suffix} files yet."
|
||||
suffix = path.suffix.lower()
|
||||
if suffix == ".py":
|
||||
outliner = CodeOutliner()
|
||||
return outliner.outline(code)
|
||||
else:
|
||||
return f"Outlining not supported for {suffix} files yet."
|
||||
|
||||
Reference in New Issue
Block a user