Rust library for putting things in a grid

Overview

rust-term-grid term-grid on crates.io Minimum Rust Version 1.31.0 Build status

This library arranges textual data in a grid format suitable for fixed-width fonts, using an algorithm to minimise the amount of space needed.

View the Rustdoc

Installation

This crate works with Cargo. Add the following to your Cargo.toml dependencies section:

[dependencies]
term_grid = "0.2"

The earliest version of Rust that this crate is tested against is Rust v1.31.0.

Usage

This library arranges textual data in a grid format suitable for fixed-width fonts, using an algorithm to minimise the amount of space needed. For example:

use term_grid::{Grid, GridOptions, Direction, Filling, Cell};

let mut grid = Grid::new(GridOptions {
    filling:     Filling::Spaces(1),
    direction:   Direction::LeftToRight,
});

for s in &["one", "two", "three", "four", "five", "six", "seven",
           "eight", "nine", "ten", "eleven", "twelve"]
{
    grid.add(Cell::from(*s));
}

println!("{}", grid.fit_into_width(24).unwrap());

Produces the following tabular result:

one  two three  four
five six seven  eight
nine ten eleven twelve

Creating a grid

To add data to a grid, first create a new Grid value, and then add cells to them with the add method.

There are two options that must be specified in the GridOptions value that dictate how the grid is formatted:

  • filling: what to put in between two columns - either a number of spaces, or a text string;
  • direction, which specifies whether the cells should go along rows, or columns:
    • Direction::LeftToRight starts them in the top left and moves rightwards, going to the start of a new row after reaching the final column;
    • Direction::TopToBottom starts them in the top left and moves downwards, going to the top of a new column after reaching the final row.

Displaying a grid

When display a grid, you can either specify the number of columns in advance, or try to find the maximum number of columns that can fit in an area of a given width.

Splitting a series of cells into columns - or, in other words, starting a new row every n cells - is achieved with the fit_into_columns method on a Grid value. It takes as its argument the number of columns.

Trying to fit as much data onto one screen as possible is the main use case for specifying a maximum width instead. This is achieved with the fit_into_width method. It takes the maximum allowed width, including separators, as its argument. However, it returns an optional Display value, depending on whether any of the cells actually had a width greater than the maximum width! If this is the case, your best bet is to just output the cells with one per line.

Cells and data

Grids do not take Strings or &strs - they take Cells.

A Cell is a struct containing an individual cell’s contents, as a string, and its pre-computed length, which gets used when calculating a grid’s final dimensions. Usually, you want the Unicode width of the string to be used for this, so you can turn a String into a Cell with the .into() method.

However, you may also want to supply your own width: when you already know the width in advance, or when you want to change the measurement, such as skipping over terminal control characters. For cases like these, the fields on the Cell values are public, meaning you can construct your own instances as necessary.

Comments
  • Potential performance improvements

    Potential performance improvements

    I have yet to test if this actually improves performance in Rust. If it does, this commit should close #5. This isn't exactly the best code in the world, so you might want to improve on it.

    opened by ArniDagur 2
  • Grid with 1 item fails to render

    Grid with 1 item fails to render

    If you only add one string to the grid, it will fail and return None. Here is the example code:

    extern crate term_grid;
    use term_grid::{Grid, GridOptions, Direction, Filling};
    
    fn main() {
        let mut grid = Grid::new(GridOptions {
            direction:  Direction::TopToBottom,
            filling:    Filling::Spaces(2),
        });
    
        for i in 0..1 {
            grid.add(format!("{}", 2_isize.pow(i)).into())
        }
    
        if let Some(grid_display) = grid.fit_into_width(40) {
            println!("{}", grid_display);
        }
        else {
            println!("Couldn't fit grid into 40 columns!");
        }
    }
    
    opened by kdar 2
  • Minor improvements and use of Rust idioms

    Minor improvements and use of Rust idioms

    This patch provides some minor improvements and the use of more idiomatic Rust in some areas of the code. IMHO it makes the code easier to understand 😄

    opened by joshleeb 1
  • Potential ways to optimize width_dimensions() algorithm

    Potential ways to optimize width_dimensions() algorithm

    See the following commit in my (rather poor) Python implementation of this algorithm: ArniDagur/guide-key.nvim@fbd9b5e

    As you can see, I tried both binary search and looping downwards from the theoretical maximum number of lines, to 1. Both seemed to improve performance, but there are almost certainly better ways to go about it.

    I thought about basing binary search hi/lows off of the theoretical maximum number of lines, but the problem there is that I'm not sure how to efficiently calculate the theoretical minimum. This occurs when the items are sorted from highest to lowest (or the other way around).

    @ogham I would love to hear your ideas and thoughts.

    opened by ArniDagur 0
  • Include license file in crate publication?

    Include license file in crate publication?

    Hi! I'm reviewing this crate for inclusion in Fuchsia, and our dependency tooling works best when there's a LICENSE file in the root of the crate upload, see regex for an example.

    The currently published version of this crate seems to exclude the license from the tarball: https://docs.rs/crate/term_grid/latest/source/Cargo.toml.orig, but I'm not seeing the equivalent on HEAD: https://github.com/ogham/rust-term-grid/blob/master/Cargo.toml#L7.

    Would it be possible to publish an updated version of the crate based on the current tip-of-tree? Thanks!

    opened by anp 0
  • Performance issue with the redundancy operations

    Performance issue with the redundancy operations

    https://github.com/ogham/rust-term-grid/blob/1cbc10f4fd641e49c20e72afbad3f850af51ab61/src/lib.rs#L319

    For this line of code, it will always update the value of widths[index], even if the value of it does not change. This introduces some redundant operations.

    If we change the code to this, we can eliminate these redundant operations.

    if widths[index] < cell.width{
         widths[index] = cell.width;
    }
    

    According to my tests, the average execution time decreased from 6.5s to 4.8s, which is a 1.37x speedup.

    Hope this information helps!

    opened by yyzdtccjdtc 0
  • Fixed the bugs in displaying the grid with `fit_into_width`

    Fixed the bugs in displaying the grid with `fit_into_width`

    These changes were initiated to fix the behavior of term-grid in uutils's ls, which uses term-grid 0.1.7 but can't upgrade to 0.2.0 due to the existence of these bugs.

    Ideally, I'd like to upgrade to 0.2.0, offloading a lot of padding/alignment code to term-grid instead.

    Things I've taken care of:

    • Fixed loop boundaries.
    • Allowed grid to try to utilize the maximum width it can, optimizing for line-count.

    Things I've not taken care of, yet:

    • I didn't create a test to make sure this behavior does not regress.
    • I didn't fix the other bug where terminal color-codes ruin the width calculation.
    opened by mtsoltan 4
  • Color codes ruin width calculation.

    Color codes ruin width calculation.

    uutils's ls --color re-calculates widths, passing them explicitly to cells, because terminal colors ruin the width calculation of term-grid.

    Ideally, term-grid should recognize color escape sequences and treat them as zero-width, or at least have a grid option which makes that possible, to allow out-of-the-box color handling.

    opened by mtsoltan 0
  • Make loop for `smallest_dimension_yet` inclusive

    Make loop for `smallest_dimension_yet` inclusive

    Closes https://github.com/ogham/rust-term-grid/issues/11

    Hi! Thanks for this great library! Like I mentioned in the issue, we would love to upgrade to a later version, but this is blocking us, so I thought I would implement it in a PR. It contains exactly the change in the issue.

    opened by tertsdiepraam 3
Releases(v0.2.0)
  • v0.2.0(Apr 26, 2020)

    Additions

    • Added right-aligned cells feature (PR #9)

    Changes

    • Remove not-very-helpful implementations of PartialEq and PartialOrd that were an implementation details that accidentally became public
    • Documentation wording changes and links
    • A teensy bit of code modernisation
    Source code(tar.gz)
    Source code(zip)
Owner
Benjamin Sago
Benjamin Sago
Putting a brain behind `cat`🐈‍⬛ Integrating language models in the Unix commands ecosystem through text streams.

smartcat (sc) Puts a brain behind cat! CLI interface to bring language models in the Unix ecosystem and allow power users to make the most out of llms

Emilien Fugier 28 Dec 2, 2023
A Rust library for drawing grid-based user interfaces using ASCII characters.

grux A library for drawing grid-based user interfaces using ASCII characters. // Provides a uniform interface for drawing to a 2D grid. use grux::Grid

Matan Lurey 4 Jan 10, 2023
A library for 3D grid coordinates: for games

Positioning rustdocs A library for manipulating coordinates on a 3D grid. This will contain code that I'll often end up repeating in games. Currently,

Samuel Schlesinger 7 Dec 6, 2022
Bevy Meshem is a Rust crate designed to provide meshing algorithms for voxel grids, enabling you to create cohesive 3D mesh structures from a grid of cubic voxels

Bevy Meshem Crates.io, docs Bevy Compatibility: Bevy Version bevy_meshem 0.11 main Bevy Meshem is a Rust crate designed to provide meshing algorithms

Adam 4 Aug 16, 2023
Grid-based drum sequencer plugin as MIDI FX in CLAP/VST3 format

dr-seq Grid-based drum sequencer plugin as MIDI FX in CLAP/VST3 format. WARNING: This project is in a very early state. So there is no guarantee for a

Oliver Rockstedt 6 Jan 29, 2023
Scouty is a command-line interface (CLI) to keep an eye on substrate-based chains and hook things up

scouty is a command-line interface (CLI) to keep an eye on substrate-based chains and hook things up

TurboFlakes 15 Aug 6, 2022
Brutally simple command line app for jotting things down

jot Brutally simple command line app for jotting things down. About jot lets you get things down before you forget, without fiddling folders, naming,

Alexander Alexandrov 1 Apr 8, 2022
Giddy up! Things are going to be wild.

Jocky - For controlling your horses Current Idea The idea is essentially to have a custom directory that writes immutable segments, this means only 2

Harrison Burt 3 Jan 7, 2023
Work out how far apart things should be (very quickly)

Kern determiner Work out how far apart things should be (very quickly) kerndeterminer is a Rust-based library for determining a kern value between two

Simon Cozens 10 Oct 29, 2022
Tool to copy things!

zp zp is a cli command to copy the contents of the source file or of the std output buffer to the clipboard. To use the zp, simply open your terminal

Gokul 26 Apr 22, 2023
A crate to help you copy things into raw buffers without invoking spooky action at a distance (undefined behavior).

?? presser Utilities to help make copying data around into raw, possibly-uninitialized buffers easier and safer. presser can help you when copying dat

Embark 131 Mar 16, 2023
ratlab is a programming platform designed loosely for hobbyist and masochist to analyse and design stuff and things that transform our world?

ratlab A programming language developed by Quinn Horton and Jay Hunter. ratlab is a programming platform designed loosely for hobbyists and masochists

Jay 10 Sep 4, 2023
A visual canvas and virtual machine for writing assembly to build cool things. Create machines and connect them together.

Visual Assembly Canvas A highly visual assembly editor, infinite canvas for wiring blocks and machines together, bytecode virtual machine runnable nat

Phoomparin Mano 31 Oct 11, 2023
An Azalea plugin with things that will probably trigger anticheats.

Azalea Hax An Azalea plugin with useful features that will probably trigger anticheats. Usage async fn handle(mut bot: Client, event: azalea::Event, s

null 4 Oct 17, 2023
A visual canvas and virtual machine for writing assembly to build cool things. Create machines and connect them together.

Visual Assembly Canvas A highly visual assembly editor, infinite canvas for wiring blocks and machines together, bytecode virtual machine runnable nat

Phoomparin Mano 32 Oct 11, 2023
A fork of criterion.rs to keep things afloat.

Criterion.rs Statistics-driven Microbenchmarking in Rust Getting Started | User Guide | Master API Docs | Released API Docs | Changelog | Criterion.rs

Boshen 5 May 7, 2024
Rust Imaging Library's Python binding: A performant and high-level image processing library for Python written in Rust

ril-py Rust Imaging Library for Python: Python bindings for ril, a performant and high-level image processing library written in Rust. What's this? Th

Cryptex 13 Dec 6, 2022
This library provides a convenient derive macro for the standard library's std::error::Error trait.

derive(Error) This library provides a convenient derive macro for the standard library's std::error::Error trait. [dependencies] therror = "1.0" Compi

Sebastian Thiel 5 Oct 23, 2023
Experimental engine agnostic 3D CSG library for game development written in Rust. Started as a port of csg.js to Rust.

brusher Experimental engine agnostic 3D CSG library for game development written in Rust. Started as a port of csg.js to Rust. ultimate goal My hope i

Brian Howard 17 Sep 4, 2024