diff --git a/README.md b/README.md index 332c663..10ae2de 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,19 @@ This will output the contents of every file, with each file preceded by its rela files-to-prompt path/to/directory --include-hidden ``` +- `--ignore-files-only`: Include directory paths which would otherwise be ignored by an `--ignore` pattern. + + ```bash + files-to-prompt path/to/directory --ignore-files-only --ignore "*dir*" + ``` + - `--ignore-gitignore`: Ignore `.gitignore` files and include all files. ```bash files-to-prompt path/to/directory --ignore-gitignore ``` -- `--ignore `: Specify one or more patterns to ignore. Can be used multiple times. +- `--ignore `: Specify one or more patterns to ignore. Can be used multiple times. Patterns may match file names and directory names, unless you also specify `--ignore-files-only`. ```bash files-to-prompt path/to/directory --ignore "*.log" --ignore "temp*" ``` @@ -138,6 +144,19 @@ Contents of file3.txt --- ``` +If you run `files-to-prompt my_directory --ignore "sub*"`, the output will exclude all files in `subdirectory/` (unless you also specify `--ignore-files-only`): + +``` +my_directory/file1.txt +--- +Contents of file1.txt +--- +my_directory/file2.txt +--- +Contents of file2.txt +--- +``` + ### Claude XML Output Anthropic has provided [specific guidelines](https://docs.anthropic.com/claude/docs/long-context-window-tips) for optimally structuring prompts to take advantage of Claude's extended context window. diff --git a/files_to_prompt/cli.py b/files_to_prompt/cli.py index 3ce3f19..ad4a0e7 100644 --- a/files_to_prompt/cli.py +++ b/files_to_prompt/cli.py @@ -68,6 +68,7 @@ def process_path( path, extensions, include_hidden, + ignore_files_only, ignore_gitignore, gitignore_rules, ignore_patterns, @@ -102,6 +103,12 @@ def process_path( ] if ignore_patterns: + if not ignore_files_only: + dirs[:] = [ + d + for d in dirs + if not any(fnmatch(d, pattern) for pattern in ignore_patterns) + ] files = [ f for f in files @@ -133,6 +140,11 @@ def process_path( is_flag=True, help="Include files and folders starting with .", ) +@click.option( + "--ignore-files-only", + is_flag=True, + help="--ignore option only ignores files", +) @click.option( "--ignore-gitignore", is_flag=True, @@ -171,6 +183,7 @@ def cli( paths, extensions, include_hidden, + ignore_files_only, ignore_gitignore, ignore_patterns, output_file, @@ -223,6 +236,7 @@ def cli( path, extensions, include_hidden, + ignore_files_only, ignore_gitignore, gitignore_rules, ignore_patterns, diff --git a/tests/test_files_to_prompt.py b/tests/test_files_to_prompt.py index 24d7234..07dd53e 100644 --- a/tests/test_files_to_prompt.py +++ b/tests/test_files_to_prompt.py @@ -88,7 +88,7 @@ def test_multiple_paths(tmpdir): def test_ignore_patterns(tmpdir): runner = CliRunner() with tmpdir.as_cwd(): - os.makedirs("test_dir") + os.makedirs("test_dir", exist_ok=True) with open("test_dir/file_to_ignore.txt", "w") as f: f.write("This file should be ignored due to ignore patterns") with open("test_dir/file_to_include.txt", "w") as f: @@ -100,12 +100,27 @@ def test_ignore_patterns(tmpdir): assert "This file should be ignored due to ignore patterns" not in result.output assert "test_dir/file_to_include.txt" not in result.output - result = runner.invoke(cli, ["test_dir", "--ignore", "file_to_ignore.*"]) + os.makedirs("test_dir/test_subdir", exist_ok=True) + with open("test_dir/test_subdir/any_file.txt", "w") as f: + f.write("This entire subdirectory should be ignored due to ignore patterns") + result = runner.invoke(cli, ["test_dir", "--ignore", "*subdir*"]) assert result.exit_code == 0 - assert "test_dir/file_to_ignore.txt" not in result.output - assert "This file should be ignored due to ignore patterns" not in result.output + assert "test_dir/test_subdir/any_file.txt" not in result.output + assert ( + "This entire subdirectory should be ignored due to ignore patterns" + not in result.output + ) assert "test_dir/file_to_include.txt" in result.output assert "This file should be included" in result.output + assert "This file should be included" in result.output + + result = runner.invoke( + cli, ["test_dir", "--ignore", "*subdir*", "--ignore-files-only"] + ) + assert result.exit_code == 0 + assert "test_dir/test_subdir/any_file.txt" in result.output + + result = runner.invoke(cli, ["test_dir", "--ignore", ""]) def test_specific_extensions(tmpdir):