diff --git a/.github/workflows/update-readme.yml b/.github/workflows/update-readme.yml index ff25277e..751e51cd 100644 --- a/.github/workflows/update-readme.yml +++ b/.github/workflows/update-readme.yml @@ -12,7 +12,7 @@ on: jobs: regen-readme: - runs-on: self-hosted + runs-on: ubuntu-latest steps: - name: šŸ›Žļø Checkout @@ -21,6 +21,11 @@ jobs: persist-credentials: true token: ${{ secrets.GITHUB_TOKEN }} + - name: šŸ Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: āš™ļø Generate TOC run: python3 scripts/order.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..020f14af --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class + +# Virtual environments +venv/ +.env/ + +# IDE +.vscode/ +.idea/ + +# Build directories +build/ +cmake-build-*/ + +# OS files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md index 7f4f0177..9b3f7019 100644 --- a/README.md +++ b/README.md @@ -38,24 +38,24 @@ A–I - I–R + J–R S–W Atari-Games - introspective + JS-compiler SFML Multithread verlet Beneficial-C programming - JS-compiler + Json Converter Simple-Code Chess 3 D - Json Converter + Kalman-Filtering-Simulation simple turso @@ -80,39 +80,44 @@ define evil - ofx Async + Naive Circuit Simulator Terminal File Manager Design-Patterns - Open GL examples + ofx Async Thread Pool Dump C++ - PFAD + Open GL examples Tokenizer tok File Lock Socket - Pipes Screen Saver + PFAD Trigonometric-Functions Gen XPassword - POng + Pipes Screen Saver Vite FA config Hangman - Random Utility tools + POng volumetric-clouds Inject Hook - Regular Expression Convertors + Random Utility tools Word Proc + + introspective + Regular Expression Convertors + + diff --git a/scripts/order.py b/scripts/order.py index 86832213..10461b6c 100644 --- a/scripts/order.py +++ b/scripts/order.py @@ -1,21 +1,30 @@ #!/usr/bin/env python3 +""" +README Table of Contents Generator + +This script automatically generates and updates the Table of Contents (TOC) +in the README.md file based on project directories in the repository. +""" import os +import sys import math import re import urllib.parse +from pathlib import Path from itertools import zip_longest # Configuration README = "README.md" -EXCLUDE = {".git", ".github", "scripts", "__pycache__"} +EXCLUDE = {".git", ".github", "scripts", "__pycache__", "wiki"} # Override mapping: directory name -> desired header display OVERRIDES = { "Dump_c++": "Dump C++", # can add any other overrides } -# Derive a human-friendly display name for TOC entries + def display_name(name): + """Derive a human-friendly display name for TOC entries.""" if name in OVERRIDES: return OVERRIDES[name] # Insert spaces before camelCase boundaries, then replace underscores @@ -23,8 +32,9 @@ def display_name(name): s = s.replace('_', ' ') return s.strip() -# Create a GitHub-style slug for IDs + def slugify(name): + """Create a GitHub-style slug for anchor IDs.""" base = OVERRIDES.get(name, name) # Split camelCase and underscores s = re.sub(r'(?<=[a-z0-9])(?=[A-Z])', ' ', base) @@ -37,84 +47,137 @@ def slugify(name): # Collapse spaces into hyphens return re.sub(r"\s+", "-", s.strip()) -# Convert slug back to a Title Case display without hyphens + def header_display_from_slug(slug): + """Convert slug back to a Title Case display without hyphens.""" disp = slug.replace('-', ' ') return disp.title() -# Compute column header ranges + def header_range(col): + """Compute column header ranges (e.g., 'A-M').""" if not col: return "" first = slugify(col[0])[0].upper() last = slugify(col[-1])[0].upper() return f"{first}–{last}" -# Collect project directories -projects = sorted( - [d for d in os.listdir('.') - if os.path.isdir(d) - and d not in EXCLUDE - and not d.startswith('.')], - key=str.lower -) - -# Split into 3 roughly even columns -cols = 3 -chunk = math.ceil(len(projects) / cols) -columns = [projects[i*chunk:(i+1)*chunk] for i in range(cols)] - -# Build HTML table -lines = [ - '', - ' ', - ' ' -] -for col in columns: - lines.append( - f' ' + +def collect_projects(base_path): + """Collect and return sorted list of project directories.""" + base = Path(base_path) + if not base.is_dir(): + raise ValueError(f"Base path '{base_path}' is not a valid directory") + + projects = sorted( + [d.name for d in base.iterdir() + if d.is_dir() + and d.name not in EXCLUDE + and not d.name.startswith('.')], + key=str.lower ) -lines += [' ', ' ', ' '] - -for row in zip_longest(*columns, fillvalue=""): - lines.append(' ') - for cell in row: - if cell: - slug = slugify(cell) - disp = display_name(cell) - lines.append( - f' ' - ) + return projects + + +def build_toc_table(projects): + """Build HTML table for the Table of Contents.""" + # Split into 3 roughly even columns + cols = 3 + chunk = math.ceil(len(projects) / cols) if projects else 1 + columns = [projects[i*chunk:(i+1)*chunk] for i in range(cols)] + + # Build HTML table + lines = [ + '
{header_range(col)}
{disp}
', + ' ', + ' ' + ] + for col in columns: + lines.append( + f' ' + ) + lines += [' ', ' ', ' '] + + for row in zip_longest(*columns, fillvalue=""): + lines.append(' ') + for cell in row: + if cell: + slug = slugify(cell) + disp = display_name(cell) + lines.append( + f' ' + ) + else: + lines.append( + ' ' + ) + lines.append(' ') + lines += [' ', '
{header_range(col)}
{disp}
'] + return "\n".join(lines) + + +def normalize_headers(content): + """Normalize all headers to slug-based Title Case (no underscores or hyphens).""" + pattern = re.compile(r'^(### \[)([^\]]+)(\]\(\./([^\)]+)\))', re.MULTILINE) + + def repl(match): + raw = match.group(4) + # Decode URL-encoded directory name + decoded = urllib.parse.unquote(raw) + # Generate slug and display + slug = slugify(decoded) + disp = header_display_from_slug(slug) + # Keep original raw in link + return f"### [{disp}](./{raw})" + + return pattern.sub(repl, content) + + +def update_toc_in_content(content, new_toc): + """Replace TOC region in content with new TOC.""" + toc_re = re.compile(r"()(.*?)()", re.S) + return toc_re.sub(rf"\1\n{new_toc}\n\3", content) + + +def main(): + """Main entry point for the TOC generator.""" + readme_path = Path(README) + + # Verify README exists + if not readme_path.is_file(): + print(f"Error: {README} not found in current directory", file=sys.stderr) + sys.exit(1) + + try: + # Collect project directories + projects = collect_projects('.') + + if not projects: + print("Warning: No project directories found", file=sys.stderr) + + # Build new TOC + new_toc = build_toc_table(projects) + + # Read README.md + content = readme_path.read_text(encoding="utf-8") + + # Normalize headers + content = normalize_headers(content) + + # Replace TOC region + updated = update_toc_in_content(content, new_toc) + + # Write back if changed + if updated != content: + readme_path.write_text(updated, encoding="utf-8") + print(f"āœ… {README} updated successfully") else: - lines.append( - ' ' - ) - lines.append(' ') -lines += [' ', ''] -new_toc = "\n".join(lines) - -# Read README.md -with open(README, "r", encoding="utf-8") as f: - content = f.read() - -# Normalize all headers to slug-based Title Case (no underscores or hyphens) -pattern = re.compile(r'^(### \[)([^\]]+)(\]\(\./([^\)]+)\))', re.MULTILINE) -def repl(match): - raw = match.group(4) - # Decode URL-encoded directory name - decoded = urllib.parse.unquote(raw) - # Generate slug and display - slug = slugify(decoded) - disp = header_display_from_slug(slug) - # Keep original raw in link - return f"### [{disp}](./{raw})" -content = pattern.sub(repl, content) - -# Replace TOC region -toc_re = re.compile(r"()(.*?)()", re.S) -updated = toc_re.sub(rf"\1\n{new_toc}\n\3", content) - -# Write back if changed -if updated != content: - with open(README, "w", encoding="utf-8") as f: - f.write(updated) + print(f"ā„¹ļø {README} already up to date") + + except (OSError, ValueError) as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/wiki/Contributing.md b/wiki/Contributing.md index 7c3b47a3..34bd13f5 100644 --- a/wiki/Contributing.md +++ b/wiki/Contributing.md @@ -143,6 +143,19 @@ When adding new features or projects: ## šŸ› Reporting Issues +We have several issue templates to help you report issues effectively: + +### Available Templates + +| Template | Use When | +|----------|----------| +| **[Bug Report](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=bug_report.md)** | Reporting bugs or unexpected behavior | +| **[Feature Request](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=feature_request.md)** | Suggesting new features or enhancements | +| **[Question](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=question.md)** | Asking questions or requesting help | +| **[New Project Proposal](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=new_project_proposal.md)** | Proposing a new C/C++ subproject | + +### Bug Reports + When reporting bugs, please include: 1. **Description** - What happened? @@ -186,6 +199,8 @@ For feature requests, please describe: ## āœ… Pull Request Checklist +We use a [Pull Request Template](https://github.com/ibra-kdbra/CodeConjurer/blob/main/.github/PULL_REQUEST_TEMPLATE.md) that includes a checklist to ensure quality contributions. + Before submitting a PR, ensure: - [ ] Code compiles without warnings diff --git a/wiki/Home.md b/wiki/Home.md index dbc94178..6deade62 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -15,6 +15,15 @@ Welcome to **CodeConjurer**, a comprehensive collection of C++ projects designed | [šŸ“‚ Project Categories](Project-Categories) | Projects organized by type and topic | | [šŸ¤ Contributing](Contributing) | Guidelines for contributing to this repository | +## šŸ“‹ Issue & PR Templates + +We provide standardized templates to help you contribute effectively: + +- **[šŸ› Bug Report](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=bug_report.md)** - Report bugs with project-specific details +- **[šŸ’” Feature Request](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=feature_request.md)** - Suggest enhancements +- **[ā“ Question](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=question.md)** - Ask for help +- **[šŸ†• New Project Proposal](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=new_project_proposal.md)** - Propose new C/C++ subprojects + ## šŸ“Š Repository Statistics - **40+ Projects** covering various C++ topics diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md index 186e540c..03c6bba7 100644 --- a/wiki/_Sidebar.md +++ b/wiki/_Sidebar.md @@ -36,6 +36,12 @@ - [Contributing](Contributing) - [Issues](https://github.com/ibra-kdbra/CodeConjurer/issues) +### šŸ“‹ Templates +- [Bug Report](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=bug_report.md) +- [Feature Request](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=feature_request.md) +- [New Project Proposal](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=new_project_proposal.md) +- [Question](https://github.com/ibra-kdbra/CodeConjurer/issues/new?template=question.md) + --- ### šŸ“Ž Resources