Open oneaiguru opened 4 weeks ago
code currently generated probably nbot fully is in scr - # src/config.py from pathlib import Path import json
class ProjectConfig: def init(self, project_path): self.project_path = Path(project_path) self.config_path = self.project_path / '.fileselect' / 'config.json' self.config = self._load_config()
def _load_config(self):
if self.config_path.exists():
with open(self.config_path) as f:
return json.load(f)
return {
'features': {
'files': True, # Files are always enabled
'folders': False,
'tags': False
},
'key_mappings': {
'tags': '123456789',
'folders': 'abcdefghijklmnopqrstuvwxyz',
'files': '0!@#$%^&*()'
}
}
def save_config(self):
self.config_path.parent.mkdir(parents=True, exist_ok=True)
with open(self.config_path, 'w') as f:
json.dump(self.config, f, indent=2)
def is_feature_enabled(self, feature_name):
return self.config['features'].get(feature_name, False)
def toggle_feature(self, feature_name):
if feature_name in self.config['features']:
self.config['features'][feature_name] = not self.config['features'][feature_name]
self.save_config()
def get_key_mapping(self, feature_name):
return self.config['key_mappings'].get(feature_name, '')
class Selection: def init(self): self.selected = set()
def toggle(self, item):
if item in self.selected:
self.selected.remove(item)
return False
else:
self.selected.add(item)
return True
def is_selected(self, item):
return item in self.selected
def clear(self):
self.selected.clear()
def add_all(self, items):
self.selected.update(items)
def remove_all(self, items):
self.selected.difference_update(items)
def get_selected(self):
return list(self.selected)
class KeyMapping: def init(self): self.key_to_item = {} self.item_to_key = {}
def assign_key(self, item, key):
if key in self.key_to_item or item in self.item_to_key:
self.clear_key(key)
self.clear_item(item)
self.key_to_item[key] = item
self.item_to_key[item] = key
def get_key(self, item):
return self.item_to_key.get(item)
def get_item(self, key):
return self.key_to_item.get(key)
def clear_key(self, key):
if key in self.key_to_item:
item = self.key_to_item[key]
del self.key_to_item[key]
if item in self.item_to_key:
del self.item_to_key[item]
def clear_item(self, item):
if item in self.item_to_key:
key = self.item_to_key[item]
del self.item_to_key[item]
if key in self.key_to_item:
del self.key_to_item[key]
from rich.console import Console from rich.table import Table
class BaseTable: def init(self): self.console = Console() self.table = None
def create_table(self):
self.table = Table(show_header=True, header_style="bold magenta")
self.add_header()
return self.table
def add_header(self):
raise NotImplementedError("Subclasses must implement add_header")
def add_row(self, *args, **kwargs):
if self.table is None:
self.create_table()
self.table.add_row(*args, **kwargs)
def render(self):
if self.table is None:
self.create_table()
self.console.print(self.table)
from .base import BaseTable from pathlib import Path
class FileTable(BaseTable): def add_header(self): self.table.add_column("S", width=1) self.table.add_column("Key", width=1) self.table.add_column("Path", style="cyan") self.table.add_column("Extension", style="yellow")
def display_files(self, files, selection, key_mapping):
self.create_table()
for file in files:
key = key_mapping.get_key(file)
if key:
selected_mark = '[bright_white]✔[/bright_white]' if selection.is_selected(file) else ''
relative_path = file.relative_to(file.parent)
name, ext = relative_path.stem, relative_path.suffix
self.add_row(
selected_mark,
key,
f" {name}",
ext
)
self.render()
from .base import BaseTable from pathlib import Path
class FolderTable(BaseTable): def add_header(self): self.table.add_column("S", width=1) self.table.add_column("Key", width=1) self.table.add_column("Folder", style="bright_blue") self.table.add_column("Files", justify="right")
def display_folders(self, folders, selection, key_mapping):
self.create_table()
folder_colors = self._get_folder_colors()
for i, folder in enumerate(sorted(folders)):
key = key_mapping.get_key(folder)
if key:
folder_files = folders[folder]
selected_count = sum(1 for f in folder_files if selection.is_selected(f))
total_count = len(folder_files)
if selected_count == total_count and total_count > 0:
selected_mark = '[bright_white]✔[/bright_white]'
elif selected_count > 0:
selected_mark = '[bright_white]◐[/bright_white]'
else:
selected_mark = ''
color = folder_colors[i % len(folder_colors)]
self.add_row(
selected_mark,
key,
f"[{color}]{folder.name}[/{color}]",
f"{selected_count}/{total_count}"
)
self.render()
def _get_folder_colors(self):
return [
"bright_blue", "bright_green", "bright_yellow",
"bright_magenta", "bright_cyan", "orange1",
"deep_sky_blue1", "spring_green1"
]
from .base import BaseTable
class TagTable(BaseTable): def add_header(self): self.table.add_column("S", width=1) self.table.add_column("Key", width=1) self.table.add_column("Tag", style="bright_yellow") self.table.add_column("Files", justify="right")
def display_tags(self, tags, selection, key_mapping):
self.create_table()
for tag_name, tag_files in sorted(tags.items()):
key = key_mapping.get_key(tag_name)
if key:
selected_mark = '[bright_white]✔[/bright_white]' if selection.is_selected(tag_name) else ''
self.add_row(
selected_mark,
key,
tag_name,
str(len(tag_files))
)
self.render()
from pathlib import Path import readchar from rich.console import Console from config import ProjectConfig from storage import SelectionStorage from selectors.files import FileSelector from selectors.folders import FolderSelector from selectors.tags import TagSelector from displays.files import FileTable from displays.folders import FolderTable from displays.tags import TagTable
class SelectionManager: def init(self, root_dir): self.root_dir = Path(root_dir) self.config = ProjectConfig(root_dir) self.storage = SelectionStorage(root_dir) self.console = Console()
# Initialize selectors based on enabled features
self.selectors = {}
self.displays = {}
# Files are always enabled
self.selectors['files'] = FileSelector(self.root_dir)
self.displays['files'] = FileTable()
if self.config.is_feature_enabled('folders'):
self.selectors['folders'] = FolderSelector(self.root_dir)
self.displays['folders'] = FolderTable()
if self.config.is_feature_enabled('tags'):
self.selectors['tags'] = TagSelector(self.root_dir)
self.displays['tags'] = TagTable()
def run(self):
while True:
self.display_tables()
key = readchar.readkey()
if key == '\n': # Enter key
self.save_selection()
break
elif key == '\x1b': # Escape key
break
else:
self.handle_key(key)
def display_tables(self):
self.console.clear()
# Display tables in order: tags -> folders -> files
if self.config.is_feature_enabled('tags'):
self.displays['tags'].display_tags(
self.selectors['tags'].list_tags(),
self.selectors['tags'].selection,
self.selectors['tags'].key_mapping
)
if self.config.is_feature_enabled('folders'):
self.displays['folders'].display_folders(
self.selectors['folders'].list_folders(),
self.selectors['files'].selection, # Use file selection for folder status
self.selectors['folders'].key_mapping
)
self.displays['files'].display_files(
self.selectors['files'].list_files(),
self.selectors['files'].selection,
self.selectors['files'].key_mapping
)
def handle_key(self, key):
handled = False
# Try tags first
if self.config.is_feature_enabled('tags'):
handled = self.selectors['tags'].handle_tag_key(key)
if handled:
tag = self.selectors['tags'].key_mapping.get_item(key)
if tag:
self.selectors['tags'].apply_tag_selection(tag)
return
# Then try folders
if not handled and self.config.is_feature_enabled('folders'):
handled = self.selectors['folders'].handle_folder_key(key)
if handled:
folder = self.selectors['folders'].key_mapping.get_item(key)
if folder:
self.selectors['folders'].toggle_folder_files(folder)
return
# Finally try files
if not handled:
self.selectors['files'].handle_file_key(key)
def save_selection(self):
# Save the current selection state
self.storage.save_selection(
self.selectors['files'].get_selection(),
'files'
)
def main(): import argparse parser = argparse.ArgumentParser(description="Interactive file selection tool") parser.add_argument("directory", help="Directory to select files from") args = parser.parse_args()
manager = SelectionManager(args.directory)
manager.run()
if name == "main": main()
Implementation Plan: Modular File Selection System
1. Project Structure
2. Core Components
2.1 Configuration (config.py)
ProjectConfig
class:load_config(project_path)
save_config()
toggle_feature(feature_name)
get_active_features()
2.2 Storage (storage.py)
SelectionStorage
class:save_selection(selection, type='files')
load_selection(type='files')
save_tag(key, selection)
load_tag(key)
2.3 Models (models.py)
Selection
class:toggle(item)
is_selected(item)
clear()
add_all(items)
remove_all(items)
KeyMapping
class:assign_key(item, key)
get_key(item)
get_item(key)
3. Display Components
3.1 Base Display (displays/base.py)
BaseTable
class:create_table()
add_header()
add_row()
render()
3.2 Files Display (displays/files.py)
FileTable(BaseTable)
class:display_files(files, selection, key_mapping)
get_file_color(file)
3.3 Folders Display (displays/folders.py)
FolderTable(BaseTable)
class:display_folders(folders, selection, key_mapping)
get_folder_color(folder)
3.4 Tags Display (displays/tags.py)
TagTable(BaseTable)
class:display_tags(tags, selection, key_mapping)
4. Selector Components
4.1 Base Selector (selectors/base.py)
BaseSelector
class:handle_input(key)
toggle_selection(item)
get_selection()
4.2 File Selector (selectors/files.py)
FileSelector(BaseSelector)
class:list_files()
filter_files()
handle_file_key(key)
4.3 Folder Selector (selectors/folders.py)
FolderSelector(BaseSelector)
class:list_folders()
handle_folder_key(key)
toggle_folder_files(folder)
4.4 Tag Selector (selectors/tags.py)
TagSelector(BaseSelector)
class:list_tags()
handle_tag_key(key)
apply_tag_selection()
5. Main Selection Manager
6. Implementation Notes
Feature Toggle Storage:
.fileselect
directory in project rootKey Mapping Priorities:
UI Layout:
Selection Behavior:
Performance Considerations:
Testing Strategy: