feat: allow configuring alignment when max columns is hit

This commit is contained in:
Matias Fontanini 2025-03-03 05:26:40 -08:00
parent ec1be93a06
commit 24e6ea8386
6 changed files with 90 additions and 12 deletions

View File

@ -50,6 +50,14 @@
"format": "uint16",
"minimum": 0.0
},
"max_columns_alignment": {
"description": "The alignment the presentation should have if `max_columns` is set and the terminal is larger than that.",
"allOf": [
{
"$ref": "#/definitions/MaxColumnsAlignment"
}
]
},
"terminal_font_size": {
"description": "Override the terminal font size when in windows or when using sixel.",
"default": 16,
@ -267,6 +275,32 @@
}
}
},
"MaxColumnsAlignment": {
"description": "The alignment to use when `defaults.max_columns` is set.",
"oneOf": [
{
"description": "Align the presentation to the left.",
"type": "string",
"enum": [
"left"
]
},
{
"description": "Align the presentation on the center.",
"type": "string",
"enum": [
"center"
]
},
{
"description": "Align the presentation to the right.",
"type": "string",
"enum": [
"right"
]
}
]
},
"MermaidConfig": {
"type": "object",
"properties": {

View File

@ -74,7 +74,7 @@ pub struct DefaultsConfig {
pub theme: Option<String>,
/// Override the terminal font size when in windows or when using sixel.
#[serde(default = "default_font_size")]
#[serde(default = "default_terminal_font_size")]
#[validate(range(min = 1))]
pub terminal_font_size: u8,
@ -89,24 +89,45 @@ pub struct DefaultsConfig {
/// A max width in columns that the presentation must always be capped to.
#[serde(default = "default_max_columns")]
pub max_columns: u16,
/// The alignment the presentation should have if `max_columns` is set and the terminal is
/// larger than that.
#[serde(default)]
pub max_columns_alignment: MaxColumnsAlignment,
}
impl Default for DefaultsConfig {
fn default() -> Self {
Self {
theme: Default::default(),
terminal_font_size: default_font_size(),
terminal_font_size: default_terminal_font_size(),
image_protocol: Default::default(),
validate_overflows: Default::default(),
max_columns: default_max_columns(),
max_columns_alignment: Default::default(),
}
}
}
fn default_font_size() -> u8 {
fn default_terminal_font_size() -> u8 {
16
}
/// The alignment to use when `defaults.max_columns` is set.
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum MaxColumnsAlignment {
/// Align the presentation to the left.
Left,
/// Align the presentation on the center.
#[default]
Center,
/// Align the presentation to the right.
Right,
}
#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ValidateOverflows {

View File

@ -418,6 +418,7 @@ fn run(cli: Cli) -> Result<(), Box<dyn std::error::Error>> {
bindings: config.bindings,
validate_overflows,
max_columns: config.defaults.max_columns,
max_columns_alignment: config.defaults.max_columns_alignment,
};
let presenter = Presenter::new(
&default_theme,

View File

@ -4,7 +4,7 @@ use crate::{
listener::{Command, CommandListener},
speaker_notes::{SpeakerNotesEvent, SpeakerNotesEventPublisher},
},
config::KeyBindingsConfig,
config::{KeyBindingsConfig, MaxColumnsAlignment},
export::ImageReplacer,
markdown::parse::{MarkdownParser, ParseError},
presentation::{
@ -43,6 +43,7 @@ pub struct PresenterOptions {
pub bindings: KeyBindingsConfig,
pub validate_overflows: bool,
pub max_columns: u16,
pub max_columns_alignment: MaxColumnsAlignment,
}
/// A slideshow presenter.
@ -105,6 +106,7 @@ impl<'a> Presenter<'a> {
let drawer_options = TerminalDrawerOptions {
font_size_fallback: self.options.font_size_fallback,
max_columns: self.options.max_columns,
max_columns_alignment: self.options.max_columns_alignment,
};
let mut drawer = TerminalDrawer::new(self.image_printer.clone(), drawer_options)?;
loop {

View File

@ -1,5 +1,6 @@
use super::{RenderError, RenderResult, layout::Layout, properties::CursorPosition, text::TextDrawer};
use crate::{
config::MaxColumnsAlignment,
markdown::{text::WeightedLine, text_style::Colors},
render::{
layout::Positioning,
@ -27,12 +28,18 @@ const MINIMUM_LINE_LENGTH: u16 = 10;
pub(crate) struct RenderEngineOptions {
pub(crate) validate_overflows: bool,
pub(crate) max_columns: u16,
pub(crate) max_columns_alignment: MaxColumnsAlignment,
pub(crate) column_layout_margin: u16,
}
impl Default for RenderEngineOptions {
fn default() -> Self {
Self { validate_overflows: false, max_columns: u16::MAX, column_layout_margin: 4 }
Self {
validate_overflows: false,
max_columns: u16::MAX,
max_columns_alignment: Default::default(),
column_layout_margin: 4,
}
}
}
@ -71,7 +78,12 @@ where
if window_dimensions.columns > options.max_columns {
let extra_width = window_dimensions.columns - options.max_columns;
let dimensions = window_dimensions.shrink_columns(extra_width);
WindowRect { dimensions, start_column: extra_width / 2, start_row }
let start_column = match options.max_columns_alignment {
MaxColumnsAlignment::Left => 0,
MaxColumnsAlignment::Center => extra_width / 2,
MaxColumnsAlignment::Right => extra_width,
};
WindowRect { dimensions, start_column, start_row }
} else {
WindowRect { dimensions: window_dimensions, start_column: 0, start_row }
}
@ -549,7 +561,12 @@ mod tests {
fn render(operations: &[RenderOperation]) -> Vec<Instruction> {
let mut buf = TerminalBuf::default();
let dimensions = WindowSize { rows: 100, columns: 100, height: 200, width: 200 };
let options = RenderEngineOptions { validate_overflows: false, max_columns: u16::MAX, column_layout_margin: 0 };
let options = RenderEngineOptions {
validate_overflows: false,
max_columns: u16::MAX,
max_columns_alignment: Default::default(),
column_layout_margin: 0,
};
let engine = RenderEngine::new(&mut buf, dimensions, options);
engine.render(operations.iter()).expect("render failed");
buf.instructions

View File

@ -6,6 +6,7 @@ pub(crate) mod text;
pub(crate) mod validate;
use crate::{
config::MaxColumnsAlignment,
markdown::{
elements::Text,
text::WeightedLine,
@ -28,16 +29,14 @@ use std::{
pub(crate) type RenderResult = Result<(), RenderError>;
pub(crate) struct TerminalDrawerOptions {
/// The font size to fall back to if we can't find the window size in pixels.
pub(crate) font_size_fallback: u8,
/// The max width in columns that the presentation should be capped to.
pub(crate) max_columns: u16,
pub(crate) max_columns_alignment: MaxColumnsAlignment,
}
impl Default for TerminalDrawerOptions {
fn default() -> Self {
Self { font_size_fallback: 1, max_columns: u16::MAX }
Self { font_size_fallback: 1, max_columns: u16::MAX, max_columns_alignment: Default::default() }
}
}
@ -98,7 +97,11 @@ impl TerminalDrawer {
}
fn create_engine(&mut self, dimensions: WindowSize) -> RenderEngine<Terminal<Stdout>> {
let options = RenderEngineOptions { max_columns: self.options.max_columns, ..Default::default() };
let options = RenderEngineOptions {
max_columns: self.options.max_columns,
max_columns_alignment: self.options.max_columns_alignment,
..Default::default()
};
RenderEngine::new(&mut self.terminal, dimensions, options)
}
}