Skip to content

Instantly share code, notes, and snippets.

@robertdevore
Last active May 11, 2025 08:37
Show Gist options
  • Save robertdevore/ec4dbaf958109e10bfd2ef48f5dd3377 to your computer and use it in GitHub Desktop.
Save robertdevore/ec4dbaf958109e10bfd2ef48f5dd3377 to your computer and use it in GitHub Desktop.

📂 Project File Tree Generator

A simple Python script that generates a Markdown overview of your project’s folder structure—complete with depth control and inline includes of your README.md, package.json, and composer.json. Outputs to filetree.md, with an optional --clip flag to copy the result to your clipboard.


Features

  • Directory tree Recursively list files and folders in Markdown format.

  • Depth control Limit recursion depth with --depth (or -d).

  • Inline includes Automatically pull in:

    • README.md
    • package.json
    • composer.json
  • Clipboard copy Off by default; enable with --clip.


Prerequisites

  • Python 3.6+

  • pyperclip

    pip install pyperclip

Installation

  1. Clone or download this repo.

  2. Ensure filetree.py is executable (or run via python).

  3. Install dependencies:

    pip install pyperclip

Usage

Run from your project’s root folder:

# Generate full tree → filetree.md (no clipboard)
python3 filetree.py

# Limit to 2 levels deep
python3 filetree.py --depth 2

# Include clipboard copy
python3 filetree.py --clip

# Both depth and clipboard
python3 filetree.py --depth 3 --clip

Arguments

  • --depth, -d <int> Maximum folder depth (default: unlimited).

  • --clip Copy the final Markdown to your clipboard.


Output

  • filetree.md

    • Starts with a “📂 Project File Tree” heading
    • Bullet-list directory structure
    • Sections for README.md, package.json, and composer.json (if present)
  • Clipboard (if --clip): the same content is copied and ready to paste


Example

# 📂 Project File Tree

- filetree.py
- src
    - main.py
    - utils.py
- tests
    - test_main.py

---

## 📖 README.md
…(your README content)…

---

## 📦 package.json
…(your package.json content)…


---

## 🔧 composer.json

…(your composer.json content)…
import os
import argparse
import pyperclip
from typing import Optional
def generate_file_tree(
base_path: str,
ignore_hidden: bool = True,
max_depth: Optional[int] = None
) -> str:
"""
Recursively generates a Markdown-formatted file tree from the given base path.
Args:
base_path (str): The root directory to start from.
ignore_hidden (bool): If True, hidden files/folders (starting with '.') are excluded.
max_depth (Optional[int]): Maximum depth to recurse (None = unlimited).
Returns:
str: A Markdown-formatted string representing the directory tree.
"""
tree_lines = []
def walk_dir(current_path: str, depth: int = 0):
if max_depth is not None and depth > max_depth:
return
try:
entries = sorted(os.listdir(current_path))
except PermissionError:
return
for entry in entries:
if ignore_hidden and entry.startswith('.'):
continue
full_path = os.path.join(current_path, entry)
indent = ' ' * depth
prefix = '- '
tree_lines.append(f"{indent}{prefix}{entry}")
if os.path.isdir(full_path):
walk_dir(full_path, depth + 1)
walk_dir(base_path)
return '\n'.join(tree_lines)
def read_file_if_exists(path: str) -> Optional[str]:
"""Return the file contents if it exists, otherwise None."""
if os.path.isfile(path):
with open(path, 'r', encoding='utf-8') as f:
return f.read().rstrip()
return None
def main():
"""
Main function to:
- Parse arguments
- Generate the file tree (up to the given depth)
- Inline include README.md, package.json, and composer.json
- Write everything to filetree.md
- Copy to clipboard if --clip is passed
"""
parser = argparse.ArgumentParser(description="Generate a Markdown project overview.")
parser.add_argument(
"--depth", "-d",
type=int,
default=None,
help="Maximum folder depth to include (default: unlimited)."
)
parser.add_argument(
"--clip",
action="store_true",
help="Copy the output to the clipboard."
)
args = parser.parse_args()
script_dir = os.path.dirname(os.path.abspath(__file__))
tree_md = generate_file_tree(script_dir, max_depth=args.depth)
sections = ["# 📂 Project File Tree\n", tree_md]
# Inline README.md
readme = read_file_if_exists(os.path.join(script_dir, "README.md"))
if readme:
sections += ["\n\n---\n\n## 📖 README.md\n", readme]
# Inline package.json
pkg = read_file_if_exists(os.path.join(script_dir, "package.json"))
if pkg:
sections += ["\n\n---\n\n## 📦 package.json\n```json\n", pkg, "\n```"]
# Inline composer.json
comp = read_file_if_exists(os.path.join(script_dir, "composer.json"))
if comp:
sections += ["\n\n---\n\n## 🔧 composer.json\n```json\n", comp, "\n```"]
markdown_output = ''.join(sections)
output_file = os.path.join(script_dir, 'filetree.md')
# Save to file
with open(output_file, 'w', encoding='utf-8') as f:
f.write(markdown_output)
print(f"✅ File tree written to: {output_file}")
# Copy to clipboard only if requested
if args.clip:
pyperclip.copy(markdown_output)
print("📋 File tree copied to clipboard.")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment