Introduction
Datui is an interactive terminal user interface (TUI) for exploring and analyzing data files.
Datui is in rapid development—features and interfaces are evolving as built. Expect some changes between releases en route to a stable foundation.
See It In Action
Use arrow keys or vim-style bindings (j/k for up/down, h/l for left/right) to explore interactively.

For more demonstrations of Datui’s features, see the Demos page.
Demo Gallery
This page showcases interactive demonstrations of Datui’s features.
Navigation

What it shows:
- Loading a Parquet file (
people.parquet) - Scrolling through data using
↑/↓(orj/k) keys
See Loading Data for more information about file formats and options.
Querying

What it shows:
- Opening the query input with
/ - Typing a query:
select first_name, last_name, city, salary where salary > 80000 - Executing the query and seeing filtered results
See Querying Data for detailed query syntax and examples.
Getting Started
This section will help you get started with datui.
Note: This is a stub. Please add your getting started content here.
Installation
Note: This is a stub. Please add installation instructions here.
Quick Start
Note: This is a stub. Please add quick start guide here.
User Guide
Note: This is a stub. Please add user guide content here.
Configuration
Datui supports extensive customization through TOML configuration files. You can customize colors, defaults, performance settings, and more.
Quick Start
Generate a default configuration file:
datui --generate-config
This creates ~/.config/datui/config.toml with all available options and helpful comments.
Configuration File Location
- Linux:
~/.config/datui/config.toml - macOS:
~/.config/datui/config.toml - Windows:
%APPDATA%\datui\config.toml
Configuration Priority
Settings are applied in this order (later values override earlier ones):
- Default values (hardcoded)
- Config file (
~/.config/datui/config.toml) - Command-line arguments (highest priority)
Configuration Sections
File Loading Defaults
Customize how data files are loaded:
[file_loading]
delimiter = 44 # CSV delimiter (44 = comma)
has_header = true # Whether files have headers
skip_lines = 0 # Lines to skip at file start
skip_rows = 0 # Rows to skip when reading
compression = "gzip" # Default compression: "gzip", "zstd", "bzip2", "xz"
Display Settings
Control how data is displayed:
[display]
pages_lookahead = 3 # Pages to buffer ahead (smoother scrolling)
pages_lookback = 3 # Pages to buffer behind
row_numbers = false # Show row numbers on left side
row_start_index = 1 # Starting index for row numbers (0 or 1)
Example: Enable row numbers starting at 0
[display]
row_numbers = true
row_start_index = 0
Performance Settings
Tune performance and responsiveness:
[performance]
sampling_threshold = 10000 # Sample datasets >= this size
event_poll_interval_ms = 25 # UI polling interval (lower = more responsive)
Memory vs Speed:
- Increase
sampling_thresholdto avoid sampling (uses more memory, full accuracy) - Decrease
sampling_thresholdfor faster analysis on large datasets (uses less memory)
Color Themes
Customize the entire UI appearance:
[theme.colors]
keybind_hints = "cyan" # Keybind hints
keybind_labels = "yellow" # Action labels
primary_chart_series_color = "cyan" # Chart data
secondary_chart_series_color = "dark_gray" # Chart theory
error = "red" # Error messages
success = "green" # Success indicators
warning = "yellow" # Warnings
dimmed = "dark_gray" # Dimmed elements
Color Formats
Three color formats are supported:
1. Named Colors
keybind_hints = "cyan"
error = "bright_red"
dimmed = "dark_gray"
background = "default" # Use terminal default background
text_primary = "default" # Use terminal default text color
Available names:
- Basic:
black,red,green,yellow,blue,magenta,cyan,white - Bright:
bright_red,bright_green,bright_blue, etc. - Grays:
gray,dark_gray,light_gray - Special:
resetordefault(uses terminal default colors - works in both light and dark themes)
2. Hex Colors
background = "#1e1e1e"
sidebar_border = "#007acc"
controls_bg = "#2d2d2d"
- Format:
#rrggbb(6 hex digits) - Case-insensitive:
#FF0000or#ff0000 - Automatically adapted to your terminal’s capabilities
3. Indexed Colors
controls_bg = "indexed(236)" # Example: specific palette entry
surface = "indexed(239)"
- Direct reference to xterm 256-color palette (0-255)
- Respects your terminal’s color scheme
- Useful for matching specific terminal themes
Terminal Compatibility
Colors automatically adapt to your terminal:
- True color terminals (Alacritty, kitty, iTerm2): Hex colors display exactly
- 256-color terminals (xterm-256color): Hex converted to nearest palette match
- Basic terminals (8/16 colors): Colors map to nearest ANSI color
- Monochrome: Set
NO_COLOR=1to disable colors
Light Theme Support: The default background and text_primary use "default" to inherit your terminal’s default colors. This ensures the app works correctly in both light and dark terminal themes. If you set explicit colors like "black" or "white", they may not work well in light themes.
Available Colors
All UI colors can be customized:
| Color | Purpose | Default |
|---|---|---|
keybind_hints | Keybind hints (modals, breadcrumb, correlation matrix) | cyan |
keybind_labels | Action labels in controls bar | yellow |
primary_chart_series_color | Chart data (histogram bars, Q-Q plot data points) | cyan |
secondary_chart_series_color | Chart theory (histogram overlays, Q-Q plot reference line) | dark_gray |
success | Success indicators, normal distributions | green |
error | Error messages, outliers | red |
warning | Warnings, skewed distributions | yellow |
dimmed | Dimmed elements, axis lines | dark_gray |
background | Main background | default (uses terminal default) |
surface | Modal/surface backgrounds | default (uses terminal default) |
controls_bg | Controls bar and table header backgrounds | dark_gray |
text_primary | Primary text | default (uses terminal default) |
text_secondary | Secondary text | dark_gray |
text_inverse | Text on light backgrounds | black |
table_header | Table column header text | white |
table_header_bg | Table column header background | dark_gray |
column_separator | Vertical line between table columns | cyan |
table_selected | Selected row style | reversed |
sidebar_border | Sidebar borders | dark_gray |
modal_border_active | Active modal elements | yellow |
modal_border_error | Error modal borders | red |
distribution_normal | Normal distribution indicator | green |
distribution_skewed | Skewed distribution indicator | yellow |
distribution_other | Other distribution types | white |
outlier_marker | Outlier indicators | red |
Query System
Configure query behavior:
[query]
history_limit = 1000 # Max queries to remember
enable_history = true # Enable query history
Template Settings
Configure template behavior:
[templates]
auto_apply = false # Auto-apply most relevant template on file open
Debug Settings
Configure debug overlay:
[debug]
enabled = false # Show debug overlay by default
show_performance = true # Show performance metrics
show_query = true # Show LazyFrame query
show_transformations = true # Show transformation state
Example Configurations
Minimal Configuration
Simple customization for common preferences:
version = "0.2"
[display]
row_numbers = true
row_start_index = 0
[theme.colors]
keybind_hints = "blue"
Dracula Theme
Complete Dracula color scheme using hex colors:
version = "0.2"
[theme.colors]
keybind_hints = "#bd93f9" # Purple
keybind_labels = "#ff79c6" # Pink
primary_chart_series_color = "#bd93f9" # Purple
secondary_chart_series_color = "#6272a4" # Comment gray
success = "#50fa7b" # Green
error = "#ff5555" # Red
warning = "#ffb86c" # Orange
dimmed = "#6272a4" # Comment gray
background = "#282a36" # Background (Dracula dark)
surface = "#44475a" # Current line
controls_bg = "#44475a" # Controls bar
text_primary = "#f8f8f2" # Foreground
text_secondary = "#6272a4" # Comment
text_inverse = "#282a36" # Background (for inverse)
table_header = "#f8f8f2" # Foreground
table_header_bg = "#44475a" # Current line
column_separator = "#bd93f9" # Purple
table_selected = "reversed"
sidebar_border = "#6272a4" # Comment gray
modal_border_active = "#ff79c6" # Pink
modal_border_error = "#ff5555" # Red
distribution_normal = "#50fa7b" # Green
distribution_skewed = "#ffb86c" # Orange
distribution_other = "#f8f8f2" # Foreground
outlier_marker = "#ff5555" # Red
Performance Tuned
Optimize for large datasets:
version = "0.2"
[display]
pages_lookahead = 5 # More buffering for smoother scrolling
pages_lookback = 5
[performance]
sampling_threshold = 50000 # Sample only very large datasets
event_poll_interval_ms = 16 # ~60 FPS polling (more responsive)
High Contrast Theme
Using named colors for maximum compatibility:
version = "0.2"
[theme.colors]
keybind_hints = "bright_cyan"
keybind_labels = "bright_yellow"
primary_chart_series_color = "bright_cyan"
secondary_chart_series_color = "dark_gray"
error = "bright_red"
success = "bright_green"
warning = "bright_yellow"
dimmed = "dark_gray"
background = "black"
controls_bg = "dark_gray"
text_primary = "bright_white"
Command-Line Overrides
CLI arguments always override config file settings:
# Config has row_numbers = true, but disable for this run:
datui data.csv --row-numbers=false
# Override page buffering:
datui data.csv --pages-lookahead 10
# Override delimiter:
datui data.csv --delimiter=9 # Tab character (ASCII 9)
Managing Configuration
View Current Config
Your config file is at ~/.config/datui/config.toml. Edit it with any text editor:
# Linux/macOS
nano ~/.config/datui/config.toml
vim ~/.config/datui/config.toml
code ~/.config/datui/config.toml
# Windows
notepad %APPDATA%\datui\config.toml
Reset to Defaults
Regenerate the default config file:
datui --generate-config --force
This overwrites your existing config with a fresh template.
Remove Configuration
Simply delete the config file:
# Linux/macOS
rm ~/.config/datui/config.toml
# Windows
del %APPDATA%\datui\config.toml
Datui will use default values when no config file exists.
Troubleshooting
Config Not Loading
If your config isn’t being used:
- Check file location: Ensure config is at
~/.config/datui/config.toml - Check syntax: TOML must be valid. Run
datui <file>and check for warnings - Check version: Config must start with
version = "0.2" - Check validation: Ensure values are in valid ranges (e.g.,
sampling_threshold > 0)
Invalid Color
If you see an error about invalid colors:
Error: Invalid color value for 'keybind_hints': Unknown color name: 'notacolor'
Solutions:
- Use valid color names (see list above)
- Use hex format:
#ff0000 - Use indexed format:
indexed(236) - Check spelling and case (names are case-insensitive)
Config Parse Error
If TOML parsing fails:
Error: Failed to parse config file: expected newline, found ...
Solutions:
- Check TOML syntax at https://toml.io/
- Ensure proper quotes around strings
- Verify no typos in section names
- Regenerate config:
datui --generate-config --force
Colors Look Wrong
If colors don’t look right:
- Check terminal capabilities: Some terminals don’t support true color
- Try named colors: More portable than hex colors
- Try indexed colors: Match your terminal’s palette exactly
- Check NO_COLOR: Unset with
unset NO_COLORif colors are disabled
See Also
- Command-Line Options - CLI flags that override config
- Quick Start Guide - Getting started with datui
- Keyboard Shortcuts - Available keybindings
Loading Data
Note: This is a stub. Please add content about loading data files (CSV, Parquet, JSON, NDJSON) here.
Querying Data
Note: This is a stub. Please add content about querying data here.
Filtering and Sorting
Note: This is a stub. Please add content about filtering and sorting data here.
Analysis Features
Note: This is a stub. Please add content about statistical analysis features here.
Templates
Note: This is a stub. Please add content about templates here.
Reference
Note: This is a stub. Please add reference documentation here.
Command Line Options
Note: This is a stub. Please add command-line options documentation here.
Keyboard Shortcuts
Note: This is a stub. Please add keyboard shortcuts documentation here.
Query Syntax
Note: This is a stub. Please add query syntax documentation here.
Advanced Topics
Note: This is a stub. Please add advanced topics content here.
Performance Tips
Note: This is a stub. Please add performance tips here.
For Developers
- Written in Rust
- Terminal UI made with Ratatui
- Powered by Polars
- Documented using mdBook
- Demo GIFs created with vhs
Contributing
Thank you for your interest in contributing to Datui!
After cloning the repo, follow the Setup instructions below to get started.
Setup
Setup Script
TLDR: The entire setup process can be automated by running
python scripts/setup-dev.py
The script will:
- Set up the Python Virtual Enviroment
- Updates it if it already exists
- Install/update pre-commit hooks
- Generates sample data needed to run the tests
- Configure and build the documentation
Python Virtual Environment
There are Python scripts in the /scripts directory that are
used to do things like build test data, documentation, and demo gifs.
Setting up a virtual environment with dependencies for these scripts will ensure you can run them all.
A common convention is to create a virtual environment in the .venv/ directory
of the repository. The .gitignore is set up to ignore this location
so that files there aren’t added by mistake.
python -m venv .venv
Then activate the virtual environment.
source .venv/bin/activate
Once activated, install dependencies used to run the availble Python scripts.
pip install -r scripts/requirements.txt
You’re now ready to run the tests.
Pre-commit Hooks
To encourage consistency and quality, the CI build checks the source code of the application for formatting and linter warnings.
This project uses pre-commit to manage git pre-commit hooks which automatically run the same code quality checks in your repository before commits are made.
Installing Pre-commit and Hooks
If you used the Setup Script, the pre-commit hooks are already installed.
-
Install pre-commit:
If you set up a Python virtual environment using the instructions above then you already have everything you need. Activate it and skip this step.
Otherwise, install
pre-commitusing your desired method.# Using pip pip install pre-commit # Or using homebrew (macOS) brew install pre-commit # Or using conda conda install -c conda-forge pre-commit -
Install the git hooks:
pre-commit installThis installs the hooks into
.git/hooks/so they run automatically on commit.Note: You only need the
pre-commitcommand accessible when you need to use it to manually run or update the hooks. Once installed into your repo, the hooks themselves do not requirepre-commit.See the
pre-commitdocumentation for more information about its features.
The following hooks are configured:
-
cargo-fmt: Automatically formats Rust code with
cargo fmt- If code needs formatting, it will be formatted and the commit will fail
- Stage the formatted changes and commit again
-
cargo-clippy: Runs
cargo clippy --all-targets -- -D warnings- Fails if clippy finds any warnings
- Fix them and commit again
Hooks run automatically when you git commit. If any hook fails, the commit is aborted.
Running Hooks
Run all hooks manually:
pre-commit run --all-files
Run a specific hook:
pre-commit run cargo-fmt --all-files
pre-commit run cargo-clippy --all-files
Skipping Hooks
If you need to skip hooks for a specific commit (not recommended):
git commit --no-verify -m "Emergency fix"
Updating hooks
Update hook versions and configurations:
pre-commit autoupdate
Troubleshooting
Hook not running?
- Make sure you ran
pre-commit install - Check
.git/hooks/pre-commitexists
Hooks too slow?
- Only changed files are checked by default
- Use
SKIP=hook-name git committo skip specific hooks
Adding Configuration Options
For detailed instructions on adding new configuration options to datui, see the dedicated Guide to Adding Configuration Options.
Quick summary:
- Add field to appropriate config struct (
src/config.rs) - Update
Defaultimplementation - Add merge logic in
merge()method - Add comments to comment constant (next to struct)
- Use the value in application code
- Add tests
- Update user documentation
The guide includes step-by-step instructions, code examples, merge rules, best practices, and special instructions for adding theme colors.
Running the Tests
Running the tests is done using Cargo’s test command.
cargo test
However, the tests require sample data which are too large to add to the repo. Instead, the data must be generated before the tests can be run.
Generating Sample Data
If you used the Setup Script, the sample data has already been generated. To regenerate the data, see the instructions
The tests will automatically run a Python script to generate the sample files if they do not already exist. However, that script has some dependencies.
To install the dependencies, I recommend following the Python Virtual Environment Setup Instructions from the Contributing section.
Once you have a Python virtual environment set up with the requirements.txt from
the scripts/ directory, and activated it, you’re ready to run the tests for the first time.
# activate the virtual environment if sample data is not already generated
source .venv/bin/activte
# run the tests
cargo test
The tests will look for the files and run the generation script if they don’t already exist. Having the virtual environment activated before running tests for the first time ensures the automatic generation goes smoothly.
After the files are built you don’t need to have that environment activated anymore to run tests.
Regenerating or Updating the Sample Data
You can run the data generation script yourself:
python scripts/generate_sample_data.py
The data will not be automatically regenerated in the future. Use the script to regenerate the data when necessary.
Documentation
Datui uses mdBook to build static documentation web pages from markdown files.
The documentation markdown files can be found in the docs subdirectory.
Build Documentation
Install mdBook
If you used the Setup Script, mdBook is already installed.
Building the documentation requires mdbook to be available in your terminal.
I recommend using cargo to install it. It will be available into your ~/.cargo/bin/,
where the documentation build script will look for it. You may also add that
location to your PATH if you like.
cargo install mdbook
Build
To build the entire documentation site:
scripts/docs/build_all_docs_local.sh
This will populate the book directory with the site’s files.
At the end it will ask you if you would like a server to view the docs, or you
can simply open the index.html with your web browser.
To view locally, you can:
1. Open book/index.html in your browser
2. Or use a simple HTTP server:
python3 -m http.server 8000 --directory book
Then visit: http://localhost:8000
Start a local HTTP server to view the docs? (y/n)
Adding Configuration Options
When adding new configuration options to datui, follow this process:
Process Overview
Adding a new configuration option requires updates in 7 places:
- Config struct definition
- Default implementation
- Merge logic
- Comment constants (for generated configs)
- Application code usage
- Tests
- Documentation
Step-by-Step Guide
1. Add Field to Config Struct
Add the new field to the appropriate config struct in src/config.rs:
#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct DisplayConfig {
pub pages_lookahead: usize,
pub pages_lookback: usize,
pub row_numbers: bool,
pub row_start_index: usize,
pub font_size: Option<u8>, // NEW FIELD
}
}
2. Update Default Implementation
Add the default value in the Default trait:
#![allow(unused)]
fn main() {
impl Default for DisplayConfig {
fn default() -> Self {
Self {
pages_lookahead: 3,
pages_lookback: 3,
row_numbers: false,
row_start_index: 1,
font_size: None, // NEW: None = use terminal default
}
}
}
}
3. Update Merge Logic
Add merge handling in the section’s merge() method:
#![allow(unused)]
fn main() {
impl DisplayConfig {
pub fn merge(&mut self, other: Self) {
let default = DisplayConfig::default();
// ... existing merge logic ...
// NEW: Merge font_size (Option fields)
if other.font_size.is_some() {
self.font_size = other.font_size;
}
}
}
}
Merge rules:
- Option fields: If
other.field.is_some(), take the value - Non-Option fields: If
other.field != default.field, take the value
4. Add Comments to Comment Constants
Add comments to the comment constant array right after the struct definition in src/config.rs:
#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct DisplayConfig {
pub pages_lookahead: usize,
pub pages_lookback: usize,
pub row_numbers: bool,
pub row_start_index: usize,
pub font_size: Option<u8>, // NEW FIELD
}
// Field comments for DisplayConfig
const DISPLAY_COMMENTS: &[(&str, &str)] = &[
// ... existing fields ...
(
"font_size",
"Font size for terminal display (optional)\nSet to null to use terminal default, or 8-16 for explicit size",
),
];
}
Note: Comments are defined next to the struct definition. The config template is generated from Rust code defaults, with all fields commented out so users can uncomment to override.
5. Use in Application Code
Access the config value where needed:
#![allow(unused)]
fn main() {
let font_size = config.display.font_size.unwrap_or(terminal_default);
}
Or pass through App if needed globally:
#![allow(unused)]
fn main() {
app.font_size = config.display.font_size;
}
6. Add Tests
Add tests in tests/config_test.rs or tests/config_integration_test.rs:
#![allow(unused)]
fn main() {
#[test]
fn test_font_size_config() {
let mut config = AppConfig::default();
config.display.font_size = Some(12);
assert_eq!(config.display.font_size, Some(12));
assert!(config.validate().is_ok());
}
}
7. Update Documentation
Update documentation:
- Add to
docs/user-guide/configuration.md - Mention in README.md if it’s a major feature
Note: Configuration comments are defined in comment constants next to struct definitions (e.g., DISPLAY_COMMENTS, PERFORMANCE_COMMENTS) in src/config.rs. The config template is generated programmatically from these constants.
Implementation Checklist
- Field added to config struct
- Default implementation updated
- Merge logic implemented
- Comments added to comment constant (next to struct)
- Used in application code
- Tests added
- Documentation updated
- All tests passing (
cargo test) - No clippy warnings (
cargo clippy) - Code formatted (
cargo fmt)
Best Practices
Choosing Field Types
-
Option fields: Use
Option<T>for optional settings#![allow(unused)] fn main() { pub font_size: Option<u8>, // None = use default } -
Required fields: Use plain types with sensible defaults
#![allow(unused)] fn main() { pub pages_lookahead: usize, // Always has a value } -
Strings: Use
Stringfor text values#![allow(unused)] fn main() { pub delimiter: String, // CSV delimiter character }
Sensible Defaults
Ensure defaults match existing behavior:
#![allow(unused)]
fn main() {
impl Default for DisplayConfig {
fn default() -> Self {
Self {
pages_lookahead: 3,
pages_lookback: 3,
row_numbers: false,
row_start_index: 1,
}
}
}
}
Clear Config Comments
Comments in the comment constants should:
- Explain what the option does
- Show valid values or ranges
- Provide examples
- Note any interactions with other settings
Good example:
#![allow(unused)]
fn main() {
const PERFORMANCE_COMMENTS: &[(&str, &str)] = &[
(
"sampling_threshold",
"Sampling threshold: datasets >= this size will be sampled for statistics\nSet to higher value to avoid sampling, or lower to sample more aggressively",
),
];
}
Poor example:
#![allow(unused)]
fn main() {
const PERFORMANCE_COMMENTS: &[(&str, &str)] = &[
("sampling_threshold", "Sampling threshold"),
];
}
Validation
Add validation in AppConfig::validate() for constraints:
#![allow(unused)]
fn main() {
fn validate(&self) -> Result<()> {
// ... existing validation ...
// Validate new field
if self.performance.sampling_threshold == 0 {
return Err(eyre!("sampling_threshold must be greater than 0"));
}
Ok(())
}
}
Testing Edge Cases
Test important scenarios:
- Missing values (uses default)
- Invalid ranges (validation catches)
- Boundary conditions
- Config merging (CLI overrides config)
- TOML parsing (valid syntax)
Adding Colors to Theme
When adding new colors to the theme system, follow these additional steps:
1. Add to ColorConfig Struct
#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ColorConfig {
// ... existing colors ...
pub new_color: String, // NEW
}
}
2. Add to ColorConfig Default
#![allow(unused)]
fn main() {
impl Default for ColorConfig {
fn default() -> Self {
Self {
// ... existing colors ...
new_color: "cyan".to_string(), // NEW
}
}
}
}
3. Add to Validation
#![allow(unused)]
fn main() {
impl ColorConfig {
fn validate(&self, parser: &ColorParser) -> Result<()> {
macro_rules! validate_color {
($field:expr, $name:expr) => {
parser
.parse($field)
.map_err(|e| eyre!("Invalid color value for '{}': {}", $name, e))?;
};
}
// ... existing validations ...
validate_color!(&self.new_color, "new_color"); // NEW
Ok(())
}
}
}
4. Add to Merge Logic
#![allow(unused)]
fn main() {
impl ColorConfig {
pub fn merge(&mut self, other: Self) {
let default = ColorConfig::default();
// ... existing merge logic ...
if other.new_color != default.new_color { // NEW
self.new_color = other.new_color;
}
}
}
}
5. Add to Theme Parsing
#![allow(unused)]
fn main() {
impl Theme {
pub fn from_config(config: &ThemeConfig) -> Result<Self> {
let parser = ColorParser::new();
let mut colors = HashMap::new();
// ... existing color parsing ...
colors.insert(
"new_color".to_string(),
parser.parse(&config.colors.new_color)?,
); // NEW
Ok(Self { colors })
}
}
}
6. Add Comments to Comment Constant
#![allow(unused)]
fn main() {
// Field comments for ColorConfig
const COLOR_COMMENTS: &[(&str, &str)] = &[
// ... existing colors ...
(
"new_color",
"Description of the new color and where it's used",
),
];
}
Note: Comments are simple text - they’ll be prefixed with # when generating the config. The field itself will appear as # new_color = "cyan" (commented out).
7. Replace Hardcoded Usage
Find and replace hardcoded colors in widgets:
Before:
#![allow(unused)]
fn main() {
Style::default().fg(Color::Cyan)
}
After:
#![allow(unused)]
fn main() {
Style::default().fg(self.color("new_color"))
// or
Style::default().fg(theme.get("new_color"))
}
Color Naming Conventions
- Use descriptive names:
sidebar_bordernotsb - Be specific:
modal_border_activevssidebar_border(modals vs sidebars) - Group logically:
distribution_normal,distribution_skewed,distribution_other - Consider purpose:
text_primary,text_secondary,text_inverse
Common Patterns
Option Field Pattern
#![allow(unused)]
fn main() {
// Config struct
pub struct Config {
pub optional_field: Option<T>,
}
// Default
impl Default for Config {
fn default() -> Self {
Self {
optional_field: None, // No default value
}
}
}
// Merge
impl Config {
pub fn merge(&mut self, other: Self) {
if other.optional_field.is_some() {
self.optional_field = other.optional_field;
}
}
}
// Usage
let value = config.optional_field.unwrap_or(fallback);
}
Required Field Pattern
#![allow(unused)]
fn main() {
// Config struct
pub struct Config {
pub required_field: usize,
}
// Default
impl Default for Config {
fn default() -> Self {
Self {
required_field: 10, // Sensible default
}
}
}
// Merge
impl Config {
pub fn merge(&mut self, other: Self) {
let default = Config::default();
if other.required_field != default.required_field {
self.required_field = other.required_field;
}
}
}
// Usage
let value = config.required_field;
}
String Field Pattern
#![allow(unused)]
fn main() {
// Config struct
pub struct Config {
pub mode: String,
}
// Default
impl Default for Config {
fn default() -> Self {
Self {
mode: "auto".to_string(),
}
}
}
// Merge
impl Config {
pub fn merge(&mut self, other: Self) {
let default = Config::default();
if other.mode != default.mode {
self.mode = other.mode;
}
}
}
// Validation
fn validate(&self) -> Result<()> {
match self.mode.as_str() {
"option1" | "option2" | "option3" => Ok(()),
_ => Err(eyre!("Invalid mode: {}. Must be one of: option1, option2, option3", self.mode))
}
}
}
Resources
- See
src/config.rsfor existing implementations and comment constants (e.g.,PERFORMANCE_COMMENTS,DISPLAY_COMMENTS) - See
tests/config_test.rsfor test examples - Run
datui --generate-configto see the generated config template (all fields commented out)
Questions?
If you’re unsure about:
- Which config section to use: Look at similar settings in existing config
- Merge logic: Follow the patterns in existing merge implementations
- Validation: Add validation if there are constraints on the value
- Testing: Look at existing tests for similar config types
Demos
The Datui demo animations are created using vhs, which lets you script and record keystrokes to a terminal app.
Install vhs
Define Tapes
The vhs application uses .tape files to script keystrokes. See Datui’s here.
Generating the Animations
Run generate-all to use vhs to generate an animated gif file for each tape.
The generate-all script will first run a release build, and then use that version of the application when creating the demos.
scripts/demos/generate-all.sh
The animations will be placed in the demos directory.
During the creation of the documentation, these animations are copied into a
demos/subdirectory of the generated site. From there, the files may be referenced from within the docs.