Skip to content

feat: add configurable line_height setting#278

Merged
lassejlv merged 5 commits intotermy-org:mainfrom
fcoury:feat/line-height
Mar 23, 2026
Merged

feat: add configurable line_height setting#278
lassejlv merged 5 commits intotermy-org:mainfrom
fcoury:feat/line-height

Conversation

@fcoury
Copy link
Copy Markdown
Contributor

@fcoury fcoury commented Mar 23, 2026

Summary

  • Replaces the hardcoded 1.4 line-height multiplier with a user-facing line_height config option (range 0.8–2.5, default 1.4)
  • Adds config parsing with validation, settings UI numeric stepper (delta 0.05), and live config reload support
  • Includes doc comments on new constants and fields
Before After
image image
image

Test plan

  • Verify line_height = 1.0 produces tightly packed rows
  • Verify line_height = 2.0 doubles vertical spacing
  • Verify out-of-range values (e.g. 0.5, 3.0) fall back to default
  • Verify settings UI stepper increments/decrements by 0.05 and respects bounds
  • Verify changing line height in settings takes effect without restart
  • Run cargo test -p termy_config_core — all pass

Summary by CodeRabbit

  • New Features

    • Added configurable terminal line-height setting (multiplier) with adjustable range of 0.8–2.5 and default value of 1.4, accessible via settings UI and configuration file.
  • Documentation

    • Updated configuration documentation to include new line-height setting details and defaults.

Replace the hardcoded 1.4 line-height multiplier with a user-facing
config option (range 0.8–2.5, default 1.4). Adds parsing, validation,
settings UI stepper, and live config reload support.
Copilot AI review requested due to automatic review settings March 23, 2026 20:24
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new configurable line_height setting for terminal rendering, allowing users to adjust the line-height multiplier between 0.8 and 2.5 (default 1.4) through configuration files and the settings UI. The feature includes parsing, validation, schema registration, and clamping at the terminal renderer.

Changes

Cohort / File(s) Summary
Core Config Constants & Types
crates/config_core/src/constants.rs, crates/config_core/src/types.rs
Added three f32 constants (DEFAULT_LINE_HEIGHT: 1.4, MIN_LINE_HEIGHT: 0.8, MAX_LINE_HEIGHT: 2.5) and introduced a new line_height: f32 field to AppConfig struct with default initialization.
Library Exports & Utilities
crates/config_core/src/lib.rs, crates/config_core/src/default_config.txt
Re-exported the three new line-height constants and added a format_line_height() helper function; registered line_height setting in default config with value 1.4.
Parser & Validation
crates/config_core/src/parser.rs, crates/config_core/src/parser_tests.rs
Extended parser to handle RootSettingId::LineHeight with parse_f32_field, range validation against min/max bounds, and finite-value checks; added test coverage for valid, out-of-range, and non-finite inputs.
Schema Registration
crates/config_core/src/schema.rs
Added LineHeight variant to RootSettingId enum with key "line_height" and numeric value kind; updated root_setting_default_value() to format line-height via format_line_height(); added unit test.
Settings UI
src/settings_view/sections.rs, src/settings_view/state.rs, src/settings_view/state_apply.rs, src/settings_view/mod.rs
Added EditableField::LineHeight variant with numeric field-spec routing; implemented rendering and value formatting with {:.2} display; added field application logic with parsing, range enforcement, persistence, and in-memory state updates.
Terminal View Integration
src/terminal_view/mod.rs
Updated TerminalView initialization and apply_runtime_config to clamp config.line_height to [MIN_LINE_HEIGHT, MAX_LINE_HEIGHT] during both startup and config reload.
Documentation & Minor Refactoring
docs/configuration.md, crates/terminal_ui/src/grid.rs
Added documentation entry for line_height setting (default 1.4, range 0.82.5, group FONT); refactored grid.rs to remove test-only iter_cells helper and use inline iteration in collect_draw_ops.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Our whiskers twitch with glee today,

Line height now has its perfect way!

From 0.8 to 2.5, hop and bound,

Your terminal's spacing is finally sound! 📏✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add configurable line_height setting' accurately describes the main change: introducing a user-configurable line_height setting across the codebase with validation, UI integration, and persistence.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a user-configurable line_height multiplier to replace the previously hardcoded terminal row-height scaling, wiring it through config parsing/validation, settings UI, and live reload so spacing can be adjusted without restart.

Changes:

  • Introduces line_height config (defaults/range/constants) and parser + schema support.
  • Updates settings UI/state to edit and persist line_height with bounds and stepper behavior.
  • Applies line_height in TerminalView initialization and config reload; updates docs/default config.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/terminal_view/mod.rs Uses config.line_height (clamped) instead of a hardcoded multiplier; updates on config reload.
src/settings_view/state_apply.rs Adds validation and persistence for the new LineHeight editable field.
src/settings_view/state.rs Adds EditableField::LineHeight, numeric stepper config, formatting helper, and updates tests.
src/settings_view/sections.rs Renders the new line-height row in the FONT settings group.
src/main.rs Removes debug-build dock icon setup (unrelated to line-height feature).
docs/configuration.md Documents the new line_height setting.
crates/terminal_ui/src/grid.rs Minor refactor/cleanup in test-only draw-op collection path.
crates/config_core/src/types.rs Adds line_height to AppConfig with default.
crates/config_core/src/schema.rs Adds LineHeight root setting + default value test.
crates/config_core/src/parser_tests.rs Adds parsing/validation coverage for line_height (bounds + NaN/inf).
crates/config_core/src/parser.rs Parses line_height and validates range/finite.
crates/config_core/src/lib.rs Re-exports line-height constants.
crates/config_core/src/default_config.txt Adds default line_height = 1.4.
crates/config_core/src/constants.rs Defines DEFAULT_LINE_HEIGHT, MIN_LINE_HEIGHT, MAX_LINE_HEIGHT.
Cargo.lock Reflects workspace version bump / lockfile updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main.rs
Comment thread src/settings_view/state_apply.rs Outdated
Comment thread src/settings_view/state.rs Outdated
Comment thread crates/config_core/src/parser.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/terminal_view/mod.rs (1)

2966-2966: Add a regression test for startup vs reload clamp parity.

Given clamping exists in two places (Line 2966 and Line 3278), a focused test would guard against drift between init and runtime-reload behavior.

Also applies to: 3278-3278

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/terminal_view/mod.rs` at line 2966, Add a regression test that verifies
clamping parity for config.line_height between the init path and the
runtime-reload path: create a test that constructs a config with line_height
below MIN_LINE_HEIGHT and another above MAX_LINE_HEIGHT, then run the init code
path that produces the initial clamped value and the runtime reload/apply path
(the code that also calls .clamp on line_height) and assert both results equal
the expected clamped value (using MIN_LINE_HEIGHT and MAX_LINE_HEIGHT). Locate
the code via the symbols line_height, MIN_LINE_HEIGHT, MAX_LINE_HEIGHT and the
two code paths (the initializer that sets line_height and the reload/apply
method that reassigns it) and ensure the test covers both negative and oversized
inputs to guard against drift.
crates/config_core/src/schema.rs (1)

482-482: Consider normalizing line-height serialization format across layers.

Line 482 uses to_string(), while src/settings_view/state.rs persists with two decimals. Aligning both would avoid cosmetic 1.4 vs 1.40 config diffs.

♻️ Optional consistency tweak
-        RootSettingId::LineHeight => Some(config.line_height.to_string()),
+        RootSettingId::LineHeight => Some(format!("{:.2}", config.line_height)),
-            Some(defaults.line_height.to_string())
+            Some(format!("{:.2}", defaults.line_height))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/config_core/src/schema.rs` at line 482, The RootSettingId::LineHeight
branch currently serializes with config.line_height.to_string(), causing
inconsistencies with the two-decimal persistence in src/settings_view/state.rs;
change the serialization in the RootSettingId::LineHeight arm to format the
value the same way as settings_view/state.rs (e.g. two decimals) so both layers
produce identical string output—locate the RootSettingId::LineHeight case in
schema.rs and replace the to_string() usage with the same formatting approach
used in settings_view/state.rs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/settings_view/state_apply.rs`:
- Around line 112-116: The code currently assigns self.config.line_height =
parsed before calling config::set_root_setting, which can leave in-memory state
changed if persistence fails; change the order so you call
config::set_root_setting(termy_config_core::RootSettingId::LineHeight,
&parsed.to_string()) first and only assign self.config.line_height = parsed
after that call succeeds (propagate or return the error from set_root_setting on
failure). Locate the update to self.config.line_height and the subsequent call
to config::set_root_setting in state_apply.rs and swap them, ensuring you
preserve the same parsed value and error handling.

---

Nitpick comments:
In `@crates/config_core/src/schema.rs`:
- Line 482: The RootSettingId::LineHeight branch currently serializes with
config.line_height.to_string(), causing inconsistencies with the two-decimal
persistence in src/settings_view/state.rs; change the serialization in the
RootSettingId::LineHeight arm to format the value the same way as
settings_view/state.rs (e.g. two decimals) so both layers produce identical
string output—locate the RootSettingId::LineHeight case in schema.rs and replace
the to_string() usage with the same formatting approach used in
settings_view/state.rs.

In `@src/terminal_view/mod.rs`:
- Line 2966: Add a regression test that verifies clamping parity for
config.line_height between the init path and the runtime-reload path: create a
test that constructs a config with line_height below MIN_LINE_HEIGHT and another
above MAX_LINE_HEIGHT, then run the init code path that produces the initial
clamped value and the runtime reload/apply path (the code that also calls .clamp
on line_height) and assert both results equal the expected clamped value (using
MIN_LINE_HEIGHT and MAX_LINE_HEIGHT). Locate the code via the symbols
line_height, MIN_LINE_HEIGHT, MAX_LINE_HEIGHT and the two code paths (the
initializer that sets line_height and the reload/apply method that reassigns it)
and ensure the test covers both negative and oversized inputs to guard against
drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e0dfec68-4a47-4ad3-89e8-589fd7527de1

📥 Commits

Reviewing files that changed from the base of the PR and between a1f348f and 4499818.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • crates/config_core/src/constants.rs
  • crates/config_core/src/default_config.txt
  • crates/config_core/src/lib.rs
  • crates/config_core/src/parser.rs
  • crates/config_core/src/parser_tests.rs
  • crates/config_core/src/schema.rs
  • crates/config_core/src/types.rs
  • crates/terminal_ui/src/grid.rs
  • docs/configuration.md
  • src/main.rs
  • src/settings_view/sections.rs
  • src/settings_view/state.rs
  • src/settings_view/state_apply.rs
  • src/terminal_view/mod.rs
💤 Files with no reviewable changes (1)
  • src/main.rs

Comment thread src/settings_view/state_apply.rs Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/settings_view/state.rs (1)

1260-1280: Consider asserting line-height step semantics explicitly.

Current test checks presence of numeric_step, but not that Line Height keeps delta=0.05 and min/max bound to termy_config_core::{MIN_LINE_HEIGHT, MAX_LINE_HEIGHT}.

🧪 Suggested test hardening
     fn numeric_step_specs_are_defined_for_numeric_fields() {
         let numeric_fields = [
             EditableField::BackgroundOpacity,
             EditableField::FontSize,
             EditableField::LineHeight,
             EditableField::PaddingX,
             EditableField::PaddingY,
             EditableField::ScrollbackHistory,
             EditableField::InactiveTabScrollback,
             EditableField::ScrollMultiplier,
             EditableField::PaneFocusStrength,
             EditableField::WindowWidth,
             EditableField::WindowHeight,
             EditableField::VerticalTabsWidth,
         ];

         for field in numeric_fields {
             let spec = SettingsWindow::field_spec(field);
             assert_eq!(spec.codec, FieldCodec::Numeric);
             assert!(spec.numeric_step.is_some());
         }
+
+        let line_height_spec = SettingsWindow::field_spec(EditableField::LineHeight);
+        let step = line_height_spec.numeric_step.expect("missing line-height step");
+        assert!((step.delta - 0.05).abs() < f32::EPSILON);
+        assert!((step.min - termy_config_core::MIN_LINE_HEIGHT).abs() < f32::EPSILON);
+        assert!((step.max - termy_config_core::MAX_LINE_HEIGHT).abs() < f32::EPSILON);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/settings_view/state.rs` around lines 1260 - 1280, The test
numeric_step_specs_are_defined_for_numeric_fields currently only checks that
spec.numeric_step is present; add explicit assertions for
EditableField::LineHeight by retrieving let spec =
SettingsWindow::field_spec(EditableField::LineHeight) and assert that
spec.numeric_step.as_ref().unwrap().delta == 0.05 and that
spec.numeric_step.as_ref().unwrap().min == termy_config_core::MIN_LINE_HEIGHT
and spec.numeric_step.as_ref().unwrap().max ==
termy_config_core::MAX_LINE_HEIGHT so the test enforces the expected step
semantics and bounds for LineHeight.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/settings_view/state.rs`:
- Around line 991-999: EditableField::LineHeight handler updates
self.config.line_height before persisting which can leave UI state inconsistent
if config::set_root_setting fails; change the flow in the
EditableField::LineHeight branch to compute next = (self.config.line_height +
(delta as f32 * step.delta)).clamp(...), call
config::set_root_setting(termy_config_core::RootSettingId::LineHeight,
&format_line_height(next)) first, check the Result and only assign
self.config.line_height = next on success (handle/log/propagate the error on
failure instead of mutating in-memory state).

---

Nitpick comments:
In `@src/settings_view/state.rs`:
- Around line 1260-1280: The test
numeric_step_specs_are_defined_for_numeric_fields currently only checks that
spec.numeric_step is present; add explicit assertions for
EditableField::LineHeight by retrieving let spec =
SettingsWindow::field_spec(EditableField::LineHeight) and assert that
spec.numeric_step.as_ref().unwrap().delta == 0.05 and that
spec.numeric_step.as_ref().unwrap().min == termy_config_core::MIN_LINE_HEIGHT
and spec.numeric_step.as_ref().unwrap().max ==
termy_config_core::MAX_LINE_HEIGHT so the test enforces the expected step
semantics and bounds for LineHeight.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b4e8dfc-b5ff-46ce-9fad-3cf2f68f7c47

📥 Commits

Reviewing files that changed from the base of the PR and between 4499818 and a890e7e.

📒 Files selected for processing (5)
  • crates/config_core/src/lib.rs
  • crates/config_core/src/schema.rs
  • src/settings_view/mod.rs
  • src/settings_view/state.rs
  • src/settings_view/state_apply.rs
✅ Files skipped from review due to trivial changes (1)
  • src/settings_view/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/settings_view/state_apply.rs
  • crates/config_core/src/lib.rs

Comment thread src/settings_view/state.rs
@lassejlv
Copy link
Copy Markdown
Member

W pr, let me know when you're done and i will review it :D

@fcoury
Copy link
Copy Markdown
Contributor Author

fcoury commented Mar 23, 2026

@lassejlv thanks! Just finished it, you can go ahead and review it :-)

@lassejlv
Copy link
Copy Markdown
Member

Looks perfect, gonna merge it from here! Thanks for your contribution!

@lassejlv lassejlv merged commit f22bd4e into termy-org:main Mar 23, 2026
1 of 2 checks passed
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.

3 participants