Skip to content

Latest commit

 

History

History
317 lines (270 loc) · 8.72 KB

File metadata and controls

317 lines (270 loc) · 8.72 KB

Developing Plugins for xfetch

xfetch plugins are standalone executables that communicate with the core via stdin/stdout using a JSON protocol. This document describes the protocol, the required binary naming conventions, and best practices for creating your own plugin.

The shared protocol crate is maintained in xfetch-cli/api.

Official plugins and third-party plugins are expected to use this crate instead of reimplementing protocol parsing manually.

Table of Contents

How It Works

  1. xfetch discovers the plugin binary (see Discovery).
  2. xfetch spawns the plugin process.
  3. xfetch writes a JSON request to the plugin's stdin.
  4. The plugin processes the request and writes a JSON response to stdout.
  5. xfetch reads the response and uses it for rendering.
  6. Errors are written to stderr; the plugin exits with a non-zero status on failure.

Binary Naming

The plugin binary must follow this naming convention so xfetch can discover it:

xfetch-plugin-<name>
Platform Example
Linux / macOS xfetch-plugin-animate-logo
Windows xfetch-plugin-animate-logo.exe

The Cargo.toml name field should follow the same convention:

[package]
name = "xfetch-plugin-<name>"
version = "0.1.0"
edition = "2024"

Discovery

When running a plugin, xfetch searches for the binary in the following order:

  1. Explicit path from the configuration (if provided).
  2. PATH environment variable, looking for xfetch-plugin-<name>.
  3. User plugin directory: ~/.config/xfetch/plugins/.
  4. Workspace target directory of the plugins repository: target/release/.
  5. Legacy development path: ./plugins/<name>/target/release/.

Protocol

The plugin protocol uses JSON over stdin/stdout. The plugin reads exactly one JSON object from stdin and writes exactly one JSON object to stdout.

Request Format

{
  "version": 1,
  "kind": "<plugin_kind>",
  "lines": ["line 1", "line 2"],
  "frames": [
    ["frame 1 line 1", "frame 1 line 2"],
    ["frame 2 line 1", "frame 2 line 2"]
  ],
  "args": {
    "fps": 12,
    "duration_ms": 1200,
    "loop": false,
    "style": "sweep"
  }
}
Field Type Description
version u32 Protocol version (currently 1).
kind string Plugin type. Currently only "logo_animation" is supported.
lines array[string] Logo ASCII art, one line per element.
frames array[array[string]] or null Optional pre-loaded frame sets for frame-based animation.
args object Plugin-specific arguments from the user config.

Response Format

{
  "frames": [
    {
      "delay_ms": 83,
      "lines": ["colored line 1", "colored line 2"]
    }
  ]
}
Field Type Description
frames array[Frame] Array of animation frames (required). Must not be empty.

Frame Object

Field Type Description
delay_ms u64 Milliseconds to display this frame before advancing.
lines array[string] Frame content (may include ANSI escape codes for color).

Example Plugin

The animate-logo plugin is the reference implementation. Its source is at plugins/animate-logo/src/main.rs.

Minimal plugin skeleton in Rust using the shared crate:

use xfetch_plugin_api::{
    read_info_plugin_args_or_default,
    write_info_lines,
};

#[derive(Debug, Default, serde::Deserialize)]
struct PluginArgs {}

fn main() {
    let _args = match read_info_plugin_args_or_default::<PluginArgs>() {
        Ok(value) => value,
        Err(err) => {
            eprintln!("{}", err);
            std::process::exit(1);
        }
    };

    if let Err(err) = write_info_lines(vec!["hello from plugin".to_string()]) {
        eprintln!("{}", err);
        std::process::exit(1);
    }
}

Testing

Test your plugin manually by writing a request file and piping it:

echo '{"version":1,"kind":"logo_animation","lines":["hello"],"args":{"fps":12}}' \
  | ./target/release/xfetch-plugin-my-plugin

You can also install it locally and test it with xfetch:

xfetch plugin install my-plugin
xfetch

Contribution Guidelines

Adding a Plugin

  1. Create a new directory under plugins/ named after your plugin (e.g., plugins/my-plugin/).
  2. Include a Cargo.toml with the package name following the xfetch-plugin-<name> convention.
  3. Implement the plugin with a src/main.rs or src/lib.rs that handles the JSON protocol.
  4. Add a README.md documenting the plugin's features, configuration options, and available styles.
  5. Add sample configs and assets if applicable (see plugins/animate-logo/ for reference).

Code Standards

  • Write all code, comments, and documentation in English.
  • Prefer the shared xfetch-plugin-api crate for protocol types and JSON IO.
  • Handle protocol and output errors explicitly — write errors to stderr and exit with non-zero.
  • Do not use external display or terminal libraries; the core handles rendering.
  • Keep the plugin focused on a single responsibility (e.g., logo animation).
  • Minimize dependencies to keep build times fast.

Pull Request Process

  1. Fork the repository and create a feature branch.
  2. Implement your plugin following the guidelines above.
  3. Ensure cargo build --release succeeds for your plugin.
  4. Add an entry for your plugin in README.md.
  5. Submit a pull request with a clear description of your plugin.
  6. Maintainers will review the protocol compliance and code quality.

What Not to Do

  • Do not modify core xfetch source files unless the plugin protocol itself needs changes.
  • Do not use network calls or file I/O in animation plugins (they should be pure transformations).
  • Do not embed binaries or large assets in the plugin source.
  • Do not introduce platform-specific code without fallbacks.