diff --git a/prompt_plan.md b/prompt_plan.md new file mode 100644 index 0000000..088e300 --- /dev/null +++ b/prompt_plan.md @@ -0,0 +1,153 @@ +# Phase 1: Core Tag Handling +## Prompt 1: Tag Parsing/Validation Module +```text +Create a Rust module ```tag_engine``` with: +1. Tag validation function ```validate_tag(tag: &str) -> Result<(), TagError>``` + - Checks for prohibited characters (NUL, :, /, space) + - Validates tag is non-empty + - Returns custom error variants +2. Tag parsing function ```parse_tags(filename: &str) -> Result<(String, Vec), ParseError>``` + - Splits filename into base name and tags using " -- " delimiter + - Handles multiple delimiters as errors + - Preserves file extension +3. Unit tests covering: + - Valid/invalid tags + - Filename parsing edge cases + - Error propagation +``` + +## Prompt 2: Tag Serialization +```text +Extend ```tag_engine``` with: +1. ```serialize_tags(base: &str, tags: &[String], ext: &str) -> String``` + - Combines base name, sorted tags, and extension + - Uses " -- " delimiter only when tags exist + - Maintains alphabetical tag order +2. Unit tests for: + - Roundtrip parsing/serialization + - Empty tags handling + - Extension preservation + - Case sensitivity checks +``` + +# Phase 2: Basic Commands +## Prompt 3: List Command Implementation +```text +Implement ```list``` command: +1. CLI argument parsing using clap +2. Core logic: + - Process each file through ```tag_engine::parse_tags``` + - Collect unique tags across all files + - Output sorted tags line-by-line +3. Unit tests for: + - Multi-file tag aggregation + - Empty input handling + - Error propagation from tag engine +``` + +## Prompt 4: Add Command Foundation +```text +Implement core of ```add``` command: +1. Tag merging logic: + - Combine existing and new tags + - Remove duplicates while preserving order + - Case-sensitive comparison +2. Function signature: + ```fn add_tags(current: Vec, new: Vec) -> Vec``` +3. Unit tests for: + - Duplicate prevention + - Order preservation + - Case sensitivity +``` + +## Prompt 5: Complete Add Command +```text +Wire up ```add``` command: +1. File processing loop: + - Parse existing tags + - Merge with new tags + - Serialize new filename + - Atomic rename operation +2. Error handling: + - Clean error messages + - Early exit on first error +3. Integration tests: + - Actual file renaming + - Permission handling + - Cross-platform path handling +``` + +# Phase 3: Advanced Operations +## Prompt 6: Remove Command Core +```text +Implement tag removal logic: +1. Function ```filter_tags(current: Vec, remove: &[String]) -> Vec``` + - Remove all instances of specified tags + - Maintain original order of remaining tags +2. Unit tests for: + - Multi-tag removal + - Non-existent tag handling + - Empty result handling +``` + +## Prompt 7: Tree Command Structure +```text +Implement tree directory builder: +1. Function ```create_tag_combinations(tags: &[String], depth: usize) -> Vec>``` + - Generate all unique permutations up to specified depth + - Maintain alphabetical order in paths +2. Unit tests for: + - Depth limiting + - Combination validity + - Order preservation +``` + +## Prompt 8: Symlink Management +```text +Create symlink helper module: +1. Function ```create_symlink_tree(paths: Vec, target_dir: &Path) -> Result<()>``` + - Creates all required directories + - Atomic symlink creation + - Cross-platform compatibility stubs +2. Error handling: + - Clean path in error messages + - Permission checks +3. Unit tests for: + - Directory structure validation + - Symlink safety checks +``` + +# Phase 4: Error Handling +## Prompt 9: Error Type Unification +```text +Create unified error type: +1. Enum ```FileTagsError``` with variants for all error cases +2. Implement ```From``` traits for IO/parsing errors +3. Consistent error formatting: + - Machine-readable when needed + - User-friendly messages +4. Unit tests for error propagation +``` + +# Phase 5: Final Integration +## Prompt 10: CLI Wiring +```text +Integrate all components: +1. Complete command implementations +2. Add proper error handling +3. Configure --help output +4. Final integration tests: + - All commands together + - Cross-command file operations + - Stress tests with large filesets +``` + +# Phase 6: Optimization +## Prompt 11: Performance Pass +```text +Optimize hot paths: +1. Zero-copy parsing where possible +2. Preallocate buffers +3. Lazy evaluation of expensive operations +4. Benchmarks for critical operations +5. Unit test preservation diff --git a/spec.md b/spec.md new file mode 100644 index 0000000..05dac27 --- /dev/null +++ b/spec.md @@ -0,0 +1,184 @@ +# filetags-rs Technical Specification + +## Overview +filetags-rs is a command-line tool written in Rust for managing tags in file and directory names. Tags are embedded directly in filenames using a specific delimiter pattern. + +## Core Constants +- Tag delimiter: " -- " (space, double dash, space) +- Tag separator: " " (single space) +- Default tree depth: 3 + +## Tag Rules +- Tags must be valid Unicode strings +- Prohibited characters: NUL, ":", "/" +- Tags cannot contain the tag separator (space) +- Tags are stored in alphabetical order +- Duplicate tags are preserved but not added again +- Tags are case-sensitive + +## Commands + +### 1. List +**Usage:** `filetags list ` + +**Behavior:** +- Lists all unique tags found in the specified files +- Output is just the tags themselves, one per line +- No structural formatting (like JSON) is applied +- Empty files (no tags) produce no output + +**Example:** +```bash +$ filetags list "document -- tag1 tag2.pdf" "notes -- tag2 tag3.txt" +tag1 +tag2 +tag3 +``` + +### 2. Add +**Usage:** `filetags add --tag= [--tag=...] ` + +**Behavior:** +- Adds specified tags to files +- Merges with existing tags +- Sorts all tags alphabetically +- Ignores duplicate tags +- Preserves the original file extension + +**Example:** +```bash +$ filetags add --tag=work --tag=draft document.pdf +# Result: document -- draft work.pdf +``` + +### 3. Remove +**Usage:** `filetags remove --tag= [--tag=...] ` + +**Behavior:** +- Removes specified tags from files +- Preserves remaining tags in alphabetical order +- Silently ignores requests to remove non-existent tags +- Preserves the original file extension + +**Example:** +```bash +$ filetags remove --tag=draft "document -- draft work.pdf" +# Result: document -- work.pdf +``` + +### 4. Tree +**Usage:** `filetags tree --dir= [--depth=] ` + +**Parameters:** +- `--dir`: Target directory for creating the tree structure +- `--depth`: Maximum depth of the tree (default: 3) + +**Behavior:** +- Creates a directory tree based on file tags +- Creates symlinks at leaf nodes pointing to the original file +- For files with no tags, creates only a root-level symlink +- Creates all possible tag combinations up to specified depth +- Maintains alphabetical order in path components + +**Example:** +For file "document -- tag1 tag2.pdf": +``` +target_dir/ +├── document.pdf -> /path/to/document -- tag1 tag2.pdf +├── tag1/ +│ ├── document.pdf -> /path/to/document -- tag1 tag2.pdf +│ └── tag2/ +│ └── document.pdf -> /path/to/document -- tag1 tag2.pdf +└── tag2/ + ├── document.pdf -> /path/to/document -- tag1 tag2.pdf + └── tag1/ + └── document.pdf -> /path/to/document -- tag1 tag2.pdf +``` + +## Error Handling + +### Validation Errors +- Invalid characters in tags +- Empty tags +- Missing required arguments +- Invalid depth value for tree command +- Non-existent target directory + +### Runtime Errors +- File permission issues +- Symlink creation failures +- File reading/writing failures +- Directory creation failures + +All errors should: +- Print clear error messages to stderr +- Use appropriate error codes +- Include the specific file/tag that caused the error +- Exit with non-zero status + +## Testing Strategy + +### Unit Tests +1. Tag validation + - Character restrictions + - Length restrictions + - Delimiter handling + - Separator handling + +2. Tag operations + - Adding tags + - Removing tags + - Sorting tags + - Duplicate handling + - Case sensitivity + +3. Filename parsing + - Splitting into base name and tags + - Extension handling + - Edge cases (no tags, multiple delimiters) + +### Integration Tests +1. Command execution + - All commands with various combinations of arguments + - Error cases + - Edge cases + +2. File system operations + - File creation/modification + - Directory operations + - Symlink handling + - Permission handling + +3. Tree structure creation + - Various depths + - Different tag combinations + - Edge cases (no tags, max depth) + +### Property-Based Tests +- Filename roundtrip (parse → modify → serialize) +- Tag ordering invariants +- Unicode handling +- Path manipulation safety + +## Performance Considerations +- Efficient string manipulation for filename parsing +- Minimal allocations in hot paths +- Proper error type design to avoid allocations +- Efficient directory traversal for tree command +- Proper buffer sizes for file operations + +## Security Considerations +- Proper handling of symbolic links +- Path traversal prevention +- Proper permission checking +- Safe handling of Unicode filenames +- Proper escaping of special characters + +## Future Considerations +- Configurable delimiters +- Tag hierarchies +- Tag aliases +- Case-insensitive option +- Bulk operations +- Regular expression support +- Tag statistics and metadata