File size: 4,853 Bytes
77bf0e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
"""
Code Viewer Component - Displays file content with syntax highlighting.
"""
import streamlit as st
from pathlib import Path
from pygments import highlight
from pygments.lexers import get_lexer_for_filename, TextLexer
from pygments.formatters import HtmlFormatter
from typing import Optional


def get_language_from_extension(filename: str) -> str:
    """Get language name from file extension for display."""
    ext = Path(filename).suffix.lower()
    
    languages = {
        ".py": "Python",
        ".js": "JavaScript",
        ".ts": "TypeScript",
        ".jsx": "React JSX",
        ".tsx": "React TSX",
        ".html": "HTML",
        ".css": "CSS",
        ".json": "JSON",
        ".md": "Markdown",
        ".yaml": "YAML",
        ".yml": "YAML",
        ".toml": "TOML",
        ".sql": "SQL",
        ".sh": "Shell",
        ".bash": "Bash",
        ".txt": "Plain Text",
    }
    
    return languages.get(ext, "Code")


def read_file_content(file_path: str) -> Optional[str]:
    """Read and return file content."""
    try:
        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
            return f.read()
    except Exception as e:
        return f"Error reading file: {e}"


def render_code_with_syntax_highlighting(content: str, filename: str):
    """Render code with Pygments syntax highlighting."""
    try:
        lexer = get_lexer_for_filename(filename)
    except:
        lexer = TextLexer()
    
    # Custom CSS for dark theme
    formatter = HtmlFormatter(
        style='monokai',
        linenos=True,
        lineanchors='line',
        cssclass='source',
        wrapcode=True
    )
    
    highlighted = highlight(content, lexer, formatter)
    
    # Custom CSS
    css = """
    <style>
    .source {
        background-color: #1E1E1E !important;
        padding: 10px;
        border-radius: 8px;
        overflow-x: auto;
        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
        font-size: 13px;
        line-height: 1.5;
    }
    .source pre {
        margin: 0;
        background-color: transparent !important;
    }
    .source .linenos {
        color: #6e7681;
        padding-right: 15px;
        border-right: 1px solid #3d3d3d;
        margin-right: 15px;
        user-select: none;
    }
    .source .code {
        color: #e6e6e6;
    }
    </style>
    """
    
    st.markdown(css + highlighted, unsafe_allow_html=True)


def render_code_viewer(file_path: Optional[str] = None):
    """
    Render the code viewer panel.
    
    Args:
        file_path: Path to the file to display
    """
    if not file_path:
        # Show placeholder when no file is selected
        st.markdown("### πŸ“ Code Viewer")
        st.info("πŸ‘ˆ Select a file from the tree to view its contents")
        return
    
    # File header
    filename = Path(file_path).name
    language = get_language_from_extension(filename)
    
    st.markdown(f"### πŸ“ {filename}")
    st.caption(f"πŸ“‚ {file_path} β€’ {language}")
    
    # Read and display content
    content = read_file_content(file_path)
    
    if content:
        # Add line count
        line_count = content.count('\n') + 1
        st.caption(f"{line_count} lines")
        
        # Render with syntax highlighting
        render_code_with_syntax_highlighting(content, filename)
    else:
        st.error("Could not read file contents")


def render_code_viewer_simple(file_path: Optional[str] = None):
    """
    Simpler code viewer using Streamlit's built-in code component.
    More reliable than custom HTML rendering.
    """
    if not file_path:
        st.markdown("### πŸ“ Code Viewer")
        st.info("πŸ‘ˆ Select a file from the tree to view its contents")
        return
    
    filename = Path(file_path).name
    language = get_language_from_extension(filename)
    ext = Path(filename).suffix.lower().lstrip('.')
    
    st.markdown(f"### πŸ“ {filename}")
    st.caption(f"πŸ“‚ `{file_path}` β€’ {language}")
    
    content = read_file_content(file_path)
    
    if content:
        line_count = content.count('\n') + 1
        st.caption(f"{line_count} lines")
        
        # Use Streamlit's native code component
        # Map extensions to language names for st.code
        lang_map = {
            "py": "python",
            "js": "javascript",
            "ts": "typescript",
            "jsx": "javascript",
            "tsx": "typescript",
            "json": "json",
            "md": "markdown",
            "yaml": "yaml",
            "yml": "yaml",
            "sh": "bash",
            "bash": "bash",
            "sql": "sql",
            "html": "html",
            "css": "css",
        }
        
        lang = lang_map.get(ext, "")
        st.code(content, language=lang, line_numbers=True)
    else:
        st.error("Could not read file contents")