Skip to content

Comments

[FEAT] Tubular Multiselect#320

Open
TomPlanche wants to merge 5 commits intomikaelmello:mainfrom
TomPlanche:tomPlanche/feat/tubular-multiselect
Open

[FEAT] Tubular Multiselect#320
TomPlanche wants to merge 5 commits intomikaelmello:mainfrom
TomPlanche:tomPlanche/feat/tubular-multiselect

Conversation

@TomPlanche
Copy link

Overview

This PR adds tabular formatting support to the MultiSelect prompt, allowing options with structured data to be displayed with properly aligned columns. This significantly improves readability when presenting multi-field data such as file listings, server information, or project metadata.

Motivation

When displaying options with multiple data fields, the current implementation shows them as plain text without alignment, making it difficult to:

  • Compare values across options (especially numbers)
  • Scan data quickly
  • Identify patterns in structured information

Before:

Select projects to clean:
> [x] copy_current_location: 898.95 KB (2025-10-12 15:41), /path1
  [x] summary-gen: 211.29 MB (2025-10-13 20:04), /path2
  [x] rona: 1.26 GB (2025-10-14 18:29), /path3

After:

Select projects to clean:
> [x] copy_current_location: 898.95 KB (2025-10-12 15:41), /path1
  [x] summary-gen:           211.29 MB (2025-10-13 20:04), /path2
  [x] rona:                  1.26 GB   (2025-10-14 18:29), /path3

Features

1. New tabular Module

  • ColumnConfig - Configure column separators and alignment
  • ColumnAlignment - Left or right alignment for each column
  • format_as_table() - Standalone function to format text into aligned columns
  • Full Unicode support using unicode-width crate

2. Flexible Column Configuration

Three ways to configure column separators:

// Default separator (single space)
ColumnConfig::new(ColumnAlignment::Left)

// Custom separator at creation
ColumnConfig::new_with_separator(": ", ColumnAlignment::Left)

// Set/replace separator (builder pattern)
ColumnConfig::new(ColumnAlignment::Left).separator(": ")

3. MultiSelect Integration

use inquire::{MultiSelect, tabular::{ColumnConfig, ColumnAlignment}};

let columns = vec![
    ColumnConfig::new_with_separator(": ", ColumnAlignment::Left),
    ColumnConfig::new(ColumnAlignment::Right),  // Right-aligned numbers
    ColumnConfig::new_with_separator(", ", ColumnAlignment::Left),
];

let ans = MultiSelect::new("Select items:", data)
    .with_tabular_columns(columns)
    .prompt()?;

Examples

Three comprehensive examples demonstrate the feature:

  1. multiselect_tabular.rs

    • Project selection with size/date/path
    • Package manager with version/size/description
    • File browser with permissions/size/date
  2. multiselect_tabular_separators.rs

    • Default separators demonstration
    • Custom separators demonstration
    • Builder pattern with .separator()
    • Raw vs formatted comparison

Use Cases

This feature is particularly valuable for:

  1. File and Directory Browsers - Display files with size, date, permissions
  2. System Monitoring Tools - Process lists with PID, memory, CPU usage
  3. Package Managers - Package lists with name, version, size
  4. Build Tools - Target selection with build time, size, status
  5. Database Tools - Record selection with multiple fields
  6. DevOps Tools - Server/service listings with metadata

Backward Compatibility

Fully backward compatible - This is an opt-in feature:

  • Existing code continues to work without changes
  • Default behavior unchanged
  • Only activated when with_tabular_columns() is called

Performance Considerations

  • Unicode-aware width calculations using unicode-width crate
  • Efficient single-pass column width calculation
  • Minimal allocations (reuses strings where possible)
  • No impact when feature is not used

Related Disscussion

#318 was my discussion.

Example Usage

use inquire::{MultiSelect, tabular::{ColumnConfig, ColumnAlignment}};

let servers = vec![
    "web-01: 192.168.1.10, 8080, Running",
    "api-gateway: 192.168.1.20, 3000, Running",
    "db-primary: 192.168.1.30, 5432, Stopped",
];

let columns = vec![
    ColumnConfig::new_with_separator(": ", ColumnAlignment::Left),
    ColumnConfig::new_with_separator(", ", ColumnAlignment::Right),
    ColumnConfig::new_with_separator(", ", ColumnAlignment::Right),
    ColumnConfig::new(ColumnAlignment::Left),
];

let selected = MultiSelect::new("Select servers:", servers)
    .with_tabular_columns(columns)
    .prompt()?;

Output:

? Select servers:
> [x] web-01     : 192.168.1.10, 8080, Running
  [x] api-gateway: 192.168.1.20, 3000, Running
  [ ] db-primary : 192.168.1.30, 5432, Stopped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant