# psource **p**rint **source** code CLI tool to pretty print source code to stdout or directly to the clipboard. The tool is created to quickly provide source code context to a large language model (LLM). [![crates.io version](https://img.shields.io/crates/v/psource)](https://crates.io/crates/psource) [![AUR version](https://img.shields.io/aur/version/psource-git)](https://aur.archlinux.org/packages/psource-git) [![build and test](https://img.shields.io/github/actions/workflow/status/frederikstroem/psource/build_and_test.yml?label=build%20and%20test)](https://github.com/frederikstroem/psource/actions/workflows/build_and_test.yml) [![docs.rs](https://img.shields.io/docsrs/psource)](https://docs.rs/psource)
--- ⚠️ This tool is still in early development, expect breaking changes. ⏳️ See [CHANGELOG.md](CHANGELOG.md) for the latest changes and [roadmap](CHANGELOG.md#unreleased). --- ## Install ### Install using Cargo Make sure to have Cargo installed and PATH configured. See [The Rust Programming Language - Installing Binaries with cargo install](https://doc.rust-lang.org/book/ch14-04-installing-binaries.html). #### Install from crates.io ```bash cargo install psource ``` #### Install from GitHub source ```bash cargo install --git https://github.com/frederikstroem/psource.git ``` #### Install from local source ```bash cargo install --path . ``` ### Arch Linux #### Install via the Arch User Repository (AUR) Install using your favorite AUR helper, e.g., [paru](https://github.com/Morganamilo/paru): ```bash paru -S psource-git ``` ## Configuration The tool can be configured using a configuration file. The configuration file is a simple TOML file with the following structure: ```toml # Copy the source code to the clipboard instead of printing it to stdout (default: false) clipboard_is_default_output_target = false ``` psource will look for a configuration file in the following `$HOME/.config/psource/config.toml`. ## Get started Get help: ```plaintext $ psource --help CLI tool to pretty print source code to stdout or directly to the clipboard. Skips binary files. Usage: psource [OPTIONS] ... Arguments: ... Input files and directories Options: -s, --stdout Print the source code to stdout -c, --copy Copy the source code to the clipboard -a, --ancestry Display the file's ancestry in the output path by including the specified number of parent directories relative to the current working directory, or 0 to omit the ancestry [default: 1] -g, --git-ancestry Display the file's ancestry in the output path, including parent directories from the current working directory within a Git repository to its root, unlike the fixed number specified by the 'ancestry' option -e, --exclude Exclude files and directories matching the specified glob pattern -h, --help Print help -V, --version Print version ``` ### Example: Add a to_uppercase utils function to a Rust project We have created a simple Rust project with a `lib.rs` file and a `main.rs` file. **main.rs:** ```rust mod lib; fn main() { let message = lib::greet("Rustacean"); println!("{}", message); } ``` **lib.rs:** ```rust pub fn greet(name: &str) -> String { format!("Hello, {}!", name) } ``` We want to add a `to_uppercase` function to a new `utils.rs` file and use it in `lib.rs`. We can use the `psource` tool to quickly copy the relevant code to the clipboard. `cd` into the project root directory and run: ```bash psource -c src ``` This command will place the following content onto your clipboard: ```plaintext ⚫ /simple_rust_program/src/main.rs mod lib; fn main() { let message = lib::greet("Rustacean"); println!("{}", message); } ⚫ /simple_rust_program/src/lib.rs pub fn greet(name: &str) -> String { format!("Hello, {}!", name) } ``` You can now prompt the LLM with the following: ```plaintext Please add a to_uppercase function to a new utils.rs file. Modify the greet function in lib.rs to use the to_uppercase function. Source code: ⚫ /simple_rust_program/src/main.rs mod lib; fn main() { let message = lib::greet("Rustacean"); println!("{}", message); } ⚫ /simple_rust_program/src/lib.rs pub fn greet(name: &str) -> String { format!("Hello, {}!", name) } ``` The LLM should be able to help you complete the task. **Note:** This is a very simple example but scales really well to large projects. The limit largely depends on the LLM's capabilities and its context window. I've had great success with [OpenAI's GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo), used with an alternative front-end utilizing the API, I can recommend [chatgpt-web](https://github.com/Niek/chatgpt-web). GPT-4 Turbo has a context window of 128,000 tokens, and I've also found setting a sample temperature of ±0.6 to work well for code development tasks. **Tip:** A file tree structure can sometimes help the LLM to better understand the context of the code. For such a task, I recommend using [eza](https://github.com/eza-community/eza) with the `--tree` option. To pipe it to the clipboard, a tool like [xsel](https://github.com/kfish/xsel) can be used, e.g., `eza --tree | xsel -b`. ## Known issues ### Speeding up the copy to clipboard process Due to a bug in the software supply chain, the `-c` option requires psource to wait for some time before exiting, else the clipboard will not be updated on some systems (discovered on KDE Plasma running X11).[[1]](https://github.com/1Password/arboard/issues/114)[[2]](https://github.com/sigoden/aichat/issues/160) To speed up the process, the `psource` stdout can be piped to a clipboard tool like [xsel](https://github.com/kfish/xsel), e.g., `psource src | xsel -b`. ### Exclude option not working The exclude option has some rough edges right now and future improvements are planned. If the `*` exclude patterns are not working as excepted, try to quote the pattern, e.g., `psource Cargo.toml README.md -e 'Cargo*'` If you need to exclude a file within a subdirectory, consider using a glob pattern such as `psource src -e '*/main.rs'` to target `main.rs` in any immediate subdirectory, or `psource src -e '**/main.rs'` to match all `main.rs` files across all levels of subdirectories.