Block geometry
BlockStyle controls the rectangle around one child View. Its operations are
independent, so the output below separates them before combining them.
This is a Layout guide. Although the Rust type is named BlockStyle, the
capabilities on this page decide space and placement. For cell color,
attributes, underlines, and hyperlinks, use Styles.
| Capability | Main API | Visible effect |
|---|---|---|
| Outer spacing | margin |
Blank cells outside the border |
| Border and edges | border, border_* |
Glyphs around enabled edges |
| Inner spacing | padding |
Cells between border and child |
| Dimensions | width, height, Length |
Fixed, intrinsic, or parent-filled allocation |
| Child placement | align, vertical_align |
Horizontal and vertical free-space distribution |
| Long text | overflow |
Wrap, clip, ellipsis, or a custom marker |
| Block-created cell style | from_text_style, border color builders |
Fill padding/alignment cells and style border cells |
See the box model
Section titled “See the box model”The order is always outermost to innermost:
Each rectangle contains the next one. Space is measured from the outside inward: margin, border, padding, then the child View.
This complete example gives each layer enough space to remain visible:
use std::io;
use urushi::{ Align, BlockStyle, Border, TextStyle, VerticalAlign, View,};
fn main() -> io::Result<()> { let view = View::block( BlockStyle::new() .margin((1, 0)) .border(Border::ROUNDED) .padding((0, 1)) .width(20) .height(5) .align(Align::Center) .vertical_align(VerticalAlign::Center), View::text("build complete", TextStyle::new()), );
urushi::println_view(&view)}╭──────────────────╮│ ││ build complete ││ │╰──────────────────╯The blank first and last rows are vertical margin. The border begins inside that margin. Padding guarantees at least one cell beside the child; alignment receives the remaining free cells.
The same layers are highlighted here because spaces alone do not reveal which part owns them:
╭──────────────────╮│ ││ build complete ││ │╰──────────────────╯
Align inside a fixed size
Section titled “Align inside a fixed size”Horizontal alignment moves the child without changing the block width:
use std::io;use urushi::{Align, BlockStyle, Border, TextStyle, View};
fn main() -> io::Result<()> { for align in [Align::Left, Align::Center, Align::Right] { let view = View::block( BlockStyle::new() .border(Border::NORMAL) .width(12) .align(align), View::text("status", TextStyle::new()), ); urushi::println_view(&view)?; } Ok(())}┌──────────┐│status │└──────────┘┌──────────┐│ status │└──────────┘┌──────────┐│ status│└──────────┘Vertical alignment uses the free rows created by height:
use std::io;use urushi::{BlockStyle, Border, TextStyle, VerticalAlign, View};
fn main() -> io::Result<()> { for align in [ VerticalAlign::Top, VerticalAlign::Center, VerticalAlign::Bottom, ] { let view = View::block( BlockStyle::new() .border(Border::NORMAL) .width(12) .height(5) .vertical_align(align), View::text("status", TextStyle::new()), ); urushi::println_view(&view)?; } Ok(())}┌──────────┐│status ││ ││ │└──────────┘┌──────────┐│ ││status ││ │└──────────┘┌──────────┐│ ││ ││status │└──────────┘Width and height accept fixed cells or Length::fill(weight). Fill requires a
finite reference size from the parent. A zero fill weight is invalid; use
Length::try_fill when it must produce a Result instead of panicking.
use urushi::{Available, BlockStyle, Length, TextStyle, View, resolve};
let fill = View::block( BlockStyle::new().width(Length::fill(1)), View::text("x", TextStyle::new()),);assert_eq!(resolve(&fill, Available::columns(12))?.size().width(), 12);assert!(Length::try_fill(0).is_err());
let minimum = View::block( BlockStyle::new().min_width(8), View::text("x", TextStyle::new()),);let maximum = View::block( BlockStyle::new().max_width(5), View::text("abcdefgh", TextStyle::new()),);assert_eq!(resolve(&minimum, Available::NONE)?.size().width(), 8);assert_eq!(resolve(&maximum, Available::NONE)?.size().width(), 5);fill(1) in 12 available columns → 12min_width(8) around "x" → 8max_width(5) around "abcdefgh" → 5try_fill(0) → Err(InvalidFillWeight)Select borders and edges
Section titled “Select borders and edges”Choose a glyph repertoire with border, then disable individual edges. This
example leaves the bottom open:
use std::io;use urushi::{BlockStyle, Border, TextStyle, View};
fn main() -> io::Result<()> { let view = View::block( BlockStyle::new() .border(Border::ROUNDED) .border_bottom(false) .padding((0, 1)), View::text("open", TextStyle::new()), ); urushi::println_view(&view)}╭──────╮│ open │border_top, border_right, border_bottom, and border_left can be toggled
independently. Border foreground and background are also independent from the
style used for padding and alignment cells.
Choose overflow behavior
Section titled “Choose overflow behavior”Overflow changes only content that exceeds the available width:
use std::io;use urushi::{BlockStyle, Overflow, TextStyle, View};
fn main() -> io::Result<()> { for overflow in [ Overflow::Wrap, Overflow::clip(), Overflow::ellipsis(), ] { let view = View::block( BlockStyle::new().width(10).overflow(overflow), View::text("alpha beta gamma", TextStyle::new()), ); urushi::println_view(&view)?; } Ok(())}alpha betagammaalpha betaalpha bet…Overflow::clip_with selects another one-cell marker. Width is measured in
terminal cells. Height always clips rows that do not fit inside the resolved
frame.
Style block-created cells
Section titled “Style block-created cells”Block appearance does not cascade into child text. from_text_style applies a
fill to cells created by padding and alignment, while the child retains its own
TextStyle:
use urushi::{BlockStyle, Border, Color, TextStyle, View};
let view = View::block( BlockStyle::from_text_style( TextStyle::new().background(Color::BLUE), ) .border(Border::ROUNDED) .border_foreground(Color::CYAN) .padding((0, 1)), View::text("child", TextStyle::new().foreground(Color::YELLOW)),);╭───────╮
│ child │
╰───────╯
Use BlockStyle::from_text_style only for block-created cells. Give content its
own text style when its appearance must remain explicit.