Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "ctxify"
version = "0.1.7"
version = "0.1.8"
description = "A tool to print git repository files with tree structure"
readme = "README.md"
requires-python = ">=3.8"
Expand Down
2 changes: 1 addition & 1 deletion src/ctxify/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.1.7'
__version__ = '0.1.8'
67 changes: 49 additions & 18 deletions src/ctxify/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def estimate_tokens(text: str) -> int:


def interactive_file_selection(root_dir: str = '.', include_md: bool = False) -> str:
"""Interactively select files to include with fuzzy tab autocompletion"""
"""Interactively select files or directories to include with fuzzy tab autocompletion"""
if not check_git_repo(root_dir):
print(
f'Error: {root_dir} is not within a git repository. This tool requires a git repository.'
Expand All @@ -192,47 +192,79 @@ def interactive_file_selection(root_dir: str = '.', include_md: bool = False) ->
print('\n'.join(tree_lines))
return '\n'.join(tree_lines)

completer = FuzzyWordCompleter(all_files)
# Add directories to completion options
all_dirs = set()
for f in all_files:
path = Path(f)
for parent in path.parents:
if str(parent) != '.':
all_dirs.add(str(parent))
completion_options = sorted(all_files + list(all_dirs))

completer = FuzzyWordCompleter(completion_options)
session = PromptSession(completer=completer, complete_while_typing=True)

tree_lines.append(f'\nFiles Available in Context (from {root_dir}):')
tree_lines.append(f'\nFiles and Directories Available in Context (from {root_dir}):')
print_filtered_tree(all_files, tree_lines)
print('\n'.join(tree_lines))
print('\nEnter file paths to include (press Enter twice to finish):')
print('\nEnter file or directory paths to include (press Enter twice to finish):')

selected_files: List[str] = []
selected_items: List[str] = []
while True:
try:
file_path = session.prompt('> ')
if not file_path:
if not selected_files:
input_path = session.prompt('> ')
if not input_path:
if not selected_items:
continue
break
if file_path in all_files:
if file_path not in selected_files:
selected_files.append(file_path)
print(f'Added: {file_path}')
if input_path in completion_options:
if input_path not in selected_items:
selected_items.append(input_path)
print(f'Added: {input_path}')
else:
print(f'Already added: {file_path}')
print(f'Already added: {input_path}')
else:
print(f'File not found: {file_path}')
print(f'Path not found: {input_path}')
except KeyboardInterrupt:
break

output_lines.extend(tree_lines)
output_lines.append('\n' + '-' * 50 + '\n')
target_dir = Path(root_dir).resolve()
for file_path in selected_files:
full_path = target_dir / file_path

for item_path in selected_items:
full_path = target_dir / item_path
if full_path.is_file():
output_lines.append(f'{file_path}:')
# Handle individual file
output_lines.append(f'{item_path}:')
try:
with open(full_path, 'r', encoding='utf-8') as f:
content = f.read()
output_lines.append(content)
except Exception as e:
output_lines.append(f'Error reading file: {e}')
output_lines.append('')
elif full_path.is_dir():
# Handle directory
output_lines.append(f'\nDirectory {item_path} contents:')
dir_files = [f for f in all_files if f.startswith(item_path + '/') or f == item_path]
if not dir_files:
output_lines.append(f'No tracked files found in {item_path}')
continue
# Print directory structure
print_filtered_tree(dir_files, output_lines)
output_lines.append('\nFile contents:')
for file_path in dir_files:
full_file_path = target_dir / file_path
if full_file_path.is_file():
output_lines.append(f'\n{file_path}:')
try:
with open(full_file_path, 'r', encoding='utf-8') as f:
content = f.read()
output_lines.append(content)
except Exception as e:
output_lines.append(f'Error reading file: {e}')
output_lines.append('')

full_output = '\n'.join(output_lines)
token_count = estimate_tokens(full_output)
Expand All @@ -244,7 +276,6 @@ def interactive_file_selection(root_dir: str = '.', include_md: bool = False) ->

return full_output


def print_git_contents(
root_dir: str = '.', include_md: bool = False, structure_only: bool = False
) -> str:
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.