-
-
Save code-yeongyu/9004d32faca17b8e691e0d6836f1c94d to your computer and use it in GitHub Desktop.
print given files marked with xml-like tags, for LLMs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Enable globstar for ** pattern support | |
shopt -s globstar 2>/dev/null | |
show_help() { | |
cat << 'EOF' | |
fp is an interactive file printer for Large Language Models. | |
It wraps file contents in LLM-friendly XML format, enabling efficient context | |
sharing with AI assistants for code review, debugging, and development tasks. | |
Author: YeonGyu Kim <[email protected]> https://github.com/code-yeongyu | |
Usage: fp [options] [file|directory|pattern]... | |
INPUT | |
file Output a single file | |
directory/ Output all files in directory recursively | |
*.ext Output all files matching the pattern | |
**/*.ext Output all files matching pattern recursively | |
OPTIONS | |
-h, --help Show this message | |
OUTPUT FORMAT | |
Files are wrapped in XML tags for optimal LLM processing: | |
<files> | |
<file path="relative/or/absolute/path"> | |
... file contents ... | |
</file> | |
</files> | |
EXAMPLES | |
fp file.txt Output single file | |
fp src/ Output all files in directory recursively | |
fp *.js Output all JavaScript files | |
fp src/**/*.py Output all Python files under src (recursive) | |
fp main.go utils/*.go Output multiple files and patterns | |
NOTES | |
- Paths are shown relative to current directory when possible | |
- Supports glob patterns with ** for recursive matching | |
- No output is produced if no files match the pattern | |
- Empty arguments show this help message | |
ENVIRONMENT VARIABLES | |
None required. Uses standard shell globbing. | |
EOF | |
} | |
main() { | |
local file_found=0 | |
local output="" | |
# Check for help flag or no arguments | |
if [ $# -eq 0 ] || [ "$1" = "--help" ] || [ "$1" = "-h" ]; then | |
show_help | |
exit 0 | |
fi | |
# Process all arguments - bash will expand wildcards before passing them | |
for path in "$@"; do | |
local result | |
result=$(process_path "$path") | |
if [ -n "$result" ]; then | |
file_found=1 | |
output="${output}${result}" | |
fi | |
done | |
# Only print output if files were found | |
if [ $file_found -eq 1 ]; then | |
printf "<files>\n" | |
printf "%s" "$output" | |
printf "</files>\n" | |
fi | |
} | |
get_display_path() { | |
local path="$1" | |
local cwd=$(pwd) | |
# Check if path is a child of cwd | |
if [[ "$path" == "$cwd"/* ]]; then | |
# Use relative path | |
echo "${path#$cwd/}" | |
else | |
# Use absolute path | |
echo "$path" | |
fi | |
} | |
print_file() { | |
local file_path="$1" | |
local display_path | |
display_path=$(get_display_path "$file_path") | |
printf '<file path="%s">\n' "$display_path" | |
cat "$file_path" 2>/dev/null | |
printf "</file>\n" | |
} | |
process_path() { | |
local path="$1" | |
local resolved_path | |
resolved_path=$(realpath "$path" 2>/dev/null || printf "%s" "$path") | |
if [ -f "$resolved_path" ]; then | |
print_file "$resolved_path" | |
elif [ -d "$resolved_path" ]; then | |
find "$resolved_path" -type f 2>/dev/null | sort | while IFS= read -r file; do | |
print_file "$file" | |
done | |
fi | |
} | |
# Call main with all arguments | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment