Skip to content

Commit

Permalink
feat: presets
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Nunamaker committed Jul 27, 2024
1 parent a4365a6 commit 9f2a268
Show file tree
Hide file tree
Showing 8 changed files with 496 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@ ehthumbs.db
Thumbs.db

# IDEs
.idea/
.idea/
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==8.3.2
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pyyaml==6.0.1
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@
install_requires=[
# Add any dependencies here
],
extras_require={
'dev': ['pytest>=8.3.2'],
},
)
58 changes: 45 additions & 13 deletions stringify/cli.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import argparse
import logging
import os

from .utils import (
load_presets, save_presets, check_rsync, run_rsync, validate_rsync_args,
gather_code, interactive_mode, print_tree, copy_to_clipboard
gather_code, interactive_mode, print_tree, copy_to_clipboard,
get_default_preset, set_default_preset, parse_gitignore
)

logging.basicConfig(level=logging.INFO)
Expand All @@ -22,27 +24,30 @@ def main():
parser.add_argument("-sap", "--save-as-preset", metavar="NAME", help="Save the current command as a preset")
parser.add_argument("-lp", "--list-presets", action="store_true", help="List all saved presets")
parser.add_argument("-dp", "--delete-preset", help="Delete a saved preset")
parser.add_argument("-sdp", "--set-default-preset", help="Set the default preset")
parser.add_argument("-i", "--interactive", action="store_true", help="Enter interactive mode")
parser.add_argument("-nc", "--no-clipboard", action="store_true", help="Don't copy output to clipboard")
parser.add_argument("-pl", "--preview-length", type=int, metavar="N",
help="Show only the first N lines of each file")
parser.add_argument("-s", "--summary", action="store_true", help="Print a summary including a tree of files")
parser.add_argument("-id", "--include-dirs", action="store_true",
help="Include empty directories in output and summary")
parser.add_argument("-g", "--no-gitignore", action="store_false", dest="use_gitignore",
help="Don't use .gitignore patterns")

args, unknown_args = parser.parse_known_args()

presets = load_presets()

if args.list_presets:
print("Saved presets:")
for name, preset_args in presets.items():
print(f" {name}: {' '.join(preset_args)}")
for name, preset in presets.items():
print(f" {'*' if preset.get('is_default', False) else ' '} {name}: {' '.join(preset['args'])}")
return

if args.save_preset:
name, preset_args = args.save_preset
presets[name] = preset_args.split()
presets[name] = {'is_default': False, 'args': preset_args.split()}
save_presets(presets)
print(f"Preset '{name}' saved.")
return
Expand All @@ -56,9 +61,28 @@ def main():
print(f"Preset '{args.delete_preset}' not found.")
return

rsync_args = presets.get(args.preset, []) if args.preset else []
if args.set_default_preset:
set_default_preset(presets, args.set_default_preset)
return

preset_name = args.preset or get_default_preset(presets)
if preset_name:
preset = presets.get(preset_name)
if preset:
rsync_args = preset['args']
else:
print(f"Error: Preset '{preset_name}' not found.")
return
else:
rsync_args = []

rsync_args.extend(unknown_args)

if args.use_gitignore:
gitignore_path = os.path.join(os.getcwd(), '.gitignore')
gitignore_patterns = parse_gitignore(gitignore_path)
rsync_args = gitignore_patterns + rsync_args

if not any(arg for arg in rsync_args if not arg.startswith('--')):
rsync_args.append('.')

Expand All @@ -67,23 +91,31 @@ def main():
return

if args.interactive:
rsync_args = interactive_mode(rsync_args)
rsync_args = interactive_mode(rsync_args, args.include_dirs)

file_list = run_rsync(rsync_args)
num_files = len([f for f in file_list if not os.path.isdir(f)])
result = gather_code(file_list, args.preview_length, args.include_dirs)

if args.summary:
preset_name = args.preset or get_default_preset(presets)
preset = presets.get(preset_name) if preset_name else None
if ' '.join(rsync_args) != ' '.join(preset['args']):
if args.use_gitignore and ' '.join(gitignore_patterns + preset['args']) != ' '.join(rsync_args):
print(f"Gathered {num_files} files using preset '{preset_name}' with modified rsync options: {' '.join(rsync_args)}:")
else:
print(f"Gathered {num_files} files using preset '{preset_name}' modified by .gitignore:")
else:
print(f"Gathered {num_files} files using preset '{preset_name}':")
print_tree(file_list, include_dirs=args.include_dirs)

if args.no_clipboard:
print(result)
else:
copy_to_clipboard(result, file_list)

if args.summary:
print(f"Gathered {len(file_list)} files using rsync options: {' '.join(rsync_args)}")
print("\nFile tree:")
print_tree(file_list, include_dirs=args.include_dirs)
copy_to_clipboard(result, file_list, num_files)

if args.save_as_preset:
presets[args.save_as_preset] = rsync_args
presets[args.save_as_preset] = {'is_default': False, 'args': rsync_args}
save_presets(presets)
print(f"Preset '{args.save_as_preset}' saved.")

Expand Down
226 changes: 226 additions & 0 deletions stringify/default_presets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
everything:
is_default: false
args:
- .

common:
is_default: true
args:
# Common exclusions
- --exclude=.*
- --exclude=.*/
- --exclude=*.log
- --exclude=*.bak
- --exclude=*.tmp
- --exclude=*.temp
- --exclude=*.swp
- --exclude=*.swo
- --exclude=*~
- --exclude=Thumbs.db
- --exclude=.DS_Store

# Version control
- --exclude=.git
- --exclude=.svn
- --exclude=.hg

# IDE and editor files
- --exclude=.vscode
- --exclude=.idea
- --exclude=*.sublime-*

# Build outputs and dependencies
- --exclude=venv
- --exclude=env
- --exclude=.venv
- --exclude=__pycache__
- --exclude=*.pyc
- --exclude=*.pyo
- --exclude=*.pyd
- --exclude=*.egg-info
- --exclude=.pytest_cache
- --exclude=.mypy_cache
- --exclude=.coverage
- --exclude=htmlcov
- --exclude=node_modules
- --exclude=bower_components
- --exclude=dist
- --exclude=build
- --exclude=.next
- --exclude=.nuxt
- --exclude=*.min.js
- --exclude=*.min.css
- --exclude=vendor/
- --exclude=*.class
- --exclude=*.jar
- --exclude=*.war
- --exclude=*.ear
- --exclude=target/
- --exclude=*.o
- --exclude=*.a
- --exclude=*.so
- --exclude=*.dll
- --exclude=*.exe
- --exclude=*.out
- --exclude=*.app
- --exclude=*.dylib
- --exclude=*.bin
- --exclude=*.dSYM
- --exclude=*.elf

# Lock files
- --exclude=package-lock.json
- --exclude=yarn.lock
- --exclude=Gemfile.lock
- --exclude=Pipfile.lock
- --exclude=Cargo.lock

# Potential secret files
- --exclude=*.env
- --exclude=.env*
- --exclude=*.pem
- --exclude=*.key
- --exclude=*_rsa
- --exclude=*_dsa
- --exclude=*.crt
- --exclude=*.cer

# Documentation and media files
- --exclude=*.pdf
- --exclude=*.doc
- --exclude=*.docx
- --exclude=*.ppt
- --exclude=*.pptx
- --exclude=*.xls
- --exclude=*.xlsx
- --exclude=*.jpg
- --exclude=*.jpeg
- --exclude=*.png
- --exclude=*.gif
- --exclude=*.bmp
- --exclude=*.svg
- --exclude=*.ico
- --exclude=*.mp3
- --exclude=*.mp4
- --exclude=*.avi
- --exclude=*.mov

# Include all directory paths
- --include=*/

# Include common source code files
- --include=*.py
- --include=*.ipynb
- --include=*.js
- --include=*.ts
- --include=*.jsx
- --include=*.tsx
- --include=*.html
- --include=*.htm
- --include=*.css
- --include=*.scss
- --include=*.sass
- --include=*.rb
- --include=*.erb
- --include=*.java
- --include=*.kt
- --include=*.groovy
- --include=*.c
- --include=*.cpp
- --include=*.cc
- --include=*.cxx
- --include=*.h
- --include=*.hpp
- --include=*.cs
- --include=*.fs
- --include=*.vb
- --include=*.go
- --include=*.rs
- --include=*.php
- --include=*.scala
- --include=*.swift
- --include=*.m
- --include=*.mm
- --include=*.sh
- --include=*.bash
- --include=*.zsh
- --include=*.sql

# Include common configuration and data files
- --include=*.ini
- --include=*.cfg
- --include=*.conf
- --include=*.toml
- --include=*.yaml
- --include=*.yml
- --include=*.json

# Include specific important configuration files
- --include=.gitignore
- --include=.dockerignore
- --include=requirements.txt
- --include=Pipfile
- --include=package.json
- --include=tsconfig.json
- --include=Gemfile
- --include=pom.xml
- --include=build.gradle
- --include=settings.gradle
- --include=Cargo.toml
- --include=.editorconfig

# Include documentation files
- --include=*.md
- --include=*.rst
- --include=*.txt

# Include other important files
- --include=Dockerfile
- --include=*.dockerfile
- --include=Makefile
- --include=*.mk
- --include=*.gradle
- --include=*.plist

# Exclude everything else
- --exclude=*

# Root directory
- .

# Add more presets as needed, for example:

docs-only:
is_default: false
args:

# Include all directories for traversal
- --include=*/

# Include only documentation files
- --include=*.md
- --include=*.rst
- --include=*.txt
- --include=*.adoc
- --include=*.docx
- --include=*.pdf

# Include specific documentation files
- --include=README*
- --include=CONTRIBUTING*
- --include=CHANGELOG*
- --include=LICENSE*

# Include documentation directories
- --include=docs/***
- --include=documentation/***
- --include=wiki/***

# Prune other directories to speed up the process
- --prune-empty-dirs

# Exclude everything by default
- --exclude=*

# Root directory
- .
Loading

0 comments on commit 9f2a268

Please sign in to comment.