import re
from pathlib import Path
from typing import Dict, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
class Language(Enum):
PYTHON = "python"
JAVASCRIPT = "javascript"
HTML = "html"
CSS = "css"
JSON = "json"
MARKDOWN = "markdown"
PLAINTEXT = "plaintext"
JAVA = "java"
CPP = "cpp"
TYPESCRIPT = "typescript"
SQL = "sql"
@dataclass
class CodeFile:
name: str
content: str
language: Language
logo: str
extension: str
can_preview: bool = False
class FileManager:
"""Manages code files, language detection, and logos"""
# Language detection mapping
LANGUAGE_MAP = {
# Extensions to Language
".py": Language.PYTHON,
".js": Language.JAVASCRIPT,
".html": Language.HTML,
".htm": Language.HTML,
".css": Language.CSS,
".json": Language.JSON,
".md": Language.MARKDOWN,
".java": Language.JAVA,
".cpp": Language.CPP,
".c": Language.CPP,
".ts": Language.TYPESCRIPT,
".sql": Language.SQL,
# Shebang detection for Python
"#!/usr/bin/env python": Language.PYTHON,
"#!/usr/bin/python": Language.PYTHON,
}
# Logo mappings (emoji fallbacks, can be replaced with image URLs)
LOGO_MAP = {
Language.PYTHON: "🐍", # Or use: "https://cdn.jsdelivr.net/npm/simple-icons@v13/icons/python.svg"
Language.JAVASCRIPT: "🟨",
Language.HTML: "🌐",
Language.CSS: "🎨",
Language.JSON: "📋",
Language.MARKDOWN: "📝",
Language.JAVA: "☕",
Language.CPP: "⚙️",
Language.TYPESCRIPT: "📘",
Language.SQL: "🗄️",
Language.PLAINTEXT: "📄",
}
# Previewable languages
PREVIEWABLE = {Language.HTML, Language.JAVASCRIPT, Language.CSS}
@classmethod
def detect_language(cls, filename: str, content: str = "") -> Language:
"""Detect language from filename and content"""
# Check by extension
ext = Path(filename).suffix.lower()
if ext in cls.LANGUAGE_MAP:
return cls.LANGUAGE_MAP[ext]
# Check for shebang in first line
if content:
first_line = content.split('\n')[0].strip()
if first_line in cls.LANGUAGE_MAP:
return cls.LANGUAGE_MAP[first_line]
# Heuristic detection
if content:
if " str:
"""Get logo for language (emoji or HTML img tag)"""
if use_emoji:
return cls.LOGO_MAP.get(language, "📄")
# For image URLs, you can use:
# return f''
return cls.LOGO_MAP.get(language, "📄")
@classmethod
def extract_files_from_code(cls, code: str) -> Dict[str, CodeFile]:
"""Extract multiple files from code block (e.g., from AI response)"""
files = {}
# Pattern for markdown code blocks with filenames
# Matches: ```python filename.py\ncode```
pattern = r'```(\w+)(?:\s+([\/\w\.-]+))?\n(.*?)```'
matches = re.findall(pattern, code, re.DOTALL)
for lang, filename, content in matches:
if not filename:
# Generate filename from language
ext_map = {
"python": "script.py",
"javascript": "script.js",
"html": "index.html",
"css": "styles.css",
"json": "data.json",
"java": "Main.java",
"cpp": "program.cpp",
}
filename = ext_map.get(lang.lower(), f"code.{lang}")
language = cls.detect_language(filename, content)
files[filename] = CodeFile(
name=filename,
content=content.strip(),
language=language,
logo=cls.get_logo(language),
extension=Path(filename).suffix,
can_preview=language in cls.PREVIEWABLE
)
return files
@classmethod
def format_file_tree(cls, files: Dict[str, CodeFile]) -> str:
"""Generate HTML for file tree with logos"""
html = '
Your styles are applied to this page.
{escaped}