
Latex Formatting
- 1.6k installs
- 255 repo stars
- Updated February 27, 2026
- lingzhi227/agent-research-skills
latex-formatting is an agent skill that handle latex formatting, templates, and styling for academic papers. set up conference templates (icml, iclr, neurips, aaai, acl), fix formatting issues, manage packages, and ensur
About
latex-formatting is an agent skill from lingzhi227/agent-research-skills that handle latex formatting, templates, and styling for academic papers. set up conference templates (icml, iclr, neurips, aaai, acl), fix formatting issues, manage packages, and ensure venue-specific com. # LaTeX Formatting Set up and manage LaTeX formatting for academic papers. ## Input - `$0` — Action: `setup`, `fix`, `check` - `$1` — Venue name (for `setup`) or `.tex` file path (for `fix`/`check`) ## Scripts ### Pre-submission format checker ```bash python ~/.claude/skills/latex-formatting/scripts/latex_checker.py paper/main.tex --venue neur Developers invoke latex-formatting during idea/research work for documentation tasks. The skill documents triggers, prerequisites, and step-by-step workflows grounded in SKILL.md. Compatible with Claude Code, Cursor, and Codex agent runtimes that load marketplace skills. Review the Security Audits panel on this listing before installing in production environments.
- Set up and manage LaTeX formatting for academic papers.
- `$0` — Action: `setup`, `fix`, `check`
- `$1` — Venue name (for `setup`) or `.tex` file path (for `fix`/`check`)
- Pre-submission format checker
- python ~/.claude/skills/latex-formatting/scripts/latex_checker.py paper/main.tex --venue neurips --check-anon
Latex Formatting by the numbers
- 1,640 all-time installs (skills.sh)
- +50 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #200 of 1,879 Documentation skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
latex-formatting capabilities & compatibility
- Capabilities
- set up and manage latex formatting for academic · `$0` — action: `setup`, `fix`, `check` · `$1` — venue name (for `setup`) or `.tex` file p · pre submission format checker · python ~/.claude/skills/latex formatting/scripts
- Use cases
- orchestration
What latex-formatting says it does
Set up and manage LaTeX formatting for academic papers.
- `$1` — Venue name (for `setup`) or `.tex` file path (for `fix`/`check`)
python ~/.claude/skills/latex-formatting/scripts/latex_checker.py paper/main.tex --venue neurips --check-anon
npx skills add https://github.com/lingzhi227/agent-research-skills --skill latex-formattingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 255 |
| Security audit | 2 / 3 scanners passed |
| Last updated | February 27, 2026 |
| Repository | lingzhi227/agent-research-skills ↗ |
What it does
Handle LaTeX formatting, templates, and styling for academic papers. Set up conference templates (ICML, ICLR, NeurIPS, AAAI, ACL), fix formatting issues, manage packages, and ensure venue-specific com
Who is it for?
Developers working on documentation during idea tasks.
Skip if: Tasks outside Documentation scope described in SKILL.md.
When should I use this skill?
Handle LaTeX formatting, templates, and styling for academic papers. Set up conference templates (ICML, ICLR, NeurIPS, AAAI, ACL), fix formatting issues, manage packages, and ensure venue-specific com
What you get
Completed documentation workflow aligned with SKILL.md steps.
- main.tex project
- references.bib
- venue-styled section files
By the numbers
- Covers 8 conference and arXiv venue templates
- NeurIPS and ICLR submissions target 9-page single-column limits
- ICBINB template uses a 4-page two-column limit
Files
LaTeX Formatting
Set up and manage LaTeX formatting for academic papers.
Input
$0— Action:setup,fix,check$1— Venue name (forsetup) or.texfile path (forfix/check)
Scripts
Pre-submission format checker
python ~/.claude/skills/latex-formatting/scripts/latex_checker.py paper/main.tex --venue neurips --check-anonChecks: word count, required sections, TODO markers, anonymization, mismatched environments, content stats.
Validate citations and references
python ~/.claude/skills/citation-management/scripts/validate_citations.py \
--tex paper/main.tex --bib paper/references.bib --check-figuresClean LaTeX text (fix special characters)
python ~/.claude/skills/latex-formatting/scripts/clean_latex.py \
--input paper/main.tex --output paper/main_cleaned.texReplaces special/non-UTF8 characters with LaTeX equivalents, skips math environments. Key flags: --dry-run, --tables-only
Auto-fix after checking
python ~/.claude/skills/latex-formatting/scripts/latex_checker.py paper/main.tex --venue neurips --fixRuns checks then applies clean_latex.py fixes, writing to main_fixed.tex.
References
- Venue specs, project structure, packages, commands:
~/.claude/skills/latex-formatting/references/venue-templates.md
Action: setup
Create the project directory structure and main.tex for the specified venue. Use the template from references/venue-templates.md.
Action: fix
Fix common LaTeX issues: unescaped special chars, math mode errors, float placement, overfull/underfull boxes, cross-reference issues.
Action: check
Run latex_checker.py for pre-submission validation. Check page count, anonymization, required sections, TODO markers.
Related Skills
- Upstream: paper-writing-section, table-generation
- Downstream: paper-compilation
- See also: citation-management
Conference Venue Templates Reference
Venue Specifications
| Venue | Pages | Columns | Style | Anonymous | Refs Extra |
|---|---|---|---|---|---|
| NeurIPS | 9 | 1 | neurips_2025.sty | Yes | Yes |
| ICML | 8 | 2 | icml2025.sty | Yes | Yes |
| ICLR | 9 | 1 | iclr2025_conference.sty | Yes | Yes |
| AAAI | 7+1 | 2 | aaai25.sty | Yes | 1 extra |
| ACL/EMNLP | 8 | 2 | acl.sty | Yes | Yes |
| CVPR/ICCV | 8 | 2 | cvpr.sty | Yes | Yes |
| ICBINB | 4 | 2 | icbinb.sty | Yes | Yes |
| arXiv | ∞ | 1 | article.cls | No | N/A |
Standard Project Structure
paper/
├── main.tex
├── references.bib
├── sections/
│ ├── abstract.tex
│ ├── introduction.tex
│ ├── related_work.tex
│ ├── background.tex
│ ├── methods.tex
│ ├── experiments.tex
│ ├── results.tex
│ └── conclusion.tex
├── figures/
├── tables/
└── appendix/
└── appendix.texEssential Packages (always include)
\usepackage{amsmath,amssymb,amsthm} % Math
\usepackage{graphicx} % Figures
\usepackage{booktabs} % Professional tables
\usepackage{hyperref} % Clickable references
\usepackage{algorithm,algpseudocode} % Algorithms
\usepackage{subcaption} % Subfigures
\usepackage{xcolor} % Colors
\usepackage{enumitem} % List customization
\usepackage{multirow} % Table multi-row
\usepackage{cleveref} % Smart references
\usepackage{microtype} % Better typographyCommon Custom Commands
\DeclareMathOperator*{\argmin}{arg\,min}
\DeclareMathOperator*{\argmax}{arg\,max}
\newcommand{\norm}[1]{\left\| #1 \right\|}
\newcommand{\abs}[1]{\left| #1 \right|}
\newcommand{\ie}{\textit{i.e.}}
\newcommand{\eg}{\textit{e.g.}}
\newcommand{\etal}{\textit{et al.}}
% Remove before submission:
\newcommand{\todo}[1]{\textcolor{red}{[TODO: #1]}}Anonymization Checklist
- [ ] No author names in
\author{} - [ ] No "our previous work [X]" or "we previously showed"
- [ ] No GitHub/institutional URLs
- [ ] No acknowledgments section
- [ ] No grant numbers or funding info
- [ ] Supplementary material is anonymous too
#!/usr/bin/env python3
"""Clean and sanitize LaTeX text for compilation.
Replaces special characters with LaTeX equivalents, handles math/text
mode separation, fixes non-UTF8 characters, and cleans table content.
Extracted from data-to-paper. Stdlib-only (uses re instead of regex).
Usage:
python clean_latex.py --input draft.tex --output cleaned.tex
python clean_latex.py --input draft.tex --dry-run
python clean_latex.py --input draft.tex --output cleaned.tex --tables-only
"""
import argparse
import os
import re
import sys
# Special characters to LaTeX escape sequences
CHARS = {
'&': r'\&',
'%': r'\%',
'#': r'\#',
'_': r'\_',
'^': r'\textasciicircum{}',
'<': r'$<$',
'>': r'$>$',
'\u2264': r'$\leq$', # ≤
'\u2265': r'$\geq$', # ≥
'\u2260': r'$\neq$', # ≠
'\u00b1': r'$\pm$', # ±
'\u00d7': r'$\times$', # ×
'\u00f7': r'$\div$', # ÷
'\u00b0': r'$^{\circ}$', # °
'\u221e': r'$\infty$', # ∞
'\u221a': r'$\sqrt{}$', # √
'\u2211': r'$\sum$', # ∑
'\u220f': r'$\prod$', # ∏
'|': r'\textbar{}',
'\u2208': r'$\in$', # ∈
'\u2209': r'$\notin$', # ∉
'\u2200': r'$\forall$', # ∀
'\u2203': r'$\exists$', # ∃
'\u2205': r'$\emptyset$', # ∅
'\u200b': '', # zero width space
'\u202f': ' ', # narrow no-break space
}
# Non-UTF8 characters to LaTeX-safe replacements
NON_UTF8_CHARS = {
'\u2013': '--', # –
'\u2019': "'", # '
'\u2018': "`", # '
'\u201c': "``", # "
'\u201d': "''", # "
'\u00b2': r'$^2$', # ²
'\u00b3': r'$^3$', # ³
'\u00bc': r'$\frac{1}{4}$', # ¼
'\u00bd': r'$\frac{1}{2}$', # ½
'\u00be': r'$\frac{3}{4}$', # ¾
'\u2206': r'$\Delta$', # ∆
'\u2207': r'$\nabla$', # ∇
'\u2202': r'$\partial$', # ∂
'\u2014': '---', # —
'\u2026': r'\ldots{}', # …
'\u00e9': r"\'e", # é
'\u00e8': r"\`e", # è
'\u00fc': r'\"u', # ü
'\u00f6': r'\"o', # ö
'\u00e4': r'\"a', # ä
}
TABLE_CHARS = {
'>': r'$>$',
'<': r'$<$',
'=': r'$=$',
'|': r'\textbar{}',
}
# Simplified math pattern (stdlib re, no recursion)
# Matches: $...$, $$...$$, \(...\), \[...\], \begin{equation}...\end{equation},
# \begin{align}...\end{align}, \begin{figure}...\end{figure}
MATH_ENVS = [
(r'\$\$', r'\$\$'), # $$...$$
(r'(?<!\$)\$(?!\$)', r'(?<!\$)\$(?!\$)'), # $...$
(r'\\\(', r'\\\)'), # \(...\)
(r'\\\[', r'\\\]'), # \[...\]
]
LATEX_ENV_NAMES = [
'equation', 'equation*', 'align', 'align*', 'gather', 'gather*',
'math', 'displaymath', 'figure', 'figure*', 'lstlisting',
'tabular', 'tabular*', 'array',
]
SKIP_COMMANDS = [r'\\ref\{[^}]*\}', r'\\label\{[^}]*\}', r'\\autoref\{[^}]*\}',
r'\\cite[a-z]*\{[^}]*\}', r'\\url\{[^}]*\}', r'\\href\{[^}]*\}\{[^}]*\}']
def build_skip_pattern() -> re.Pattern:
"""Build a combined regex pattern for all math/skip regions."""
patterns = []
# Comments (% to end of line, unless escaped)
patterns.append(r'(?<!\\)%[^\n]*')
# Command definitions (contain # for parameters)
patterns.append(r'\\(?:(?:re)?newcommand|providecommand|DeclareMathOperator)\*?'
r'(?:\{[^}]*\}|\[[^\]]*\])*\{[^}]*\}')
patterns.append(r'\\def\\[a-zA-Z@]+[^{]*\{[^}]*\}')
# Dollar signs
patterns.append(r'\$\$.*?\$\$')
patterns.append(r'(?<!\$)\$(?!\$).*?(?<!\$)\$(?!\$)')
# Escaped delimiters
patterns.append(r'\\\(.*?\\\)')
patterns.append(r'\\\[.*?\\\]')
# Named environments
for env in LATEX_ENV_NAMES:
esc = re.escape(env)
patterns.append(rf'\\begin\{{{esc}\}}.*?\\end\{{{esc}\}}')
# Skip commands
patterns.extend(SKIP_COMMANDS)
return re.compile('|'.join(patterns), re.DOTALL)
SKIP_RE = build_skip_pattern()
def replace_special_latex_chars(text: str) -> str:
"""Replace special characters in text (non-math) with LaTeX equivalents."""
chars_pattern = '|'.join(re.escape(c) for c in CHARS.keys())
pattern = re.compile(rf'(?<!\\)({chars_pattern})')
return pattern.sub(lambda m: CHARS[m.group(1)], text)
def replace_non_utf8_chars(text: str) -> str:
"""Replace non-UTF8 characters with LaTeX-safe equivalents."""
for char, replacement in NON_UTF8_CHARS.items():
text = text.replace(char, replacement)
return text
def process_latex_text_and_math(text: str, process_text=None, process_math=None) -> str:
"""Process text and math regions separately.
Applies process_text to non-math regions and process_math to math regions.
"""
if process_text is None:
process_text = replace_special_latex_chars
if process_math is None:
process_math = lambda x: x
result = []
last_end = 0
for match in SKIP_RE.finditer(text):
# Process non-math text before this match
non_math = text[last_end:match.start()]
result.append(process_text(non_math))
# Keep math region as-is (or apply process_math)
result.append(process_math(match.group()))
last_end = match.end()
# Process remaining text after last match
result.append(process_text(text[last_end:]))
return "".join(result)
def escape_table_chars(text: str) -> str:
"""Escape special characters in table cells."""
pattern = re.compile('|'.join(re.escape(k) for k in TABLE_CHARS.keys()))
return pattern.sub(lambda m: TABLE_CHARS[m.group()], text)
def escape_special_chars_in_table(table: str,
begin: str = r'\begin{tabular}',
end: str = r'\end{tabular}') -> str:
"""Apply character escaping to the tabular content of a LaTeX table."""
if begin not in table:
return table
if end not in table:
return table
before, rest = table.split(begin, 1)
tabular, after = rest.split(end, 1)
tabular = process_latex_text_and_math(tabular, escape_table_chars)
return before + begin + tabular + end + after
def clean_latex_file(content: str, tables_only: bool = False) -> str:
"""Clean a full LaTeX file content."""
if tables_only:
# Only clean table environments
parts = re.split(r'(\\begin\{tabular\}.*?\\end\{tabular\})', content, flags=re.DOTALL)
result = []
for part in parts:
if part.startswith(r'\begin{tabular}'):
result.append(escape_special_chars_in_table(part))
else:
result.append(part)
return ''.join(result)
# Full cleaning
content = replace_non_utf8_chars(content)
content = process_latex_text_and_math(content)
return content
def main():
parser = argparse.ArgumentParser(description="Clean and sanitize LaTeX text")
parser.add_argument("--input", required=True, help="Input .tex file")
parser.add_argument("--output", "-o", help="Output .tex file (default: stdout)")
parser.add_argument("--dry-run", action="store_true", help="Show changes without writing")
parser.add_argument("--tables-only", action="store_true", help="Only clean table environments")
args = parser.parse_args()
with open(args.input, encoding="utf-8", errors="replace") as f:
content = f.read()
cleaned = clean_latex_file(content, tables_only=args.tables_only)
if args.dry_run:
# Show diff summary
orig_lines = content.splitlines()
new_lines = cleaned.splitlines()
changes = 0
for i, (old, new) in enumerate(zip(orig_lines, new_lines)):
if old != new:
changes += 1
if changes <= 20:
print(f"Line {i+1}:")
print(f" - {old[:100]}")
print(f" + {new[:100]}")
if changes > 20:
print(f"... and {changes - 20} more changes")
print(f"\nTotal lines changed: {changes}")
return
if args.output:
with open(args.output, "w", encoding="utf-8") as f:
f.write(cleaned)
print(f"Cleaned file written to {args.output}", file=sys.stderr)
else:
sys.stdout.write(cleaned)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Pre-submission LaTeX format checker.
Validates a LaTeX paper against common venue requirements:
page count, anonymization, required sections, formatting issues.
Self-contained: uses only stdlib.
Usage:
python latex_checker.py paper/main.tex
python latex_checker.py paper/main.tex --venue neurips --page-limit 9
python latex_checker.py paper/main.tex --check-anon
"""
import argparse
import os
import re
import sys
VENUE_LIMITS = {
"neurips": {"pages": 9, "columns": 1, "anonymous": True},
"icml": {"pages": 8, "columns": 2, "anonymous": True},
"iclr": {"pages": 9, "columns": 1, "anonymous": True},
"aaai": {"pages": 7, "columns": 2, "anonymous": True},
"acl": {"pages": 8, "columns": 2, "anonymous": True},
"emnlp": {"pages": 8, "columns": 2, "anonymous": True},
"cvpr": {"pages": 8, "columns": 2, "anonymous": True},
"icbinb": {"pages": 4, "columns": 2, "anonymous": True},
"arxiv": {"pages": None, "columns": None, "anonymous": False},
}
REQUIRED_SECTIONS = [
"abstract", "introduction",
]
EXPECTED_SECTIONS = [
"abstract", "introduction", "related work",
"method", "experiment", "result", "conclusion",
]
def load_tex(path: str) -> str:
"""Load tex file, following \\input{} directives."""
with open(path, encoding="utf-8", errors="replace") as f:
content = f.read()
# Resolve \input{file} directives
base_dir = os.path.dirname(path)
def resolve_input(match):
fname = match.group(1)
if not fname.endswith(".tex"):
fname += ".tex"
fpath = os.path.join(base_dir, fname)
if os.path.exists(fpath):
with open(fpath, encoding="utf-8", errors="replace") as f:
return f.read()
return match.group(0)
content = re.sub(r"\\input\{([^}]+)\}", resolve_input, content)
return content
def estimate_word_count(tex_content: str) -> int:
"""Rough word count excluding LaTeX commands, math, and comments."""
# Remove comments
text = re.sub(r"%.*$", "", tex_content, flags=re.MULTILINE)
# Remove math environments
text = re.sub(r"\$\$.*?\$\$", "", text, flags=re.DOTALL)
text = re.sub(r"\$.*?\$", "", text)
text = re.sub(r"\\begin\{(?:equation|align|gather|math).*?\}.*?\\end\{(?:equation|align|gather|math).*?\}", "", text, flags=re.DOTALL)
# Remove LaTeX commands
text = re.sub(r"\\[a-zA-Z]+(?:\[.*?\])?\{([^}]*)\}", r"\1", text)
text = re.sub(r"\\[a-zA-Z]+", "", text)
# Remove braces and special chars
text = re.sub(r"[{}\\]", "", text)
words = text.split()
return len(words)
def check_anonymization(tex_content: str) -> list[str]:
"""Check for anonymization violations."""
issues = []
# Check for author names in common locations
author_match = re.search(r"\\author\{([^}]+)\}", tex_content)
if author_match:
author_text = author_match.group(1)
if "anonymous" not in author_text.lower() and "author" not in author_text.lower():
issues.append(f"Author field contains names: {author_text[:50]}...")
# Check for self-citations like "our previous work [1]"
self_cite_patterns = [
r"our (?:previous|prior|earlier|recent) (?:work|paper|study)",
r"we (?:previously|earlier|recently) (?:proposed|showed|demonstrated)",
r"in our (?:previous|prior|earlier) (?:work|paper)",
]
for pat in self_cite_patterns:
if re.search(pat, tex_content, re.IGNORECASE):
issues.append(f"Possible self-citation: pattern '{pat}' found")
# Check for GitHub/institutional links
url_patterns = [
(r"github\.com/[a-zA-Z0-9_-]+/", "GitHub link found"),
(r"gitlab\.com/[a-zA-Z0-9_-]+/", "GitLab link found"),
(r"\\url\{https?://(?!arxiv|doi|paperswithcode)[^}]+\}", "Non-anonymous URL found"),
]
for pat, msg in url_patterns:
match = re.search(pat, tex_content)
if match:
issues.append(f"{msg}: {match.group(0)[:60]}")
# Check for acknowledgments (should be removed for review)
if re.search(r"\\section\*?\{Acknowledgment", tex_content, re.IGNORECASE):
issues.append("Acknowledgments section present (remove for anonymous submission)")
return issues
def check_required_sections(tex_content: str) -> tuple[list[str], list[str]]:
"""Check for required and expected sections."""
sections = re.findall(r"\\section\*?\{([^}]+)\}", tex_content)
section_names_lower = [s.lower().strip() for s in sections]
# Check abstract
has_abstract = bool(re.search(r"\\begin\{abstract\}", tex_content))
missing_required = []
if not has_abstract and "abstract" not in section_names_lower:
missing_required.append("Abstract")
if not any("introduction" in s for s in section_names_lower):
missing_required.append("Introduction")
missing_expected = []
for expected in EXPECTED_SECTIONS:
if expected == "abstract":
if not has_abstract:
missing_expected.append("Abstract")
elif not any(expected in s for s in section_names_lower):
missing_expected.append(expected.title())
return missing_required, missing_expected
def check_todos(tex_content: str) -> list[str]:
"""Find remaining TODO/TBD/FIXME markers."""
issues = []
patterns = [r"TODO", r"TBD", r"FIXME", r"XXX", r"HACK"]
for pat in patterns:
matches = list(re.finditer(pat, tex_content, re.IGNORECASE))
for m in matches:
# Get surrounding context
start = max(0, m.start() - 30)
end = min(len(tex_content), m.end() + 30)
context = tex_content[start:end].replace("\n", " ").strip()
# Skip if in a comment
line_start = tex_content.rfind("\n", 0, m.start()) + 1
line = tex_content[line_start:m.end()]
if "%" in line[:line.index(pat) if pat in line else 0]:
continue
issues.append(f"{pat} found: ...{context}...")
return issues
def main():
parser = argparse.ArgumentParser(description="Pre-submission LaTeX checker")
parser.add_argument("tex_file", help="Main .tex file")
parser.add_argument("--venue", choices=list(VENUE_LIMITS.keys()), help="Target venue")
parser.add_argument("--page-limit", type=int, help="Override page limit")
parser.add_argument("--check-anon", action="store_true", help="Check anonymization")
parser.add_argument("--fix", action="store_true", help="Apply fixes using clean_latex.py")
args = parser.parse_args()
tex_content = load_tex(args.tex_file)
issues_total = 0
print(f"Checking: {args.tex_file}")
if args.venue:
print(f"Venue: {args.venue.upper()}")
print()
# Word count
word_count = estimate_word_count(tex_content)
print(f"Estimated word count: {word_count}")
# Section count
sections = re.findall(r"\\section\*?\{([^}]+)\}", tex_content)
print(f"Sections: {len(sections)}")
for s in sections:
print(f" - {s}")
print()
# Required sections
missing_req, missing_exp = check_required_sections(tex_content)
if missing_req:
print(f"MISSING REQUIRED SECTIONS:")
for s in missing_req:
print(f" - {s}")
issues_total += len(missing_req)
if missing_exp:
print(f"MISSING EXPECTED SECTIONS:")
for s in missing_exp:
print(f" - {s}")
print()
# TODOs
todos = check_todos(tex_content)
if todos:
print(f"REMAINING MARKERS ({len(todos)}):")
for t in todos[:10]:
print(f" - {t}")
issues_total += len(todos)
print()
# Anonymization
if args.check_anon or (args.venue and VENUE_LIMITS.get(args.venue, {}).get("anonymous")):
anon_issues = check_anonymization(tex_content)
if anon_issues:
print(f"ANONYMIZATION ISSUES ({len(anon_issues)}):")
for issue in anon_issues:
print(f" - {issue}")
issues_total += len(anon_issues)
else:
print("Anonymization: OK")
print()
# Common formatting issues
fmt_issues = []
# Check for unescaped special chars (outside math mode, simplified)
for char, escaped in [("_", r"\_"), ("%", r"\%"), ("&", r"\&")]:
# This is a simplified check
pass
# Check for \begin without \end
begins = re.findall(r"\\begin\{(\w+)\}", tex_content)
ends = re.findall(r"\\end\{(\w+)\}", tex_content)
begin_counts = {}
end_counts = {}
for b in begins:
begin_counts[b] = begin_counts.get(b, 0) + 1
for e in ends:
end_counts[e] = end_counts.get(e, 0) + 1
for env in set(list(begin_counts.keys()) + list(end_counts.keys())):
bc = begin_counts.get(env, 0)
ec = end_counts.get(env, 0)
if bc != ec:
fmt_issues.append(f"Mismatched environment: \\begin{{{env}}} ({bc}x) vs \\end{{{env}}} ({ec}x)")
if fmt_issues:
print(f"FORMATTING ISSUES ({len(fmt_issues)}):")
for issue in fmt_issues:
print(f" - {issue}")
issues_total += len(fmt_issues)
print()
# Stats
cite_count = len(re.findall(r"\\cite[a-z]*\{", tex_content))
fig_count = len(re.findall(r"\\begin\{figure", tex_content))
table_count = len(re.findall(r"\\begin\{table", tex_content))
eq_count = len(re.findall(r"\\begin\{(?:equation|align)", tex_content))
print(f"Content stats:")
print(f" Citations: {cite_count}")
print(f" Figures: {fig_count}")
print(f" Tables: {table_count}")
print(f" Equations: {eq_count}")
print()
# Summary
if issues_total == 0:
print("All checks passed!")
else:
print(f"Total issues: {issues_total}")
if args.fix and issues_total > 0:
clean_script = os.path.join(os.path.dirname(__file__), "clean_latex.py")
if os.path.exists(clean_script):
import subprocess
fixed_path = args.tex_file.replace(".tex", "_fixed.tex")
fix_cmd = [sys.executable, clean_script, "--input", args.tex_file, "--output", fixed_path]
result = subprocess.run(fix_cmd, capture_output=True, text=True)
if result.returncode == 0:
print(f"\nFixed file written to: {fixed_path}")
if result.stderr:
print(result.stderr)
else:
print(f"\nFix failed: {result.stderr}", file=sys.stderr)
sys.exit(1 if issues_total > 0 else 0)
if __name__ == "__main__":
main()
Related skills
Forks & variants (2)
Latex Formatting has 2 known copies in the catalog totaling 13 installs. They canonicalize to this original listing.
- lingzhi227 - 12 installs
- lingzhi227 - 1 installs
FAQ
What does latex-formatting do?
Handle LaTeX formatting, templates, and styling for academic papers. Set up conference templates (ICML, ICLR, NeurIPS, AAAI, ACL), fix formatting issues, manage packages, and ensure venue-specific com
When should I use latex-formatting?
During idea research work for documentation.
Is latex-formatting safe to install?
Review the Security Audits panel on this listing before production use.