tennis

repository·main·Indexed 21 days ago

https://github.com/gurgeous/tennis

A Rust-based CLI tool for printing stylish, auto-formatted, and colorized tables in the terminal from CSV, JSON, and SQLite data. Version 0.7.1 supports features such as zebra striping, custom border styles, column width adjustments (-b, -bb, -bbb), data filtering, sorting, and color scales for numeric data.

Tokens
12.3K
Snippets
44
Records
61
Agent score
72%

What's inside tennis

  1. Supported file formats and data types

    main

    Tennis automatically detects input formats based on file extensions and the first few bytes of the file.

    • CSV/TSV/Delimited: Automatically sniffs delimiters (commas, tabs, semicolons, pipes, etc.). Use -d, --delimiter <char> to override.
    • JSON: Supports full arrays of objects, JSONL/NDJSON, or single JSON objects (where keys become columns).
    • SQLite: Reads via the external sqlite3 CLI. Use --table <table_name> to specify a table; otherwise, it attempts to auto-detect one.

    Data Features:

    • Numeric Formatting: Automatically detects and formats/aligns integers and floats. Use --vanilla to disable this.
    • Color Scales: Add color gradients to columns using --scale <headers> (red-to-green) or --rscale <headers> (green-to-red).
  2. Install Tennis

    main

    You can install tennis via Homebrew on macOS, download pre-built binaries for Linux, or build it from source using Cargo.

    ### Brew/macOS
    ```sh
    $ brew install gurgeous/tap/tennis

    Build from source

    $ mise trust && mise install
    $ cargo build -p tennis-cli
  3. Customize column width (Big, Bigger, Biggest)

    main

    Tennis automatically fits tables to your terminal width, but you can manually enlarge specific columns using the following flags. Note that -bb and -bbb may cause the table to overflow the terminal width, so it is recommended to use them with the --pager (-p) option.

    • -b <headers>: Make columns Bigger (still attempts to fit terminal width).
    • -bb <headers>: Make columns BIGGER (p90 width, likely to overflow).
    • -bbb <headers>: Make columns BIGGEST (full width, likely to overflow).
    • --width <width>: Manually set table width (e.g., --width 1000 or --width max).
    Use `-b` (big), `-bb` (bigger) and `-bbb` (biggest) to enlarge a specific column.
  4. Use `SortKey` for structured sorting

    main

    A SortKey defines how a specific column should be treated during a sort operation. It consists of a column index and a SortKind.

    Structure:

    • index: usize: The position of the column in the row.
    • kind: SortKind: The comparison logic to apply.

    SortKind variants:

    • Natural: Case-insensitive natural sort (e.g., 'abc' == 'ABC', 'a2' < 'a10').
    • Numeric(ColumnType): Numeric comparison using f64. Supports various ColumnType values, including Percent (which handles the % character).
  5. How column statistics are calculated in `--peek`

    main

    The --peek command infers the ColumnType to determine how min and max values are calculated and formatted:

    Column TypeLogic for Min/Max
    intParses values as i128. Uses comma separators (e.g., 1,000) unless --vanilla is used.
    floatParses values as f64. Formats to the specified number of --digits decimal places.
    percentParses values by stripping the % suffix. Formats as X.XXX%.
    stringCalculates the minimum and maximum visual width of the strings in the column.

    Note on Empty Columns: If a column contains no data, the min and max fields will display a placeholder (typically ).

  6. Use the `Record` trait for automatic table generation

    main

    By implementing the Record trait (usually via #[derive(Record)]) on a struct, you can automatically generate tables with correct headers and styling. You can use the #[tennis(...)] attribute to configure the table directly on the struct.

    Field Attributes

    • #[tennis(rename = "NewName")]: Changes the column header name.
    • #[tennis(big)], #[tennis(bigger)], #[tennis(biggest)]: Sets the column width mode.
    • #[tennis(scale = "scale_name")]: Applies a color scale to the field.
    • #[tennis(skip)]: Excludes the field from the table.

    Struct Attributes

    • #[tennis(title = "...")]: Sets the table title.
    • #[tennis(footer = "...")]: Sets the table footer.
    • #[tennis(border = "...")]: Sets the border style.
    • #[tennis(width = ...)]: Sets the table width.
    • #[tennis(digits = ...)]: Sets float precision.
    • #[tennis(zebra, row_numbers, vanilla, titleize)]: Toggles boolean options.
    • #[tennis(hyperlinks = bool)]: Toggles hyperlink support.
    • #[tennis(crate_path = "...")]: Specifies the path to the crate for macro expansion.
    #[derive(crate::Record)]
    #[tennis(
      title = "People",
      footer = "done",
      border = "basic",
      width = 72,
      digits = 2,
      zebra,
      row_numbers,
      vanilla,
      titleize,
      hyperlinks = false
    )]
    struct Person {
      #[tennis(rename = "Name")]
      name: String,
      #[tennis(biggest)]
      notes: String,
      #[tennis(scale = "green_red")]
      score: u32,
      #[tennis(skip)]
      _internal_id: String,
    }
    
    // Usage:
    let people = [Person { ... }];
    let table = Table::builder().load_records(people).build().unwrap();
  7. Supported input formats

    main

    The tennis CLI supports three primary input data formats. The tool automatically detects the format based on file extensions or content heuristics.

    Supported Formats

    • CSV: Detected via .csv or .tsv extensions, or as the default fallback.
    • JSON: Detected via .json, .jsonl, or .ndjson extensions, or if the file content starts with { or [ after whitespace.
    • Sqlite: Detected via .db, .sqlite, or .sqlite3 extensions, or if the file contains the SQLite format 3 magic number.
  8. View data preview with --peek

    main

    The --peek flag allows you to inspect the raw data structure or a simplified version of the input before full table transformation and rendering occurs. This is useful for debugging input formats or verifying data loading without the overhead of complex table styling.

    tennis data.csv --peek
  9. Use a pager for large tables

    main

    If a table is too large for the terminal screen, you can pipe the output to a pager (like less). Tennis will automatically use the PAGER environment variable if set, otherwise it defaults to less -RS.

    Enable the pager using the --pager flag.

    tennis large_data.csv --pager
  10. Use the tennis CLI to process data

    main

    The tennis CLI tool allows you to load, transform, and render tabular data from various formats (CSV, JSON, SQLite) into formatted tables in your terminal. It supports filtering, sorting, selecting columns, and various visual styling options.

    Basic Usage

    From a file:

    tennis data.csv

    From stdin:

    cat data.json | tennis

    From SQLite:

    tennis path/to/database.db --table users

    Data Transformation

    You can chain several transformations to manipulate the data before it is rendered:

    • Filter: Keep rows where any cell matches a case-insensitive string.
      • --filter <pattern>
    • Sort: Sort by one or more columns (supports natural/numeric sorting).
      • --sort <column_name>
      • Use --reverse to reverse the sort order.
    • Select/Deselect: Limit the columns displayed.
      • --select <col1,col2>
      • --deselect <col1>
    • Head/Tail: Limit the number of rows.
      • --head <n>
      • --tail <n>
    • Shuffle: Randomize row order.
      • --shuffle

    Visual Styling

    Customize the appearance of the output table:

    • Themes & Colors:
      • --theme <theme_name>
      • --color <mode>
      • --zebra (enables zebra striping)
      • --vanilla (minimalist output)
    • Borders & Titles:
      • --border <style>
      • --title <text>
      • --footer <text>
    • Column Scaling (Color Scales):
      • Apply color gradients to columns based on values.
      • --scale <column> (Red-to-Green scale)
      • --rscale <column> (Green-to-Red scale)
    • Sizing:
      • --width <number> (fixed width)
      • --big, --bigger, --biggest (increase font/cell size)
      • --digits <n> (set decimal precision)
    # Example: Filter for 'Alice', sort by 'score' descending, and select only 'name' and 'score'
    tennis data.csv --filter Alice --sort score --reverse --select name,score
  11. Use the `tennis --peek` command

    main

    The --peek command provides a quick summary of a dataset. It renders two distinct sections:

    1. Sample View: A preview of the first 5 rows of the data (or fewer if the dataset is small). If there are more rows than the sample size, a footer like … 10 more row(s) … is displayed.
    2. Stats View: A summary table containing metadata for every column, including:
      • column: The header name.
      • type: The inferred data type (int, float, percent, or string).
      • fill: The percentage of non-empty rows.
      • uniq: The count of unique non-empty values.
      • min: The minimum value (formatted based on type).
      • max: The maximum value (formatted based on type).

    This command is useful for verifying data integrity and understanding the distribution of values before performing full operations.

  12. Generate shell completion scripts for tennis

    main

    The tennis CLI supports generating shell completion scripts for Bash and Zsh. These scripts enable tab-completion for flags, arguments, and specific values.

    Supported shells:

    • Bash
    • Zsh

    When generating completions, the following features are included:

    • Flag Completion: Autocompletes short (-t) and long (--title) flags, including aliases.
    • Value Completion: Autocompletes specific allowed values for certain flags (e.g., --width supports auto, min, max).
    • File Extension Globbing: Provides completion for common data file extensions: csv, tsv, db, json, jsonl, ndjson, sqlite, and sqlite3.
    • Special Flag Support: Includes support for non-standard multi-letter short flags like -bb and -bbb (used for big2 and big3 modes).