Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,7 +13,7 @@ import re
|
|
| 13 |
|
| 14 |
# Set page configuration
|
| 15 |
st.set_page_config(
|
| 16 |
-
page_title="
|
| 17 |
page_icon="📝",
|
| 18 |
layout="wide",
|
| 19 |
initial_sidebar_state="collapsed"
|
|
@@ -109,7 +109,7 @@ def parse_latex_errors(output):
|
|
| 109 |
|
| 110 |
return errors, warnings
|
| 111 |
|
| 112 |
-
# Function to extract document structure
|
| 113 |
def extract_document_structure(latex_code):
|
| 114 |
structure = []
|
| 115 |
|
|
@@ -149,6 +149,48 @@ def extract_document_structure(latex_code):
|
|
| 149 |
|
| 150 |
return structure
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
# Default LaTeX template
|
| 153 |
default_template = r"""\documentclass{article}
|
| 154 |
\usepackage[utf8]{inputenc}
|
|
@@ -158,7 +200,7 @@ default_template = r"""\documentclass{article}
|
|
| 158 |
\usepackage{hyperref}
|
| 159 |
\usepackage{xcolor}
|
| 160 |
|
| 161 |
-
\title{
|
| 162 |
\author{Your Name}
|
| 163 |
\date{\today}
|
| 164 |
|
|
@@ -244,7 +286,7 @@ Your conclusion here.
|
|
| 244 |
\end{document}
|
| 245 |
"""
|
| 246 |
|
| 247 |
-
# Enhanced VSCode-like advanced styling
|
| 248 |
st.markdown("""
|
| 249 |
<style>
|
| 250 |
/* Base theming - VS Code inspired */
|
|
@@ -267,8 +309,8 @@ st.markdown("""
|
|
| 267 |
background-color: #1177bb;
|
| 268 |
}
|
| 269 |
|
| 270 |
-
/* VS Code-like editor */
|
| 271 |
-
.
|
| 272 |
font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important;
|
| 273 |
font-size: 14px !important;
|
| 274 |
line-height: 1.5 !important;
|
|
@@ -279,6 +321,45 @@ st.markdown("""
|
|
| 279 |
border: 1px solid #252526 !important;
|
| 280 |
}
|
| 281 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
/* VS Code-like editor container */
|
| 283 |
.editor-container {
|
| 284 |
background-color: #1e1e1e;
|
|
@@ -553,61 +634,236 @@ st.markdown("""
|
|
| 553 |
.info-value {
|
| 554 |
text-align: right;
|
| 555 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
</style>
|
| 557 |
""", unsafe_allow_html=True)
|
| 558 |
|
| 559 |
-
# VS Code-
|
| 560 |
-
def
|
| 561 |
-
tab_html = f"""
|
| 562 |
-
<div class="tab-bar">
|
| 563 |
-
<div class="tab active">
|
| 564 |
-
<span class="tab-icon">📄</span> {active_tab}
|
| 565 |
-
</div>
|
| 566 |
-
</div>
|
| 567 |
-
"""
|
| 568 |
-
st.markdown(tab_html, unsafe_allow_html=True)
|
| 569 |
-
|
| 570 |
-
# Build a VS Code-like toolbar
|
| 571 |
-
def render_toolbar():
|
| 572 |
toolbar_html = """
|
| 573 |
<div class="toolbar">
|
| 574 |
-
<button class="toolbar-button" title="Bold">
|
| 575 |
<strong>B</strong>
|
| 576 |
</button>
|
| 577 |
-
<button class="toolbar-button" title="Italic">
|
| 578 |
<em>I</em>
|
| 579 |
</button>
|
| 580 |
-
<button class="toolbar-button" title="Math">
|
| 581 |
∑
|
| 582 |
</button>
|
| 583 |
<div class="toolbar-separator"></div>
|
| 584 |
-
<button class="toolbar-button" title="Section">
|
| 585 |
§
|
| 586 |
</button>
|
| 587 |
-
<button class="toolbar-button" title="Subsection">
|
| 588 |
§§
|
| 589 |
</button>
|
| 590 |
<div class="toolbar-separator"></div>
|
| 591 |
-
<button class="toolbar-button" title="Itemize">
|
| 592 |
•
|
| 593 |
</button>
|
| 594 |
-
<button class="toolbar-button" title="Enumerate">
|
| 595 |
1.
|
| 596 |
</button>
|
| 597 |
<div class="toolbar-separator"></div>
|
| 598 |
-
<button class="toolbar-button" title="Equation">
|
| 599 |
=
|
| 600 |
</button>
|
| 601 |
-
<button class="toolbar-button" title="
|
|
|
|
|
|
|
|
|
|
| 602 |
🖼
|
| 603 |
</button>
|
| 604 |
-
<button class="toolbar-button" title="Table">
|
| 605 |
⊞
|
| 606 |
</button>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
"""
|
| 609 |
st.markdown(toolbar_html, unsafe_allow_html=True)
|
| 610 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
# VS Code-style status bar
|
| 612 |
def render_status_bar():
|
| 613 |
status_html = """
|
|
@@ -619,6 +875,42 @@ def render_status_bar():
|
|
| 619 |
"""
|
| 620 |
st.markdown(status_html, unsafe_allow_html=True)
|
| 621 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 622 |
# Render a document outline based on section hierarchy
|
| 623 |
def render_document_outline(structure):
|
| 624 |
if not structure:
|
|
@@ -702,6 +994,7 @@ def render_document_info(latex_code):
|
|
| 702 |
|
| 703 |
# Count equations
|
| 704 |
equation_count = len(re.findall(r'\\begin\{equation', latex_code))
|
|
|
|
| 705 |
|
| 706 |
# Count figures
|
| 707 |
figure_count = len(re.findall(r'\\begin\{figure', latex_code))
|
|
@@ -709,6 +1002,13 @@ def render_document_info(latex_code):
|
|
| 709 |
# Count tables
|
| 710 |
table_count = len(re.findall(r'\\begin\{table', latex_code))
|
| 711 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 712 |
# Render the info panel
|
| 713 |
st.markdown('<div class="document-info">', unsafe_allow_html=True)
|
| 714 |
|
|
@@ -718,8 +1018,12 @@ def render_document_info(latex_code):
|
|
| 718 |
("Character Count", char_count),
|
| 719 |
("Line Count", line_count),
|
| 720 |
("Equations", equation_count),
|
|
|
|
| 721 |
("Figures", figure_count),
|
| 722 |
-
("Tables", table_count)
|
|
|
|
|
|
|
|
|
|
| 723 |
]
|
| 724 |
|
| 725 |
for label, value in info_rows:
|
|
@@ -733,6 +1037,81 @@ def render_document_info(latex_code):
|
|
| 733 |
|
| 734 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 735 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 736 |
# Main application
|
| 737 |
def main():
|
| 738 |
# Initialize session state
|
|
@@ -746,6 +1125,8 @@ def main():
|
|
| 746 |
st.session_state.errors = []
|
| 747 |
if 'warnings' not in st.session_state:
|
| 748 |
st.session_state.warnings = []
|
|
|
|
|
|
|
| 749 |
|
| 750 |
# Check installation status
|
| 751 |
if not is_pdflatex_installed():
|
|
@@ -756,7 +1137,7 @@ def main():
|
|
| 756 |
|
| 757 |
with col1:
|
| 758 |
# Create tabs for main editing area with VS Code style
|
| 759 |
-
editor_tabs = st.tabs(["Editor", "Settings"])
|
| 760 |
|
| 761 |
with editor_tabs[0]:
|
| 762 |
# VS Code-like editor interface
|
|
@@ -765,10 +1146,11 @@ def main():
|
|
| 765 |
# Tab bar
|
| 766 |
render_editor_tabs()
|
| 767 |
|
| 768 |
-
# Toolbar
|
| 769 |
-
|
| 770 |
|
| 771 |
-
#
|
|
|
|
| 772 |
latex_code = st.text_area(
|
| 773 |
"",
|
| 774 |
value=st.session_state.latex_code,
|
|
@@ -776,6 +1158,7 @@ def main():
|
|
| 776 |
key="latex_editor",
|
| 777 |
label_visibility="collapsed"
|
| 778 |
)
|
|
|
|
| 779 |
st.session_state.latex_code = latex_code
|
| 780 |
|
| 781 |
# Status bar
|
|
@@ -804,6 +1187,14 @@ def main():
|
|
| 804 |
st.rerun()
|
| 805 |
|
| 806 |
with editor_tabs[1]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
st.markdown("<h3>LaTeX Settings</h3>", unsafe_allow_html=True)
|
| 808 |
|
| 809 |
st.markdown('<div class="control-panel">', unsafe_allow_html=True)
|
|
@@ -813,6 +1204,7 @@ def main():
|
|
| 813 |
st.checkbox("Auto-compile on save", value=False, key="auto_compile")
|
| 814 |
st.checkbox("Use pdflatex", value=True, key="use_pdflatex")
|
| 815 |
st.checkbox("Enable BibTeX", value=False, key="use_bibtex")
|
|
|
|
| 816 |
|
| 817 |
with col_b:
|
| 818 |
st.selectbox("Document Class",
|
|
@@ -821,12 +1213,18 @@ def main():
|
|
| 821 |
st.selectbox("PDF Engine",
|
| 822 |
["pdflatex", "xelatex", "lualatex"],
|
| 823 |
index=0, key="pdf_engine")
|
|
|
|
|
|
|
|
|
|
| 824 |
|
| 825 |
st.markdown('</div>', unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
| 826 |
|
| 827 |
with col2:
|
| 828 |
# Output tabs with VS Code style
|
| 829 |
-
output_tabs = st.tabs(["Output", "Outline", "
|
| 830 |
|
| 831 |
with output_tabs[0]:
|
| 832 |
# PDF compilation and output
|
|
@@ -920,18 +1318,36 @@ def main():
|
|
| 920 |
structure = extract_document_structure(st.session_state.latex_code)
|
| 921 |
else:
|
| 922 |
structure = []
|
| 923 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 924 |
|
| 925 |
with output_tabs[2]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 926 |
# Problems panel (errors & warnings)
|
| 927 |
if st.session_state.errors or st.session_state.warnings:
|
| 928 |
render_problems(st.session_state.errors, st.session_state.warnings)
|
| 929 |
else:
|
| 930 |
-
st.info("No problems detected")
|
| 931 |
-
|
| 932 |
-
with output_tabs[3]:
|
| 933 |
-
# Document information panel
|
| 934 |
-
render_document_info(st.session_state.latex_code)
|
| 935 |
|
| 936 |
if __name__ == "__main__":
|
| 937 |
main()
|
|
|
|
| 13 |
|
| 14 |
# Set page configuration
|
| 15 |
st.set_page_config(
|
| 16 |
+
page_title="Professional LaTeX Editor",
|
| 17 |
page_icon="📝",
|
| 18 |
layout="wide",
|
| 19 |
initial_sidebar_state="collapsed"
|
|
|
|
| 109 |
|
| 110 |
return errors, warnings
|
| 111 |
|
| 112 |
+
# Function to extract document structure
|
| 113 |
def extract_document_structure(latex_code):
|
| 114 |
structure = []
|
| 115 |
|
|
|
|
| 149 |
|
| 150 |
return structure
|
| 151 |
|
| 152 |
+
# Function to analyze LaTeX packages
|
| 153 |
+
def analyze_packages(latex_code):
|
| 154 |
+
if not isinstance(latex_code, str):
|
| 155 |
+
try:
|
| 156 |
+
latex_code = str(latex_code)
|
| 157 |
+
except:
|
| 158 |
+
return []
|
| 159 |
+
|
| 160 |
+
# Find all package imports
|
| 161 |
+
package_pattern = r'\\usepackage(?:\[.*?\])?\{([^}]+)\}'
|
| 162 |
+
matches = re.finditer(package_pattern, latex_code)
|
| 163 |
+
|
| 164 |
+
packages = []
|
| 165 |
+
for match in matches:
|
| 166 |
+
package_name = match.group(1)
|
| 167 |
+
packages.append(package_name)
|
| 168 |
+
|
| 169 |
+
return packages
|
| 170 |
+
|
| 171 |
+
# Function to find all environments in the document
|
| 172 |
+
def find_environments(latex_code):
|
| 173 |
+
if not isinstance(latex_code, str):
|
| 174 |
+
try:
|
| 175 |
+
latex_code = str(latex_code)
|
| 176 |
+
except:
|
| 177 |
+
return []
|
| 178 |
+
|
| 179 |
+
# Find all environments (begin-end pairs)
|
| 180 |
+
env_pattern = r'\\begin\{([^}]+)\}(.*?)\\end\{\1\}'
|
| 181 |
+
matches = re.finditer(env_pattern, latex_code, re.DOTALL)
|
| 182 |
+
|
| 183 |
+
environments = []
|
| 184 |
+
for match in matches:
|
| 185 |
+
env_name = match.group(1)
|
| 186 |
+
environments.append({
|
| 187 |
+
'name': env_name,
|
| 188 |
+
'position': match.start(),
|
| 189 |
+
'content': match.group(2)
|
| 190 |
+
})
|
| 191 |
+
|
| 192 |
+
return environments
|
| 193 |
+
|
| 194 |
# Default LaTeX template
|
| 195 |
default_template = r"""\documentclass{article}
|
| 196 |
\usepackage[utf8]{inputenc}
|
|
|
|
| 200 |
\usepackage{hyperref}
|
| 201 |
\usepackage{xcolor}
|
| 202 |
|
| 203 |
+
\title{Professional \LaTeX{} Document}
|
| 204 |
\author{Your Name}
|
| 205 |
\date{\today}
|
| 206 |
|
|
|
|
| 286 |
\end{document}
|
| 287 |
"""
|
| 288 |
|
| 289 |
+
# Enhanced VSCode-like advanced styling with syntax highlighting
|
| 290 |
st.markdown("""
|
| 291 |
<style>
|
| 292 |
/* Base theming - VS Code inspired */
|
|
|
|
| 309 |
background-color: #1177bb;
|
| 310 |
}
|
| 311 |
|
| 312 |
+
/* VS Code-like editor - with additional syntax highlighting */
|
| 313 |
+
.editor-area textarea {
|
| 314 |
font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important;
|
| 315 |
font-size: 14px !important;
|
| 316 |
line-height: 1.5 !important;
|
|
|
|
| 321 |
border: 1px solid #252526 !important;
|
| 322 |
}
|
| 323 |
|
| 324 |
+
/* Add a special class for syntax highlighting in the preview */
|
| 325 |
+
.syntax-highlight {
|
| 326 |
+
background-color: #1e1e1e;
|
| 327 |
+
color: #d4d4d4;
|
| 328 |
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
| 329 |
+
font-size: 14px;
|
| 330 |
+
padding: 10px;
|
| 331 |
+
border-radius: 4px;
|
| 332 |
+
border: 1px solid #252526;
|
| 333 |
+
white-space: pre-wrap;
|
| 334 |
+
margin-top: 10px;
|
| 335 |
+
overflow-x: auto;
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
/* Syntax highlighting for different LaTeX elements */
|
| 339 |
+
.syntax-highlight .command {
|
| 340 |
+
color: #569cd6; /* Blue for commands */
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
.syntax-highlight .environment {
|
| 344 |
+
color: #4ec9b0; /* Teal for environments */
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
.syntax-highlight .bracket {
|
| 348 |
+
color: #d4d4d4; /* White for brackets */
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
.syntax-highlight .math {
|
| 352 |
+
color: #c586c0; /* Purple for math */
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
.syntax-highlight .comment {
|
| 356 |
+
color: #6a9955; /* Green for comments */
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
.syntax-highlight .package {
|
| 360 |
+
color: #dcdcaa; /* Yellow for package imports */
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
/* VS Code-like editor container */
|
| 364 |
.editor-container {
|
| 365 |
background-color: #1e1e1e;
|
|
|
|
| 634 |
.info-value {
|
| 635 |
text-align: right;
|
| 636 |
}
|
| 637 |
+
|
| 638 |
+
/* Packages panel */
|
| 639 |
+
.packages-panel {
|
| 640 |
+
background-color: #252526;
|
| 641 |
+
border: 1px solid #2d2d2d;
|
| 642 |
+
border-radius: 4px;
|
| 643 |
+
margin-top: 10px;
|
| 644 |
+
padding: 0;
|
| 645 |
+
}
|
| 646 |
+
|
| 647 |
+
.packages-header {
|
| 648 |
+
background-color: #2d2d2d;
|
| 649 |
+
padding: 5px 10px;
|
| 650 |
+
font-weight: bold;
|
| 651 |
+
font-size: 13px;
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
.package-item {
|
| 655 |
+
padding: 5px 10px;
|
| 656 |
+
border-bottom: 1px solid #2d2d2d;
|
| 657 |
+
display: flex;
|
| 658 |
+
align-items: center;
|
| 659 |
+
}
|
| 660 |
+
|
| 661 |
+
.package-name {
|
| 662 |
+
color: #dcdcaa;
|
| 663 |
+
margin-right: 10px;
|
| 664 |
+
font-family: monospace;
|
| 665 |
+
}
|
| 666 |
+
|
| 667 |
+
/* Environment analyzer */
|
| 668 |
+
.environments-panel {
|
| 669 |
+
background-color: #252526;
|
| 670 |
+
border: 1px solid #2d2d2d;
|
| 671 |
+
border-radius: 4px;
|
| 672 |
+
margin-top: 10px;
|
| 673 |
+
padding: 0;
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
.environments-header {
|
| 677 |
+
background-color: #2d2d2d;
|
| 678 |
+
padding: 5px 10px;
|
| 679 |
+
font-weight: bold;
|
| 680 |
+
font-size: 13px;
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
.environment-item {
|
| 684 |
+
padding: 5px 10px;
|
| 685 |
+
border-bottom: 1px solid #2d2d2d;
|
| 686 |
+
}
|
| 687 |
+
|
| 688 |
+
.environment-name {
|
| 689 |
+
color: #4ec9b0;
|
| 690 |
+
font-family: monospace;
|
| 691 |
+
font-weight: bold;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
/* Syntax highlight code preview */
|
| 695 |
+
.code-preview {
|
| 696 |
+
background-color: #1e1e1e;
|
| 697 |
+
border: 1px solid #2d2d2d;
|
| 698 |
+
border-radius: 4px;
|
| 699 |
+
margin-top: 10px;
|
| 700 |
+
padding: 10px;
|
| 701 |
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
| 702 |
+
font-size: 14px;
|
| 703 |
+
line-height: 1.5;
|
| 704 |
+
overflow-x: auto;
|
| 705 |
+
white-space: pre-wrap;
|
| 706 |
+
}
|
| 707 |
+
|
| 708 |
+
/* Custom select styling */
|
| 709 |
+
.stSelectbox [data-baseweb="select"] {
|
| 710 |
+
background-color: #3c3c3c;
|
| 711 |
+
border-color: #3c3c3c;
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
.stSelectbox [data-baseweb="select"] > div {
|
| 715 |
+
color: #cccccc;
|
| 716 |
+
}
|
| 717 |
+
|
| 718 |
+
/* Keyboard shortcuts display */
|
| 719 |
+
.shortcuts-container {
|
| 720 |
+
background-color: #252526;
|
| 721 |
+
border: 1px solid #2d2d2d;
|
| 722 |
+
border-radius: 4px;
|
| 723 |
+
margin-top: 10px;
|
| 724 |
+
padding: 10px;
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
.shortcut-row {
|
| 728 |
+
display: flex;
|
| 729 |
+
justify-content: space-between;
|
| 730 |
+
margin-bottom: 8px;
|
| 731 |
+
border-bottom: 1px solid #333;
|
| 732 |
+
padding-bottom: 8px;
|
| 733 |
+
}
|
| 734 |
+
|
| 735 |
+
.shortcut-keys {
|
| 736 |
+
background-color: #3c3c3c;
|
| 737 |
+
padding: 2px 8px;
|
| 738 |
+
border-radius: 3px;
|
| 739 |
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
| 740 |
+
font-size: 12px;
|
| 741 |
+
}
|
| 742 |
+
|
| 743 |
+
.shortcut-description {
|
| 744 |
+
color: #cccccc;
|
| 745 |
+
font-size: 13px;
|
| 746 |
+
}
|
| 747 |
</style>
|
| 748 |
""", unsafe_allow_html=True)
|
| 749 |
|
| 750 |
+
# Function to create a functional VS Code-like toolbar
|
| 751 |
+
def render_functional_toolbar():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 752 |
toolbar_html = """
|
| 753 |
<div class="toolbar">
|
| 754 |
+
<button class="toolbar-button" title="Bold" onclick="insertAtCursor('\\\\textbf{', '}')">
|
| 755 |
<strong>B</strong>
|
| 756 |
</button>
|
| 757 |
+
<button class="toolbar-button" title="Italic" onclick="insertAtCursor('\\\\textit{', '}')">
|
| 758 |
<em>I</em>
|
| 759 |
</button>
|
| 760 |
+
<button class="toolbar-button" title="Inline Math" onclick="insertAtCursor('$', '$')">
|
| 761 |
∑
|
| 762 |
</button>
|
| 763 |
<div class="toolbar-separator"></div>
|
| 764 |
+
<button class="toolbar-button" title="Section" onclick="insertAtCursor('\\\\section{', '}')">
|
| 765 |
§
|
| 766 |
</button>
|
| 767 |
+
<button class="toolbar-button" title="Subsection" onclick="insertAtCursor('\\\\subsection{', '}')">
|
| 768 |
§§
|
| 769 |
</button>
|
| 770 |
<div class="toolbar-separator"></div>
|
| 771 |
+
<button class="toolbar-button" title="Itemize" onclick="insertAtCursor('\\\\begin{itemize}\\n \\\\item ', '\\n\\\\end{itemize}')">
|
| 772 |
•
|
| 773 |
</button>
|
| 774 |
+
<button class="toolbar-button" title="Enumerate" onclick="insertAtCursor('\\\\begin{enumerate}\\n \\\\item ', '\\n\\\\end{enumerate}')">
|
| 775 |
1.
|
| 776 |
</button>
|
| 777 |
<div class="toolbar-separator"></div>
|
| 778 |
+
<button class="toolbar-button" title="Equation" onclick="insertAtCursor('\\\\begin{equation}\\n ', '\\n\\\\end{equation}')">
|
| 779 |
=
|
| 780 |
</button>
|
| 781 |
+
<button class="toolbar-button" title="Align" onclick="insertAtCursor('\\\\begin{align}\\n ', '\\n\\\\end{align}')">
|
| 782 |
+
≡
|
| 783 |
+
</button>
|
| 784 |
+
<button class="toolbar-button" title="Figure" onclick="insertAtCursor('\\\\begin{figure}[h]\\n \\\\centering\\n \\\\includegraphics[width=0.8\\\\textwidth]{', '}\\n \\\\caption{Caption}\\n \\\\label{fig:label}\\n\\\\end{figure}')">
|
| 785 |
🖼
|
| 786 |
</button>
|
| 787 |
+
<button class="toolbar-button" title="Table" onclick="insertAtCursor('\\\\begin{table}[h]\\n \\\\centering\\n \\\\begin{tabular}{ccc}\\n ', ' & B & C \\\\\\\\\\n 1 & 2 & 3 \\\\\\\\\\n \\\\end{tabular}\\n \\\\caption{Caption}\\n \\\\label{tab:label}\\n\\\\end{table}')">
|
| 788 |
⊞
|
| 789 |
</button>
|
| 790 |
+
<div class="toolbar-separator"></div>
|
| 791 |
+
<button class="toolbar-button" title="Fraction" onclick="insertAtCursor('\\\\frac{', '}{denominator}')">
|
| 792 |
+
⅟
|
| 793 |
+
</button>
|
| 794 |
+
<button class="toolbar-button" title="Square Root" onclick="insertAtCursor('\\\\sqrt{', '}')">
|
| 795 |
+
√
|
| 796 |
+
</button>
|
| 797 |
+
<button class="toolbar-button" title="Add Package" onclick="insertAtCursor('\\\\usepackage{', '}')">
|
| 798 |
+
📦
|
| 799 |
+
</button>
|
| 800 |
</div>
|
| 801 |
+
|
| 802 |
+
<script>
|
| 803 |
+
function insertAtCursor(before, after) {
|
| 804 |
+
// Find the textarea element
|
| 805 |
+
var textarea = document.querySelector('textarea');
|
| 806 |
+
if (!textarea) return;
|
| 807 |
+
|
| 808 |
+
// Get current cursor position
|
| 809 |
+
var startPos = textarea.selectionStart;
|
| 810 |
+
var endPos = textarea.selectionEnd;
|
| 811 |
+
|
| 812 |
+
// Get text before and after selection
|
| 813 |
+
var textBefore = textarea.value.substring(0, startPos);
|
| 814 |
+
var textSelected = textarea.value.substring(startPos, endPos);
|
| 815 |
+
var textAfter = textarea.value.substring(endPos);
|
| 816 |
+
|
| 817 |
+
// Insert the text
|
| 818 |
+
var newText;
|
| 819 |
+
if (textSelected) {
|
| 820 |
+
// If text is selected, wrap it with before and after
|
| 821 |
+
newText = textBefore + before + textSelected + after + textAfter;
|
| 822 |
+
} else {
|
| 823 |
+
// If no text is selected, just insert before and after
|
| 824 |
+
newText = textBefore + before + after + textAfter;
|
| 825 |
+
// Put cursor between before and after
|
| 826 |
+
var newCursorPos = startPos + before.length;
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
// Update textarea value
|
| 830 |
+
textarea.value = newText;
|
| 831 |
+
|
| 832 |
+
// Set selection range to position cursor appropriately
|
| 833 |
+
if (textSelected) {
|
| 834 |
+
// If text was selected, select the wrapped text
|
| 835 |
+
textarea.setSelectionRange(startPos, endPos + before.length + after.length);
|
| 836 |
+
} else {
|
| 837 |
+
// Otherwise position cursor between before and after
|
| 838 |
+
textarea.setSelectionRange(newCursorPos, newCursorPos);
|
| 839 |
+
}
|
| 840 |
+
|
| 841 |
+
// Focus on textarea
|
| 842 |
+
textarea.focus();
|
| 843 |
+
|
| 844 |
+
// Trigger an input event to update Streamlit
|
| 845 |
+
var event = new Event('input', { bubbles: true });
|
| 846 |
+
textarea.dispatchEvent(event);
|
| 847 |
+
|
| 848 |
+
// Trigger change event to update Streamlit session state
|
| 849 |
+
var changeEvent = new Event('change', { bubbles: true });
|
| 850 |
+
textarea.dispatchEvent(changeEvent);
|
| 851 |
+
}
|
| 852 |
+
</script>
|
| 853 |
"""
|
| 854 |
st.markdown(toolbar_html, unsafe_allow_html=True)
|
| 855 |
|
| 856 |
+
# VS Code-style editor tabs
|
| 857 |
+
def render_editor_tabs(active_tab="document.tex"):
|
| 858 |
+
tab_html = f"""
|
| 859 |
+
<div class="tab-bar">
|
| 860 |
+
<div class="tab active">
|
| 861 |
+
<span class="tab-icon">📄</span> {active_tab}
|
| 862 |
+
</div>
|
| 863 |
+
</div>
|
| 864 |
+
"""
|
| 865 |
+
st.markdown(tab_html, unsafe_allow_html=True)
|
| 866 |
+
|
| 867 |
# VS Code-style status bar
|
| 868 |
def render_status_bar():
|
| 869 |
status_html = """
|
|
|
|
| 875 |
"""
|
| 876 |
st.markdown(status_html, unsafe_allow_html=True)
|
| 877 |
|
| 878 |
+
# Create syntax highlighting for the code preview
|
| 879 |
+
def syntax_highlight_latex(latex_code):
|
| 880 |
+
if not isinstance(latex_code, str):
|
| 881 |
+
try:
|
| 882 |
+
latex_code = str(latex_code)
|
| 883 |
+
except:
|
| 884 |
+
return "<pre>Invalid code</pre>"
|
| 885 |
+
|
| 886 |
+
# Replace special HTML characters
|
| 887 |
+
latex_code = latex_code.replace("&", "&").replace("<", "<").replace(">", ">")
|
| 888 |
+
|
| 889 |
+
# Highlight LaTeX commands (starting with \)
|
| 890 |
+
latex_code = re.sub(r'(\\[a-zA-Z]+)(\{|\[|\s|$)', r'<span class="command">\1</span>\2', latex_code)
|
| 891 |
+
|
| 892 |
+
# Highlight environment tags
|
| 893 |
+
latex_code = re.sub(r'(\\begin\{[^}]+\}|\\end\{[^}]+\})', r'<span class="environment">\1</span>', latex_code)
|
| 894 |
+
|
| 895 |
+
# Highlight math modes
|
| 896 |
+
latex_code = re.sub(r'(\$\$.*?\$\$|\$.*?\$)', r'<span class="math">\1</span>', latex_code)
|
| 897 |
+
|
| 898 |
+
# Highlight comments
|
| 899 |
+
latex_code = re.sub(r'(%.*$)', r'<span class="comment">\1</span>', latex_code)
|
| 900 |
+
|
| 901 |
+
# Highlight package imports
|
| 902 |
+
latex_code = re.sub(r'(\\usepackage(\[.*?\])?\{[^}]+\})', r'<span class="package">\1</span>', latex_code)
|
| 903 |
+
|
| 904 |
+
# Highlight brackets
|
| 905 |
+
latex_code = re.sub(r'(\{|\}|\[|\])', r'<span class="bracket">\1</span>', latex_code)
|
| 906 |
+
|
| 907 |
+
return f'<div class="syntax-highlight">{latex_code}</div>'
|
| 908 |
+
|
| 909 |
+
# Function to display the code with syntax highlighting
|
| 910 |
+
def display_code_with_syntax_highlighting(latex_code):
|
| 911 |
+
highlighted_code = syntax_highlight_latex(latex_code)
|
| 912 |
+
st.markdown(highlighted_code, unsafe_allow_html=True)
|
| 913 |
+
|
| 914 |
# Render a document outline based on section hierarchy
|
| 915 |
def render_document_outline(structure):
|
| 916 |
if not structure:
|
|
|
|
| 994 |
|
| 995 |
# Count equations
|
| 996 |
equation_count = len(re.findall(r'\\begin\{equation', latex_code))
|
| 997 |
+
align_count = len(re.findall(r'\\begin\{align', latex_code))
|
| 998 |
|
| 999 |
# Count figures
|
| 1000 |
figure_count = len(re.findall(r'\\begin\{figure', latex_code))
|
|
|
|
| 1002 |
# Count tables
|
| 1003 |
table_count = len(re.findall(r'\\begin\{table', latex_code))
|
| 1004 |
|
| 1005 |
+
# Count custom command definitions
|
| 1006 |
+
command_count = len(re.findall(r'\\newcommand', latex_code))
|
| 1007 |
+
|
| 1008 |
+
# Count references
|
| 1009 |
+
ref_count = len(re.findall(r'\\ref\{', latex_code))
|
| 1010 |
+
cite_count = len(re.findall(r'\\cite\{', latex_code))
|
| 1011 |
+
|
| 1012 |
# Render the info panel
|
| 1013 |
st.markdown('<div class="document-info">', unsafe_allow_html=True)
|
| 1014 |
|
|
|
|
| 1018 |
("Character Count", char_count),
|
| 1019 |
("Line Count", line_count),
|
| 1020 |
("Equations", equation_count),
|
| 1021 |
+
("Align Environments", align_count),
|
| 1022 |
("Figures", figure_count),
|
| 1023 |
+
("Tables", table_count),
|
| 1024 |
+
("Custom Commands", command_count),
|
| 1025 |
+
("References", ref_count),
|
| 1026 |
+
("Citations", cite_count)
|
| 1027 |
]
|
| 1028 |
|
| 1029 |
for label, value in info_rows:
|
|
|
|
| 1037 |
|
| 1038 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 1039 |
|
| 1040 |
+
# Display the packages used in the document
|
| 1041 |
+
def render_packages_panel(packages):
|
| 1042 |
+
if not packages:
|
| 1043 |
+
return
|
| 1044 |
+
|
| 1045 |
+
st.markdown('<div class="packages-panel">', unsafe_allow_html=True)
|
| 1046 |
+
st.markdown('<div class="packages-header">Imported Packages</div>', unsafe_allow_html=True)
|
| 1047 |
+
|
| 1048 |
+
for package in packages:
|
| 1049 |
+
st.markdown(
|
| 1050 |
+
f'<div class="package-item">'
|
| 1051 |
+
f'<span class="package-name">\\usepackage{{{package}}}</span>'
|
| 1052 |
+
f'</div>',
|
| 1053 |
+
unsafe_allow_html=True
|
| 1054 |
+
)
|
| 1055 |
+
|
| 1056 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
| 1057 |
+
|
| 1058 |
+
# Display environments in the document
|
| 1059 |
+
def render_environments_panel(environments):
|
| 1060 |
+
if not environments:
|
| 1061 |
+
return
|
| 1062 |
+
|
| 1063 |
+
st.markdown('<div class="environments-panel">', unsafe_allow_html=True)
|
| 1064 |
+
st.markdown('<div class="environments-header">Environments</div>', unsafe_allow_html=True)
|
| 1065 |
+
|
| 1066 |
+
# Count environment types
|
| 1067 |
+
env_counts = {}
|
| 1068 |
+
for env in environments:
|
| 1069 |
+
env_name = env['name']
|
| 1070 |
+
if env_name in env_counts:
|
| 1071 |
+
env_counts[env_name] += 1
|
| 1072 |
+
else:
|
| 1073 |
+
env_counts[env_name] = 1
|
| 1074 |
+
|
| 1075 |
+
# Display counts
|
| 1076 |
+
for env_name, count in env_counts.items():
|
| 1077 |
+
st.markdown(
|
| 1078 |
+
f'<div class="environment-item">'
|
| 1079 |
+
f'<span class="environment-name">\\begin{{{env_name}}}</span> - {count} instances'
|
| 1080 |
+
f'</div>',
|
| 1081 |
+
unsafe_allow_html=True
|
| 1082 |
+
)
|
| 1083 |
+
|
| 1084 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
| 1085 |
+
|
| 1086 |
+
# Display keyboard shortcuts
|
| 1087 |
+
def render_keyboard_shortcuts():
|
| 1088 |
+
st.markdown('<div class="shortcuts-container">', unsafe_allow_html=True)
|
| 1089 |
+
st.markdown('<div style="font-weight:bold;margin-bottom:10px;">Keyboard Shortcuts</div>', unsafe_allow_html=True)
|
| 1090 |
+
|
| 1091 |
+
shortcuts = [
|
| 1092 |
+
("Ctrl+B", "Insert bold text"),
|
| 1093 |
+
("Ctrl+I", "Insert italic text"),
|
| 1094 |
+
("Ctrl+M", "Insert inline math"),
|
| 1095 |
+
("Ctrl+E", "Insert equation"),
|
| 1096 |
+
("Ctrl+L", "Insert list"),
|
| 1097 |
+
("Ctrl+F", "Insert fraction"),
|
| 1098 |
+
("F5", "Compile document"),
|
| 1099 |
+
("Ctrl+S", "Save document"),
|
| 1100 |
+
("Ctrl+/", "Toggle comment"),
|
| 1101 |
+
("Tab", "Indent")
|
| 1102 |
+
]
|
| 1103 |
+
|
| 1104 |
+
for key, description in shortcuts:
|
| 1105 |
+
st.markdown(
|
| 1106 |
+
f'<div class="shortcut-row">'
|
| 1107 |
+
f'<span class="shortcut-keys">{key}</span>'
|
| 1108 |
+
f'<span class="shortcut-description">{description}</span>'
|
| 1109 |
+
f'</div>',
|
| 1110 |
+
unsafe_allow_html=True
|
| 1111 |
+
)
|
| 1112 |
+
|
| 1113 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
| 1114 |
+
|
| 1115 |
# Main application
|
| 1116 |
def main():
|
| 1117 |
# Initialize session state
|
|
|
|
| 1125 |
st.session_state.errors = []
|
| 1126 |
if 'warnings' not in st.session_state:
|
| 1127 |
st.session_state.warnings = []
|
| 1128 |
+
if 'show_syntax_highlight' not in st.session_state:
|
| 1129 |
+
st.session_state.show_syntax_highlight = False
|
| 1130 |
|
| 1131 |
# Check installation status
|
| 1132 |
if not is_pdflatex_installed():
|
|
|
|
| 1137 |
|
| 1138 |
with col1:
|
| 1139 |
# Create tabs for main editing area with VS Code style
|
| 1140 |
+
editor_tabs = st.tabs(["Editor", "Preview", "Settings"])
|
| 1141 |
|
| 1142 |
with editor_tabs[0]:
|
| 1143 |
# VS Code-like editor interface
|
|
|
|
| 1146 |
# Tab bar
|
| 1147 |
render_editor_tabs()
|
| 1148 |
|
| 1149 |
+
# Toolbar with functional buttons
|
| 1150 |
+
render_functional_toolbar()
|
| 1151 |
|
| 1152 |
+
# Editor with VS Code styling
|
| 1153 |
+
st.markdown('<div class="editor-area">', unsafe_allow_html=True)
|
| 1154 |
latex_code = st.text_area(
|
| 1155 |
"",
|
| 1156 |
value=st.session_state.latex_code,
|
|
|
|
| 1158 |
key="latex_editor",
|
| 1159 |
label_visibility="collapsed"
|
| 1160 |
)
|
| 1161 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
| 1162 |
st.session_state.latex_code = latex_code
|
| 1163 |
|
| 1164 |
# Status bar
|
|
|
|
| 1187 |
st.rerun()
|
| 1188 |
|
| 1189 |
with editor_tabs[1]:
|
| 1190 |
+
# Show syntax highlighted preview
|
| 1191 |
+
st.markdown("<h3>Syntax Highlighted Preview</h3>", unsafe_allow_html=True)
|
| 1192 |
+
st.markdown("<p>This shows your LaTeX code with syntax highlighting</p>", unsafe_allow_html=True)
|
| 1193 |
+
|
| 1194 |
+
# Display code with syntax highlighting
|
| 1195 |
+
display_code_with_syntax_highlighting(st.session_state.latex_code)
|
| 1196 |
+
|
| 1197 |
+
with editor_tabs[2]:
|
| 1198 |
st.markdown("<h3>LaTeX Settings</h3>", unsafe_allow_html=True)
|
| 1199 |
|
| 1200 |
st.markdown('<div class="control-panel">', unsafe_allow_html=True)
|
|
|
|
| 1204 |
st.checkbox("Auto-compile on save", value=False, key="auto_compile")
|
| 1205 |
st.checkbox("Use pdflatex", value=True, key="use_pdflatex")
|
| 1206 |
st.checkbox("Enable BibTeX", value=False, key="use_bibtex")
|
| 1207 |
+
st.checkbox("Show line numbers", value=True, key="show_line_numbers")
|
| 1208 |
|
| 1209 |
with col_b:
|
| 1210 |
st.selectbox("Document Class",
|
|
|
|
| 1213 |
st.selectbox("PDF Engine",
|
| 1214 |
["pdflatex", "xelatex", "lualatex"],
|
| 1215 |
index=0, key="pdf_engine")
|
| 1216 |
+
st.selectbox("Editor Theme",
|
| 1217 |
+
["Dark", "Light", "High Contrast"],
|
| 1218 |
+
index=0, key="editor_theme")
|
| 1219 |
|
| 1220 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 1221 |
+
|
| 1222 |
+
# Display keyboard shortcuts
|
| 1223 |
+
render_keyboard_shortcuts()
|
| 1224 |
|
| 1225 |
with col2:
|
| 1226 |
# Output tabs with VS Code style
|
| 1227 |
+
output_tabs = st.tabs(["Output", "Outline", "Analysis", "Problems"])
|
| 1228 |
|
| 1229 |
with output_tabs[0]:
|
| 1230 |
# PDF compilation and output
|
|
|
|
| 1318 |
structure = extract_document_structure(st.session_state.latex_code)
|
| 1319 |
else:
|
| 1320 |
structure = []
|
| 1321 |
+
|
| 1322 |
+
if structure:
|
| 1323 |
+
render_document_outline(structure)
|
| 1324 |
+
else:
|
| 1325 |
+
st.info("No document structure detected. Add sections using the toolbar.")
|
| 1326 |
|
| 1327 |
with output_tabs[2]:
|
| 1328 |
+
# Document analysis features
|
| 1329 |
+
|
| 1330 |
+
# Document info
|
| 1331 |
+
render_document_info(st.session_state.latex_code)
|
| 1332 |
+
|
| 1333 |
+
# Package analysis
|
| 1334 |
+
packages = analyze_packages(st.session_state.latex_code)
|
| 1335 |
+
if packages:
|
| 1336 |
+
render_packages_panel(packages)
|
| 1337 |
+
else:
|
| 1338 |
+
st.info("No packages detected. Add packages using \\usepackage{}.")
|
| 1339 |
+
|
| 1340 |
+
# Environment analysis
|
| 1341 |
+
environments = find_environments(st.session_state.latex_code)
|
| 1342 |
+
if environments:
|
| 1343 |
+
render_environments_panel(environments)
|
| 1344 |
+
|
| 1345 |
+
with output_tabs[3]:
|
| 1346 |
# Problems panel (errors & warnings)
|
| 1347 |
if st.session_state.errors or st.session_state.warnings:
|
| 1348 |
render_problems(st.session_state.errors, st.session_state.warnings)
|
| 1349 |
else:
|
| 1350 |
+
st.info("No problems detected in the document.")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1351 |
|
| 1352 |
if __name__ == "__main__":
|
| 1353 |
main()
|