Compare commits

..

112 Commits

Author SHA1 Message Date
Josh McKinney
720303e806 fix: Align clear() semantics with contract (#2320) 2026-01-13 04:46:06 -08:00
dependabot[bot]
5f0331ec89 build(deps): bump taiki-e/install-action from 2.65.13 to 2.66.1 (#2344)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.65.13 to 2.66.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.66.1</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.18.</p>
</li>
<li>
<p>Update <code>ubi@latest</code> to 0.9.0.</p>
</li>
</ul>
<h2>2.66.0</h2>
<ul>
<li>
<p>Support <code>mdbook-mermaid-ssr</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1400">#1400</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Improve support for Windows with MSYS2 bash.</p>
</li>
<li>
<p>Documentation improvements.</p>
</li>
</ul>
<h2>2.65.16</h2>
<ul>
<li>
<p>Update <code>zola@latest</code> to 0.22.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 40.0.1.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.23.2.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.24.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.42.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 0.7.16.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.40.0.</p>
</li>
<li>
<p>Update <code>protoc@latest</code> to 3.33.3.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.27.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.1.1.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.120.</p>
</li>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.19.0.</p>
</li>
</ul>
<h2>2.65.15</h2>
<ul>
<li>
<p>Update <code>parse-dockerfile@latest</code> to 0.1.3.</p>
</li>
<li>
<p>Update <code>parse-changelog@latest</code> to 0.6.15.</p>
</li>
<li>
<p>Update <code>cargo-llvm-cov@latest</code> to 0.6.23.</p>
</li>
<li>
<p>Update <code>cargo-hack@latest</code> to 0.6.41.</p>
</li>
<li>
<p>Update <code>cargo-minimal-versions@latest</code> to 0.1.35.</p>
</li>
<li>
<p>Update <code>cargo-no-dev-deps@latest</code> to 0.2.20.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<ul>
<li>
<p>Update <code>protoc@latest</code> to 3.33.4.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.22.0.</p>
</li>
</ul>
<h2>[2.66.1] - 2026-01-11</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.18.</p>
</li>
<li>
<p>Update <code>ubi@latest</code> to 0.9.0.</p>
</li>
</ul>
<h2>[2.66.0] - 2026-01-10</h2>
<ul>
<li>
<p>Support <code>mdbook-mermaid-ssr</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1400">#1400</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Improve support for Windows with MSYS2 bash.</p>
</li>
<li>
<p>Documentation improvements.</p>
</li>
</ul>
<h2>[2.65.16] - 2026-01-10</h2>
<ul>
<li>
<p>Update <code>zola@latest</code> to 0.22.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 40.0.1.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.23.2.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.24.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.42.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 0.7.16.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.40.0.</p>
</li>
<li>
<p>Update <code>protoc@latest</code> to 3.33.3.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.27.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3522286d40"><code>3522286</code></a>
Release 2.66.1</li>
<li><a
href="0ed1c967ed"><code>0ed1c96</code></a>
Update changelog</li>
<li><a
href="e69513dca4"><code>e69513d</code></a>
Update <code>tombi@latest</code> to 0.7.18</li>
<li><a
href="4c5e3dc538"><code>4c5e3dc</code></a>
Update <code>ubi@latest</code> to 0.9.0</li>
<li><a
href="e2cc276530"><code>e2cc276</code></a>
Update <code>tombi@latest</code> to 0.7.17</li>
<li><a
href="8fb4e4b842"><code>8fb4e4b</code></a>
Update .deny.toml</li>
<li><a
href="83961fc0a2"><code>83961fc</code></a>
Release 2.66.0</li>
<li><a
href="c761556c39"><code>c761556</code></a>
Update changelog</li>
<li><a
href="f19ed92a93"><code>f19ed92</code></a>
Workaround MSYS2 bash issue</li>
<li><a
href="e53d9e37e3"><code>e53d9e3</code></a>
docs: Clarify &quot;tool is supported&quot; doesn't mean &quot;tool is
trusted or reviewed b...</li>
<li>Additional commits viewable in <a
href="0e76c5c569...3522286d40">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.65.13&new-version=2.66.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 10:27:34 +03:00
dependabot[bot]
eeed03cba2 build(deps): bump EmbarkStudios/cargo-deny-action from 2.0.14 to 2.0.15 (#2345)
Bumps
[EmbarkStudios/cargo-deny-action](https://github.com/embarkstudios/cargo-deny-action)
from 2.0.14 to 2.0.15.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3fd3802e88"><code>3fd3802</code></a>
Bump to 0.19.0</li>
<li>See full diff in <a
href="76cd80eb77...3fd3802e88">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=EmbarkStudios/cargo-deny-action&package-manager=github_actions&previous-version=2.0.14&new-version=2.0.15)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 10:27:20 +03:00
dependabot[bot]
c3b575e24e build(deps): bump crate-ci/typos from 1.41.0 to 1.42.0 (#2346)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.41.0 to
1.42.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.42.0</h2>
<h2>[1.42.0] - 2026-01-07</h2>
<h3>Features</h3>
<ul>
<li>Dictionary updates</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.42.0] - 2026-01-07</h2>
<h3>Features</h3>
<ul>
<li>Dictionary updates</li>
</ul>
<h2>[1.41.0] - 2025-12-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1431">December
2025</a> changes</li>
</ul>
<h2>[1.40.1] - 2025-12-29</h2>
<h3>Fixes</h3>
<ul>
<li>Treat <code>incrementer</code> and <code>incrementor</code> the same
for now</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't correct ITerm2</li>
</ul>
<h2>[1.40.0] - 2025-11-26</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1405">November
2025</a> changes</li>
</ul>
<h2>[1.39.2] - 2025-11-13</h2>
<h3>Fixes</h3>
<ul>
<li>Don't offer <code>entry</code> as a correction for
<code>entrys</code></li>
</ul>
<h2>[1.39.1] - 2025-11-12</h2>
<h3>Features</h3>
<ul>
<li>Make <code>--help</code> more vibrant</li>
</ul>
<h2>[1.39.0] - 2025-10-31</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bb4666ad77"><code>bb4666a</code></a>
chore: Release</li>
<li><a
href="6995a8a1d2"><code>6995a8a</code></a>
chore: Release</li>
<li><a
href="e0227ba473"><code>e0227ba</code></a>
docs: Update changelog</li>
<li><a
href="c4054dbccf"><code>c4054db</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1460">#1460</a>
from epage/wiki</li>
<li><a
href="596a0bd11d"><code>596a0bd</code></a>
feat(dict): Extend from misspell's list</li>
<li><a
href="2d459793db"><code>2d45979</code></a>
refactor(misspell): Reformat dict to look like ours</li>
<li><a
href="54e1366637"><code>54e1366</code></a>
feat(dict): Extend from codespell's list</li>
<li><a
href="74e0660315"><code>74e0660</code></a>
feat(dict): Extend from wikipedia's list</li>
<li><a
href="a2568ec213"><code>a2568ec</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1459">#1459</a>
from epage/update</li>
<li><a
href="c360cf6c3d"><code>c360cf6</code></a>
fix(wikipedia): Update dict</li>
<li>Additional commits viewable in <a
href="5c19779cb5...bb4666ad77">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.41.0&new-version=1.42.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 10:27:05 +03:00
dependabot[bot]
6fdb3fa18e build(deps): bump serde_json from 1.0.148 to 1.0.149 (#2347)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.148 to
1.0.149.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/serde-rs/json/releases">serde_json's
releases</a>.</em></p>
<blockquote>
<h2>v1.0.149</h2>
<ul>
<li>Align arbitrary_precision number strings with zmij's formatting (<a
href="https://redirect.github.com/serde-rs/json/issues/1306">#1306</a>,
thanks <a href="https://github.com/b41sh"><code>@​b41sh</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4f6dbfac79"><code>4f6dbfa</code></a>
Release 1.0.149</li>
<li><a
href="f3df680098"><code>f3df680</code></a>
Touch up PR 1306</li>
<li><a
href="e16730ff44"><code>e16730f</code></a>
Merge pull request <a
href="https://redirect.github.com/serde-rs/json/issues/1306">#1306</a>
from b41sh/fix-float-number-display</li>
<li><a
href="eeb2bcd3f2"><code>eeb2bcd</code></a>
Align <code>arbitrary_precision</code> number strings with zmij’s
formatting</li>
<li>See full diff in <a
href="https://github.com/serde-rs/json/compare/v1.0.148...v1.0.149">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde_json&package-manager=cargo&previous-version=1.0.148&new-version=1.0.149)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 10:26:49 +03:00
Dheepak Krishnamurthy
ab5ad3fc7c chore: escape username using backticks in changelog (#2336)
The motivation behind this is that GitHub mentions in PR descriptions trigger notifications for every contributor for every release because their username is part of the changelog.
2026-01-07 18:02:37 -08:00
dependabot[bot]
332658406c build(deps): bump lru from 0.16.2 to 0.16.3 in the cargo group across 1 directory (#2337)
Bumps the cargo group with 1 update in the / directory:
[lru](https://github.com/jeromefroe/lru-rs).

Updates `lru` from 0.16.2 to 0.16.3
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md">lru's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/jeromefroe/lru-rs/tree/0.16.3">v0.16.3</a> -
2026-01-07</h2>
<ul>
<li>Fix Stacked Borrows violation in <code>IterMut</code>.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="af233e5c36"><code>af233e5</code></a>
Merge pull request <a
href="https://redirect.github.com/jeromefroe/lru-rs/issues/225">#225</a>
from jeromefroe/jerome/prepare-0-16-3-release</li>
<li><a
href="cf56f9a5dd"><code>cf56f9a</code></a>
Prepare 0.16.3 release</li>
<li><a
href="62be24c961"><code>62be24c</code></a>
Merge pull request <a
href="https://redirect.github.com/jeromefroe/lru-rs/issues/224">#224</a>
from paolobarbolini/iter-mut-stacked-borrows-violation</li>
<li><a
href="25669e7611"><code>25669e7</code></a>
Add regression test for <code>IterMut</code> stacked borrows
violation</li>
<li><a
href="b9bca3492d"><code>b9bca34</code></a>
Fix stacked borrows violation in <code>IterMut::next</code> and
<code>IterMut::next_back</code></li>
<li>See full diff in <a
href="https://github.com/jeromefroe/lru-rs/compare/0.16.2...0.16.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=lru&package-manager=cargo&previous-version=0.16.2&new-version=0.16.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/ratatui/ratatui/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 18:00:57 -08:00
Josh McKinney
ae975c7200 feat(examples): allow overlap spacing in explorer (#2316)
Store spacing as i16 so negative values map to Spacing::Overlap, and
show overlap in the axis label.

Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2026-01-06 17:23:44 -08:00
Josh McKinney
3df8c20dfb docs: ask issue authors about PR willingness (#2317)
Add a contribution question to the bug report and feature request
templates so maintainers know whether the reporter wants to work on a
fix/PR or needs guidance.
2026-01-06 17:22:48 -08:00
dependabot[bot]
2dcf1a61c1 build(deps): bump rsa from 0.9.9 to 0.9.10 in the cargo group across 1 directory (#2334)
Bumps the cargo group with 1 update in the / directory:
[rsa](https://github.com/RustCrypto/RSA).

Updates `rsa` from 0.9.9 to 0.9.10
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/RustCrypto/RSA/blob/v0.9.10/CHANGELOG.md">rsa's
changelog</a>.</em></p>
<blockquote>
<h2>0.9.10 (2026-01-06)</h2>
<h3>Fixed</h3>
<ul>
<li>do not panic on a prime being 1 when loading a secret key (<a
href="https://redirect.github.com/RustCrypto/RSA/issues/624">#624</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/RustCrypto/RSA/issues/624">#624</a>:
<a
href="https://redirect.github.com/RustCrypto/RSA/pull/624">RustCrypto/RSA#624</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="da2af9a0ff"><code>da2af9a</code></a>
chore: release v0.9.10</li>
<li><a
href="2926c91bef"><code>2926c91</code></a>
fix: do not panic on a prime being 1 when loading a secret key (<a
href="https://redirect.github.com/RustCrypto/RSA/issues/624">#624</a>)</li>
<li>See full diff in <a
href="https://github.com/RustCrypto/RSA/compare/v0.9.9...v0.9.10">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rsa&package-manager=cargo&previous-version=0.9.9&new-version=0.9.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/ratatui/ratatui/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-07 00:31:02 +03:00
dependabot[bot]
6ce4a7e84b build(deps): bump octocrab from 0.49.4 to 0.49.5 (#2328)
Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.49.4 to
0.49.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.49.5</h2>
<h3>Fixed</h3>
<ul>
<li>resolve docs.rs build failure (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/848">#848</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.4...v0.49.5">0.49.5</a>
- 2025-12-30</h2>
<h3>Fixed</h3>
<ul>
<li>resolve docs.rs build failure (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/848">#848</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d4fde40841"><code>d4fde40</code></a>
chore: release v0.49.5 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/849">#849</a>)</li>
<li><a
href="81da9b10e9"><code>81da9b1</code></a>
fix: resolve docs.rs build failure (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/848">#848</a>)</li>
<li>See full diff in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.4...v0.49.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.49.4&new-version=0.49.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:13:49 +03:00
dependabot[bot]
e0687aa155 build(deps): bump tokio from 1.48.0 to 1.49.0 (#2327)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.48.0 to 1.49.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tokio/releases">tokio's
releases</a>.</em></p>
<blockquote>
<h2>Tokio v1.49.0</h2>
<h1>1.49.0 (January 3rd, 2026)</h1>
<h3>Added</h3>
<ul>
<li>net: add support for <code>TCLASS</code> option on IPv6 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7781">#7781</a>)</li>
<li>runtime: stabilize <code>runtime::id::Id</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7125">#7125</a>)</li>
<li>task: implement <code>Extend</code> for <code>JoinSet</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7195">#7195</a>)</li>
<li>task: stabilize the <code>LocalSet::id()</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7776">#7776</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>net: deprecate <code>{TcpStream,TcpSocket}::set_linger</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7752">#7752</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>macros: fix the hygiene issue of <code>join!</code> and
<code>try_join!</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7766">#7766</a>)</li>
<li>runtime: revert &quot;replace manual vtable definitions with
Wake&quot; (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7699">#7699</a>)</li>
<li>sync: return <code>TryRecvError::Disconnected</code> from
<code>Receiver::try_recv</code> after <code>Receiver::close</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7686">#7686</a>)</li>
<li>task: remove unnecessary trait bounds on the <code>Debug</code>
implementation (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7720">#7720</a>)</li>
</ul>
<h3>Unstable</h3>
<ul>
<li>fs: handle <code>EINTR</code> in <code>fs::write</code> for io-uring
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7786">#7786</a>)</li>
<li>fs: support io-uring with <code>tokio::fs::read</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7696">#7696</a>)</li>
<li>runtime: disable io-uring on <code>EPERM</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7724">#7724</a>)</li>
<li>time: add alternative timer for better multicore scalability (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7467">#7467</a>)</li>
</ul>
<h3>Documented</h3>
<ul>
<li>docs: fix a typos in <code>bounded.rs</code> and
<code>park.rs</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7817">#7817</a>)</li>
<li>io: add <code>SyncIoBridge</code> cross-references to
<code>copy</code> and <code>copy_buf</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7798">#7798</a>)</li>
<li>io: doc that <code>AsyncWrite</code> does not inherit from
<code>std::io::Write</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7705">#7705</a>)</li>
<li>metrics: clarify that <code>num_alive_tasks</code> is not strongly
consistent (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7614">#7614</a>)</li>
<li>net: clarify the cancellation safety of the
<code>TcpStream::peek</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7305">#7305</a>)</li>
<li>net: clarify the drop behavior of <code>unix::OwnedWriteHalf</code>
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7742">#7742</a>)</li>
<li>net: clarify the platform-dependent backlog in
<code>TcpSocket</code> docs (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7738">#7738</a>)</li>
<li>runtime: mention <code>LocalRuntime</code> in
<code>new_current_thread</code> docs (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7820">#7820</a>)</li>
<li>sync: add missing period to <code>mpsc::Sender::try_send</code> docs
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7721">#7721</a>)</li>
<li>sync: clarify the cancellation safety of
<code>oneshot::Receiver</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7780">#7780</a>)</li>
<li>sync: improve the docs for the <code>errors</code> of mpsc (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7722">#7722</a>)</li>
<li>task: add example for <code>spawn_local</code> usage on local
runtime (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7689">#7689</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tokio/issues/7125">#7125</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7125">tokio-rs/tokio#7125</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7195">#7195</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7195">tokio-rs/tokio#7195</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7305">#7305</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7305">tokio-rs/tokio#7305</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7467">#7467</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7467">tokio-rs/tokio#7467</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7614">#7614</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7614">tokio-rs/tokio#7614</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7686">#7686</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7686">tokio-rs/tokio#7686</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7689">#7689</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7689">tokio-rs/tokio#7689</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e3b89bbefa"><code>e3b89bb</code></a>
chore: prepare Tokio v1.49.0 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7824">#7824</a>)</li>
<li><a
href="4f577b84e9"><code>4f577b8</code></a>
Merge 'tokio-1.47.3' into 'master'</li>
<li><a
href="f320197693"><code>f320197</code></a>
chore: prepare Tokio v1.47.3 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7823">#7823</a>)</li>
<li><a
href="ea6b144cd1"><code>ea6b144</code></a>
ci: freeze rustc on nightly-2025-01-25 in <code>netlify.toml</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7652">#7652</a>)</li>
<li><a
href="264e703296"><code>264e703</code></a>
Merge <code>tokio-1.43.4</code> into <code>tokio-1.47.x</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7822">#7822</a>)</li>
<li><a
href="dfb0f00838"><code>dfb0f00</code></a>
chore: prepare Tokio v1.43.4 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7821">#7821</a>)</li>
<li><a
href="4a91f197b0"><code>4a91f19</code></a>
ci: fix wasm32-wasip1 tests (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7788">#7788</a>)</li>
<li><a
href="601c383ab6"><code>601c383</code></a>
ci: upgrade FreeBSD from 14.2 to 14.3 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7758">#7758</a>)</li>
<li><a
href="484cb52d8d"><code>484cb52</code></a>
sync: return <code>TryRecvError::Disconnected</code> from
<code>Receiver::try_recv</code> after `Re...</li>
<li><a
href="16f20c34ed"><code>16f20c3</code></a>
rt: mention <code>LocalRuntime</code> in <code>new_current_thread</code>
docs (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7820">#7820</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tokio/compare/tokio-1.48.0...tokio-1.49.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tokio&package-manager=cargo&previous-version=1.48.0&new-version=1.49.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:13:30 +03:00
dependabot[bot]
0346476ddf build(deps): bump crate-ci/typos from 1.40.0 to 1.41.0 (#2325)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.40.0 to
1.41.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.41.0</h2>
<h2>[1.41.0] - 2025-12-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1431">December
2025</a> changes</li>
</ul>
<h2>v1.40.1</h2>
<h2>[1.40.1] - 2025-12-29</h2>
<h3>Fixes</h3>
<ul>
<li>Treat <code>incrementer</code> and <code>incrementor</code> the same
for now</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't correct ITerm2</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.41.0] - 2025-12-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1431">December
2025</a> changes</li>
</ul>
<h2>[1.40.1] - 2025-12-29</h2>
<h3>Fixes</h3>
<ul>
<li>Treat <code>incrementer</code> and <code>incrementor</code> the same
for now</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't correct ITerm2</li>
</ul>
<h2>[1.40.0] - 2025-11-26</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1405">November
2025</a> changes</li>
</ul>
<h2>[1.39.2] - 2025-11-13</h2>
<h3>Fixes</h3>
<ul>
<li>Don't offer <code>entry</code> as a correction for
<code>entrys</code></li>
</ul>
<h2>[1.39.1] - 2025-11-12</h2>
<h3>Features</h3>
<ul>
<li>Make <code>--help</code> more vibrant</li>
</ul>
<h2>[1.39.0] - 2025-10-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1383">October
2025</a> changes</li>
</ul>
<h3>Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5c19779cb5"><code>5c19779</code></a>
chore: Release</li>
<li><a
href="cf11fdd0ca"><code>cf11fdd</code></a>
chore: Release</li>
<li><a
href="54e83d2a58"><code>54e83d2</code></a>
docs: Update changelog</li>
<li><a
href="fbd7b69944"><code>fbd7b69</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1454">#1454</a>
from epage/dec</li>
<li><a
href="5dc35c7a63"><code>5dc35c7</code></a>
feat(dict): December additions</li>
<li><a
href="1a319b54cc"><code>1a319b5</code></a>
chore: Release</li>
<li><a
href="00852bb03b"><code>00852bb</code></a>
docs: Update changelog</li>
<li><a
href="1d4327057a"><code>1d43270</code></a>
chore: Release</li>
<li><a
href="770146db44"><code>770146d</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1452">#1452</a>
from epage/incrementer</li>
<li><a
href="6bf28995c6"><code>6bf2899</code></a>
fix(dict): Be neutral on incrementer vs incrementor</li>
<li>Additional commits viewable in <a
href="2d0ce569fe...5c19779cb5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.40.0&new-version=1.41.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:13:10 +03:00
dependabot[bot]
fd8c1a4010 build(deps): bump taiki-e/install-action from 2.65.7 to 2.65.13 (#2326)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.65.7 to 2.65.13.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.65.13</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.118.</p>
</li>
<li>
<p>Update <code>martin@latest</code> to 1.2.0.</p>
</li>
<li>
<p>Update <code>cargo-insta@latest</code> to 1.46.0.</p>
</li>
</ul>
<h2>2.65.12</h2>
<ul>
<li>
<p>Update <code>just@latest</code> to 1.46.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.117.</p>
</li>
</ul>
<h2>2.65.11</h2>
<ul>
<li>
<p>Update <code>cargo-tarpaulin@latest</code> to 0.35.0.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.41.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.23.0.</p>
</li>
</ul>
<h2>2.65.10</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.13.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.21.</p>
</li>
</ul>
<h2>2.65.9</h2>
<ul>
<li>Update <code>cargo-llvm-cov@latest</code> to 0.6.22.</li>
</ul>
<h2>2.65.8</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.14.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.20.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.40.1.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.65.13] - 2026-01-05</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.118.</p>
</li>
<li>
<p>Update <code>martin@latest</code> to 1.2.0.</p>
</li>
<li>
<p>Update <code>cargo-insta@latest</code> to 1.46.0.</p>
</li>
</ul>
<h2>[2.65.12] - 2026-01-02</h2>
<ul>
<li>
<p>Update <code>just@latest</code> to 1.46.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.117.</p>
</li>
</ul>
<h2>[2.65.11] - 2026-01-01</h2>
<ul>
<li>
<p>Update <code>cargo-tarpaulin@latest</code> to 0.35.0.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.41.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.23.0.</p>
</li>
</ul>
<h2>[2.65.10] - 2025-12-31</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.13.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.21.</p>
</li>
</ul>
<h2>[2.65.9] - 2025-12-30</h2>
<ul>
<li>Update <code>cargo-llvm-cov@latest</code> to 0.6.22.</li>
</ul>
<h2>[2.65.8] - 2025-12-30</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.14.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.20.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0e76c5c569"><code>0e76c5c</code></a>
Release 2.65.13</li>
<li><a
href="0466464eeb"><code>0466464</code></a>
Update <code>cargo-nextest@latest</code> to 0.9.118</li>
<li><a
href="389b56344a"><code>389b563</code></a>
Update <code>martin@latest</code> to 1.2.0</li>
<li><a
href="83028a3bd2"><code>83028a3</code></a>
Update <code>cargo-insta@latest</code> to 1.46.0</li>
<li><a
href="cc33365ec7"><code>cc33365</code></a>
Release 2.65.12</li>
<li><a
href="8f085a196a"><code>8f085a1</code></a>
Update <code>just@latest</code> to 1.46.0</li>
<li><a
href="6b0d292eb8"><code>6b0d292</code></a>
Update <code>cargo-nextest@latest</code> to 0.9.117</li>
<li><a
href="a983ca7951"><code>a983ca7</code></a>
Release 2.65.11</li>
<li><a
href="66de739d66"><code>66de739</code></a>
Update <code>cargo-tarpaulin@latest</code> to 0.35.0</li>
<li><a
href="790813cf48"><code>790813c</code></a>
Update <code>typos@latest</code> to 1.41.0</li>
<li>Additional commits viewable in <a
href="4c6723ec9c...0e76c5c569">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.65.7&new-version=2.65.13)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:12:56 +03:00
dependabot[bot]
dd6621daf9 build(deps): bump tokio-stream from 0.1.17 to 0.1.18 (#2330)
Bumps [tokio-stream](https://github.com/tokio-rs/tokio) from 0.1.17 to
0.1.18.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="60b083b630"><code>60b083b</code></a>
chore: prepare tokio-stream 0.1.18 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7830">#7830</a>)</li>
<li><a
href="9cc02cc88d"><code>9cc02cc</code></a>
chore: prepare tokio-util 0.7.18 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7829">#7829</a>)</li>
<li><a
href="d2799d791b"><code>d2799d7</code></a>
task: improve the docs of <code>Builder::spawn_local</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7828">#7828</a>)</li>
<li><a
href="4d4870f291"><code>4d4870f</code></a>
task: doc that task drops before JoinHandle completion (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7825">#7825</a>)</li>
<li><a
href="fdb150901a"><code>fdb1509</code></a>
fs: check for io-uring opcode support (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7815">#7815</a>)</li>
<li><a
href="426a562780"><code>426a562</code></a>
rt: remove <code>allow(dead_code)</code> after <code>JoinSet</code>
stabilization (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7826">#7826</a>)</li>
<li><a
href="e3b89bbefa"><code>e3b89bb</code></a>
chore: prepare Tokio v1.49.0 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7824">#7824</a>)</li>
<li><a
href="4f577b84e9"><code>4f577b8</code></a>
Merge 'tokio-1.47.3' into 'master'</li>
<li><a
href="f320197693"><code>f320197</code></a>
chore: prepare Tokio v1.47.3 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7823">#7823</a>)</li>
<li><a
href="ea6b144cd1"><code>ea6b144</code></a>
ci: freeze rustc on nightly-2025-01-25 in <code>netlify.toml</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7652">#7652</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tokio/compare/tokio-stream-0.1.17...tokio-stream-0.1.18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tokio-stream&package-manager=cargo&previous-version=0.1.17&new-version=0.1.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:11:56 +03:00
dependabot[bot]
d37db578b8 build(deps): bump clap from 4.5.53 to 4.5.54 (#2331)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.53 to 4.5.54.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/releases">clap's
releases</a>.</em></p>
<blockquote>
<h2>v4.5.54</h2>
<h2>[4.5.54] - 2026-01-02</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Move <code>[default]</code> to its own paragraph
when <code>PossibleValue::help</code> is present in
<code>--help</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/blob/master/CHANGELOG.md">clap's
changelog</a>.</em></p>
<blockquote>
<h2>[4.5.54] - 2026-01-02</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Move <code>[default]</code> to its own paragraph
when <code>PossibleValue::help</code> is present in
<code>--help</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="194c676f60"><code>194c676</code></a>
chore: Release</li>
<li><a
href="44838f6606"><code>44838f6</code></a>
docs: Update changelog</li>
<li><a
href="0f59d55ff6"><code>0f59d55</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6027">#6027</a>
from Alpha1337k/master</li>
<li><a
href="e2aa2f07d1"><code>e2aa2f0</code></a>
Feat: Add catch-all on external subcommands for zsh</li>
<li><a
href="b9c0aee9f2"><code>b9c0aee</code></a>
Feat: Add external subcommands test to suite</li>
<li>See full diff in <a
href="https://github.com/clap-rs/clap/compare/clap_complete-v4.5.53...clap_complete-v4.5.54">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=clap&package-manager=cargo&previous-version=4.5.53&new-version=4.5.54)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-05 23:07:55 +03:00
Colton Loftus
53d925a8ab docs: Add Documentation on the Map Projection / CRS (#2324) 2026-01-04 21:31:10 -08:00
0xferrous
1e0ab0c549 feat(ratatui-crossterm): add IntoCrossterm<ContentStyle> for Style (#2323) 2026-01-04 01:57:29 -08:00
Orhun Parmaksız
e82b3b77fe docs(buffer): run the doctests for Buffer (#2319)
addresses
https://github.com/ratatui/ratatui/pull/2314#pullrequestreview-3621576941

the doctest was not running at all... (due to `fn foo`)
2026-01-01 23:59:26 +03:00
Josh McKinney
b696ea37b2 test(core): Split Terminal into submodules and expand test coverage (#2315)
- Split the `Terminal` implementation into focused submodules to improve
readability and maintainability.
- Add characterization tests covering `Terminal` initialization, buffer
lifecycle, resizing and autoresize behavior, and rendering paths.
- Add inline viewport tests for `compute_inline_size` and
`insert_before` in both fallback and scrolling-regions modes, including
an end-to-end `draw -> insert_before -> draw scenario` scenario.
- Extend `TestBackend` cursor plumbing to support the new terminal tests
and assert cursor/ behavior.
2026-01-01 11:46:33 -08:00
Josh McKinney
64d964b259 docs: Update Terminal docs (#2312)
## Summary

- Improve `Terminal` Rustdocs to better explain typical app setup, the
rendering pipeline, and how
diff-based rendering works (including full redraw behavior on viewport
size changes).
- Clarify viewport concepts and behavior in `Viewport`/`Terminal` docs,
with a more complete inline
  section (anchoring, scrolling, resize behavior).
- Reorder `Terminal::draw` / `Terminal::try_draw` closer to constructors
so the primary rendering
  entry points are easier to find.

## Notes

- Docs-only change; no public API or runtime behavior changes.
- No new tests in this PR.

## Test Plan

- `cargo +nightly fmt`
- `cargo +nightly docs-rs -p ratatui-core`
- `cargo test -p ratatui-core --doc --features std`
2026-01-01 11:15:55 -08:00
homebrewmellow
8d73d4738e docs: Fix comment to reflect correct symbol in assertion (#2314) 2025-12-31 18:22:41 -08:00
n4n5
556cc7b543 feat: add comment for inner area to popup example (#2309) 2025-12-31 18:21:04 -08:00
cgzones
fbd562117b docs: fix misspellings (#2310) 2025-12-30 18:36:14 +03:00
Alan Somers
d2b0ce17a4 fix: Fix the dependency on time (#2306)
ratatui-widgets uses time's Month::length(), which requires time-0.3.37
or later.
2025-12-29 12:38:09 -08:00
Josh McKinney
01a15f9809 feat: Add AsRef impls for widget types (#2297) 2025-12-29 11:16:27 -08:00
dependabot[bot]
1c9f56aa4b build(deps): bump octocrab from 0.49.2 to 0.49.4 (#2305)
Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.49.2 to
0.49.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.49.4</h2>
<h3>Added</h3>
<ul>
<li>Add squash_merge_commit_title, squash_merge_commit_title to repo
model (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/845">#845</a>)</li>
</ul>
<h2>v0.49.3</h2>
<h3>Added</h3>
<ul>
<li>Http caching &amp; Conditional requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/831">#831</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.3...v0.49.4">0.49.4</a>
- 2025-12-25</h2>
<h3>Added</h3>
<ul>
<li>Add squash_merge_commit_title, squash_merge_commit_title to repo
model (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/845">#845</a>)</li>
</ul>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.2...v0.49.3">0.49.3</a>
- 2025-12-21</h2>
<h3>Added</h3>
<ul>
<li>Http caching &amp; Conditional requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/831">#831</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4ffda40672"><code>4ffda40</code></a>
chore: release v0.49.4 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/846">#846</a>)</li>
<li><a
href="0c20a918d6"><code>0c20a91</code></a>
feat: Add squash_merge_commit_title, squash_merge_commit_title to repo
model ...</li>
<li><a
href="73799b212a"><code>73799b2</code></a>
chore: release v0.49.3 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/844">#844</a>)</li>
<li><a
href="c08ad2e894"><code>c08ad2e</code></a>
feat: Http caching &amp; Conditional requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/831">#831</a>)</li>
<li>See full diff in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.2...v0.49.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.49.2&new-version=0.49.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 18:40:21 +03:00
dependabot[bot]
0e89e042e0 build(deps): bump serde_json from 1.0.146 to 1.0.148 (#2304)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.146 to
1.0.148.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/serde-rs/json/releases">serde_json's
releases</a>.</em></p>
<blockquote>
<h2>v1.0.148</h2>
<ul>
<li>Update <code>zmij</code> dependency to 1.0</li>
</ul>
<h2>v1.0.147</h2>
<ul>
<li>Switch float-to-string algorithm from Ryū to Żmij for better f32 and
f64 serialization performance (<a
href="https://redirect.github.com/serde-rs/json/issues/1304">#1304</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8b291c4c56"><code>8b291c4</code></a>
Release 1.0.148</li>
<li><a
href="1aefe15273"><code>1aefe15</code></a>
Update to zmij 1.0</li>
<li><a
href="62d6e8d615"><code>62d6e8d</code></a>
Release 1.0.147</li>
<li><a
href="fd829a65be"><code>fd829a6</code></a>
Merge pull request <a
href="https://redirect.github.com/serde-rs/json/issues/1304">#1304</a>
from dtolnay/zmij</li>
<li><a
href="e757a3d881"><code>e757a3d</code></a>
Switch from ryu -&gt; zmij for float formatting</li>
<li>See full diff in <a
href="https://github.com/serde-rs/json/compare/v1.0.146...v1.0.148">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde_json&package-manager=cargo&previous-version=1.0.146&new-version=1.0.148)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 18:39:32 +03:00
dependabot[bot]
2e73be7982 build(deps): bump taiki-e/install-action from 2.65.1 to 2.65.7 (#2303)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.65.1 to 2.65.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.65.7</h2>
<ul>
<li>
<p>Update <code>cargo-no-dev-deps@latest</code> to 0.2.19.</p>
</li>
<li>
<p>Update <code>cargo-minimal-versions@latest</code> to 0.1.34.</p>
</li>
<li>
<p>Update <code>cargo-insta@latest</code> to 1.45.1.</p>
</li>
<li>
<p>Update <code>cargo-hack@latest</code> to 0.6.40.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.51.1.</p>
</li>
</ul>
<h2>2.65.6</h2>
<ul>
<li>
<p>Update <code>dprint@latest</code> to 0.51.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.22.0.</p>
</li>
</ul>
<h2>2.65.5</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.12.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.6.</p>
</li>
</ul>
<h2>2.65.4</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.116.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.25.</p>
</li>
</ul>
<h2>2.65.3</h2>
<ul>
<li>Update <code>tombi@latest</code> to 0.7.11.</li>
</ul>
<h2>2.65.2</h2>
<ul>
<li>
<p>Update <code>prek@latest</code> to 0.2.24.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 40.0.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.21.7.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 0.7.10.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.39.0.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.5.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<ul>
<li>Update <code>tombi@latest</code> to 0.7.13.</li>
</ul>
<h2>[2.65.7] - 2025-12-29</h2>
<ul>
<li>
<p>Update <code>cargo-no-dev-deps@latest</code> to 0.2.19.</p>
</li>
<li>
<p>Update <code>cargo-minimal-versions@latest</code> to 0.1.34.</p>
</li>
<li>
<p>Update <code>cargo-insta@latest</code> to 1.45.1.</p>
</li>
<li>
<p>Update <code>cargo-hack@latest</code> to 0.6.40.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.51.1.</p>
</li>
</ul>
<h2>[2.65.6] - 2025-12-28</h2>
<ul>
<li>
<p>Update <code>dprint@latest</code> to 0.51.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.22.0.</p>
</li>
</ul>
<h2>[2.65.5] - 2025-12-27</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.12.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.6.</p>
</li>
</ul>
<h2>[2.65.4] - 2025-12-27</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.116.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.25.</p>
</li>
</ul>
<h2>[2.65.3] - 2025-12-26</h2>
<ul>
<li>Update <code>tombi@latest</code> to 0.7.11.</li>
</ul>
<h2>[2.65.2] - 2025-12-23</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4c6723ec9c"><code>4c6723e</code></a>
Release 2.65.7</li>
<li><a
href="9ff15877d9"><code>9ff1587</code></a>
Update <code>cargo-no-dev-deps@latest</code> to 0.2.19</li>
<li><a
href="4f0419fae3"><code>4f0419f</code></a>
Update <code>cargo-minimal-versions@latest</code> to 0.1.34</li>
<li><a
href="1eecdc5eb1"><code>1eecdc5</code></a>
Update <code>cargo-insta@latest</code> to 1.45.1</li>
<li><a
href="cff8e9966c"><code>cff8e99</code></a>
Update <code>cargo-hack@latest</code> to 0.6.40</li>
<li><a
href="080e4ee4f5"><code>080e4ee</code></a>
Update <code>dprint@latest</code> to 0.51.1</li>
<li><a
href="28a9d316db"><code>28a9d31</code></a>
Release 2.65.6</li>
<li><a
href="323c4aadcd"><code>323c4aa</code></a>
Update <code>dprint@latest</code> to 0.51.0</li>
<li><a
href="bfbd3b229c"><code>bfbd3b2</code></a>
Update <code>vacuum@latest</code> to 0.22.0</li>
<li><a
href="45a93d9c71"><code>45a93d9</code></a>
Release 2.65.5</li>
<li>Additional commits viewable in <a
href="b9c5db3aef...4c6723ec9c">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.65.1&new-version=2.65.7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 18:39:08 +03:00
Kareem Khazem
f9d066f4d7 feat(table): let Cells span multiple columns (#2150)
Add a 'column_span' field to table cells. The default value
is 1; larger values will cause cells to span over multiple columns,
being rendered over all columns plus the spaces between them.

Fixes #1568.
2025-12-28 21:25:42 -08:00
Josh McKinney
65c520245a fix(changelog): fix typo (#2300) 2025-12-27 22:19:39 +03:00
Orhun Parmaksız
f8b42adb5f docs(breaking-changes): update header for 0.30.0 (#2295) 2025-12-26 13:20:21 +03:00
github-actions[bot]
0a2a7c0363 chore(ratatui): unleash the rats v0.30.0 (#2294)
## [v0.30.0](https://github.com/ratatui/ratatui/releases/tag/v0.30.0) -
2025-12-26

> _"Rats don't just survive; they discover; they create. ... I mean,
just look at what they do with
the terminal!" – Remy & Orhun_

We are excited to announce the biggest release of `ratatui` so far - a
Rust library that's all about cooking up TUIs 👨‍🍳🐀

🌠 Added "no_std" support for embedded targets, modularized architecture,
major widget & layout upgrades!

 **Release highlights**: <https://ratatui.rs/highlights/v030/>

⚠️ List of breaking changes can be found
[here](https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md).

### Features

-
[90a77aa](90a77aaf8b)
*(direction)* Add `Direction::perpendicular(self)` by @b-guild in
[#2197](https://github.com/ratatui/ratatui/pull/2197)

-
[56d5e05](56d5e05762)
*(bar)* Update label and text_value to accept Into<> by @Emivvvvv in
[#1471](https://github.com/ratatui/ratatui/pull/1471) [**breaking**]
  >
> BREAKING CHANGE:label and text_value now accept `Into<>` types, which
  > breaks type inference.
  >
  > ```diff
  > - Bar::default().label("foo".into());
  > + Bar::default().label("foo");
  > ```
  >
  > ```diff
  > - Bar::default().text_value("bar".into());
  > + Bar::default().text_value("bar");
  > ```

-
[b76ad3b](b76ad3b02e)
*(bar)* Impl Styled for Bar by @Emivvvvv in
[#1476](https://github.com/ratatui/ratatui/pull/1476)
  >
  > Related:https://github.com/ratatui/ratatui/issues/683

-
[e15fefa](e15fefa922)
*(barchar)* Add BarChart::grouped constructor by @joshka in
[#1513](https://github.com/ratatui/ratatui/pull/1513)

> Add a new constructor to the `BarChart` widget that allows creating a
  > grouped barchart with multiple groups of bars.
  >
> Also add a new constructor to the `BarGroup` widget that allows
creating
  > a group of bars with a label.

-
[369b18e](369b18eef2)
*(barchart)* Reduce barchart creation verbosity by @Emivvvvv in
[#1453](https://github.com/ratatui/ratatui/pull/1453)

  > Adds constructor methods for BarChart, BarGroup, and Bar

-
[1dc18bf](1dc18bf3cf)
*(calendar)* Add width and height functions by @joshka in
[#2198](https://github.com/ratatui/ratatui/pull/2198)

  > Fixes https://github.com/ratatui/ratatui/issues/2016
  >
  > ---------

-
[f18bcbf](f18bcbf06b)
*(canvas)* Add quadrant, sextant and octant markers by @sbarral in
[#2235](https://github.com/ratatui/ratatui/pull/2235) [**breaking**]

> The octant marker is an alternative to the Braille marker with the
same
> resolution, but offering densely packed, regular pseudo-pixels,
without
  > visible bands between rows and columns.
  >
  > Quadrant and Sextants are also added to support 2x2 and 2x3.
  >
> Sextant and Octant unicode characters that are less widely supported
at
  > the moment, which is why `Braille` was left as the default.
  >
  > BREAKING CHANGE:addition of new variants to `Marker` and removal of
  > no longer used constants in `ratatui::symbols::braille`.

-
[26b05de](26b05dee59)
*(chart)* Render Braille over Blocks in Charts and Canvas by @j-g00da in
[#2165](https://github.com/ratatui/ratatui/pull/2165)

> This makes it possible to stack charts, and write text over block
symbols in
> Charts and Canvas while still showing the block symbols behind the
text.

-
[bf84c62](bf84c6229b)
*(core)* Add a `has_modifier()` method to `Style` by @sxyazi in
[#2267](https://github.com/ratatui/ratatui/pull/2267)

  > Resolves https://github.com/ratatui/ratatui/issues/2264

-
[2d713d7](2d713d723d)
*(crossterm)* Allow multiple crossterm versions by @joshka in
[#1841](https://github.com/ratatui/ratatui/pull/1841)

  > This commit introduces feature flags to make it possible for widget
  > library authors to depend on a specific version of crossterm without
> causing version conflicts. This should make it easier for libraries
and
  > apps to update crossterm versions more easily.
  >
> The available feature flags are `crossterm_0_28` and `crossterm_0_29`.
> By default, the latest version is enabled. If a multiple features are
  > enabled we choose the latest version. We will in general support at
  > least the last two major (0.x) versions of crossterm, and will only
  > remove versions in a major version bump.

-
[d99984f](d99984f1e9)
*(layout)* Add `Flex::SpaceEvenly` by @kdheepak in
[#1952](https://github.com/ratatui/ratatui/pull/1952) [**breaking**]

  > Resolves https://github.com/ratatui/ratatui/issues/1951
  >
> BREAKING CHANGE:Old `Flex::SpaceAround` behavior is available by using
  >
  > `Flex::SpaceEvenly` and new
  >
  > `Flex::SpaceAround` now distributes space evenly around each element
  > except the middle spacers
  >     are twice the size of first and last elements
  >
  > With this change, the following variants of `Flex` are supported:
  >
> - `Flex::Start`: Aligns items to the start; excess space appears at
the
  > end.
  > - `Flex::End`: Aligns items to the end; excess space appears at the
  > start.
  > - `Flex::Center`: Centers items with equal space on both sides.
> - `Flex::SpaceAround` (**new**): Distributes space _around_ items;
space
  > between items is _twice_ the edge spacing.
> - `Flex::SpaceBetween`: Distributes space _evenly between_ items
except
  > no space at the edges.
> - `Flex::SpaceEvenly` (**previously `Flex::SpaceAround`**):
Distributes
  > space _evenly between_ items and edges.
> - `Flex::Legacy`: Preserves legacy behavior, placing all excess space
at
  > the end.
  >
  > This aligns behavior of `Flex` with CSS flexbox more closely.
  >
  > The following is a screenshot in action:
  >
  > <img width="1090" alt="image"
  >
>
src="https://github.com/user-attachments/assets/2c7cd797-27bd-4242-a824-4565d369227b"
  > />
  >
  > ---------

-
[9275d34](9275d3421c)
*(layout)* Add Offset::new() constructor by @joshka in
[#1547](https://github.com/ratatui/ratatui/pull/1547)

-
[7ad9c29](7ad9c29eac)
*(linegauge)* Customized symbols by @sectore in
[#1601](https://github.com/ratatui/ratatui/pull/1601)

  > With this PR any symbol (`&str`) can be used to render `filled` and
  > `unfilled` parts of `LineGauge` now. Before that change, only
>
[`symbols::line::Set`](https://docs.rs/ratatui/latest/ratatui/symbols/line/struct.Set.html)
  > was accepted.
  >
  > Note:New methods are introduced to define those symbols:
  > `filled_symbol` and `unfilled_symbol`. The method
>
[`line_set`](https://docs.rs/ratatui/latest/ratatui/widgets/struct.LineGauge.html#method.line_set)
  > is still there, but marked as `deprecated`.
  >
>
![line_gauge](https://github.com/user-attachments/assets/cae308b8-151b-461d-8af6-9a20012adf2f)

-
[92a19cb](92a19cb604)
*(list)* Highlight symbol styling by @airblast-dev in
[#1595](https://github.com/ratatui/ratatui/pull/1595) [**breaking**]

  > Allow styling for `List`'s highlight symbol
  >
  > This change makes it so anything that implements `Into<Line>` can be
  > used as a highlight symbol.
  >
> BREAKING CHANGE:`List::highlight_symbol` can no longer be used in
const
  > context
  >
  > BREAKING CHANGE:`List::highlight_symbol` accepted `&str`. Conversion
  > methods that rely on type inference will need to be rewritten as the
  > compiler cannot infer the type.
  >
  > closes:https://github.com/ratatui/ratatui/issues/1443
  >
  > ---------

-
[e89a526](e89a526aab)
*(no_std)* Portable-atomic integration for targets with no atomic types
by @j-g00da in [#2076](https://github.com/ratatui/ratatui/pull/2076)

  > Improves compatibility with no-std targets that don't support atomic
  > types.
  >
  > We support three different scenarios depending on the target:
  > 1. Terminal applications and other std targets (e.g. espidf):
  > - `std` enabled, `portable-atomic` disabled
  > 2. Embedded targets with atomic types, bare metal x86, etc.:
  > - `std` disabled `portable-atomic` disabled
  > 3. Embedded targets without atomic types (e.g. single-core MCUs):
  > - `std` disabled, `portable-atomic` enabled
  >
> Turning on `portable-atomic` together with `std` will fall back to
`std`
  > atomic.

-
[1399d95](1399d95ae0)
*(no_std)* Make palette and serde features depends on std by @j-g00da in
[#1919](https://github.com/ratatui/ratatui/pull/1919)

-
[b32f781](b32f78195b)
*(no_std)* Make `ratatui-macros` no-std by @j-g00da in
[#1865](https://github.com/ratatui/ratatui/pull/1865)

-
[3e1c72f](3e1c72fb27)
*(no_std)* Make ratatui compatible with `#![no_std]` by @j-g00da in
[#1794](https://github.com/ratatui/ratatui/pull/1794) [**breaking**]
  >
  > Resolves #1781
  >
  > This PR makes it possible to compile ratatui with `#![no_std]`.
  > Also makes me answer "We Are So Embedded" to "Are We Embedded Yet?"

-
[ab48c06](ab48c06171)
*(no_std)* Option to disable layout cache for `no_std` compatibility by
@j-g00da in [#1795](https://github.com/ratatui/ratatui/pull/1795)
[**breaking**]
  >
  > Resolves #1780
  >
  > BREAKING CHANGE:Disabling `default-features` will now disable layout
  > cache, which can have a negative impact on performance.
  >
  > `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only
  > available if `layout-cache` feature is enabled.

-
[09173d1](09173d1829)
*(no_std)* Make `TestBackend::Error` `Infallible` by @j-g00da in
[#1823](https://github.com/ratatui/ratatui/pull/1823) [**breaking**]
  >
> BREAKING CHANGE:`TestBackend` now uses `core::convert::Infallible` for
  > error handling instead of `std::io::Error`

-
[007713e](007713e50a)
*(no_std)* Replace `Backend`'s `io::Error` usages with associated
`Error` type by @j-g00da in
[#1778](https://github.com/ratatui/ratatui/pull/1778) [**breaking**]
  >
  > Resolves #1775
  >
> BREAKING CHANGE:Custom backends now have to implement `Backend::Error`
> and `Backend::clear_region`. Additionally some generic `Backend` usage
  > will have to explicitly set trait bounds for `Backend::Error`.

-
[a42a17e](a42a17e184)
*(no_std)* Make `ratatui-widgets` `no_std` by @j-g00da in
[#1779](https://github.com/ratatui/ratatui/pull/1779)
  >
  > Resolves #1776

-
[5a232a3](5a232a3115)
*(no_std)* Remove redundant `std` usages in `ratatui-widgets` by
@j-g00da in [#1762](https://github.com/ratatui/ratatui/pull/1762)

-
[ebe10cd](ebe10cd81f)
*(no_std)* Remove redundant `std` usages in `ratatui-core` by @j-g00da
in [#1753](https://github.com/ratatui/ratatui/pull/1753)

  > Resolves https://github.com/ratatui/ratatui/issues/1751

-
[08b08cc](08b08cc45b)
*(rect)* Centering by @janTatesa in
[#1814](https://github.com/ratatui/ratatui/pull/1814)
  >
  > Resolves #617

-
[ff729b7](ff729b7607)
*(scrollbar)* Support retrieving the current position of state by @orhun
in [#1552](https://github.com/ratatui/ratatui/pull/1552)

> As of now it is possible to change the position of the Scrollbar but
not
  > possible to retrieve the position for further use. e.g.
  >
  > ```rust
  > let mut state = ScrollbarState::default();
  > state.next();
  > ```
  >
> This commit adds a new method "`current_position`" (since `position`
is
  > already taken by the fluent setter) for that purpose:
  >
  > ```rust
  > let index = state.get_position(); // yay
  > ```
  >
  > See #1545 for the concrete usage of this.

-
[4c3c054](4c3c0540cd)
*(serde)* Handle null modifiers in serde Style by @joshka in
[#2172](https://github.com/ratatui/ratatui/pull/2172)

  > Allow `Style`'s `add_modifier` and `sub_modifier` fields to
  > deserialize from `null`

-
[b9da192](b9da1926a0)
*(serde)* Derive Serialize/Deserialize for alignment enums by @j-g00da
in [#1957](https://github.com/ratatui/ratatui/pull/1957)
  >
  > Resolves #1954

-
[89b7421](89b74214d9)
*(serde)* Derive Serialize/Deserialize for additional structs/enums by
@aurreland in [#1883](https://github.com/ratatui/ratatui/pull/1883)

  > This PR adds `#[derive(Serialize, Deserialize)]` to the following
  > structs:
  > - `Constraint`
  > - `Direction`
  > - `Spacing`
  > - `Layout`
  > - `AccentedPalette`
  > - `NonAccentedPalette`
  > - `Palette`
  > - `Padding`
  > - `Borders`
  > - `BorderType`
  > - `ListDirection`
  > - `ScrollbarOrientation`
  > - `ScrollDirection`
  > - `RenderDirection`
  > - `HighlightSpacing`
  >
  > Fixes #1877

-
[03f3f6d](03f3f6df35)
*(style)* Allow add/sub modifiers to be omitted in Style serialization.
by @rcorre in [#2057](https://github.com/ratatui/ratatui/pull/2057)

  > It's really useful that Style supports Deserialize, this allows TUI
  > apps to have configurable theming without much extra code.
  >
  > However, deserializing a style currently fails if `add_modifier` and
  > `sub_modifier` are
  > not specified. That means the following TOML config:
  >
  > ```toml
  > [theme.highlight]
  > fg = "white"
  > bg = "black"
  > ```
  >
> Will fail to deserialize with "missing field `add_modifier`". It
should
  > be possible
  > to omit modifiers and have them default to "none".

-
[ee67347](ee673476d3)
*(symbols)* Make `Marker` non-exhaustive by @j-g00da in
[#2236](https://github.com/ratatui/ratatui/pull/2236) [**breaking**]

> This will allow us to add new markers without causing further breaking
  > changes.
  >
  > BREAKING CHANGE:`Marker` is now non-exhaustive

-
[985cd05](985cd05573)
*(symbols)* Add dashed borders by @theotchlx in
[#1573](https://github.com/ratatui/ratatui/pull/1573)

  > Adds several new border sets:
  > - ratatui::symbols::border::LIGHT_DOUBLE_DASHED
  > - ratatui::symbols::border::HEAVY_DOUBLE_DASHED
  > - ratatui::symbols::border::LIGHT_TRIPLE_DASHED
  > - ratatui::symbols::border::HEAVY_TRIPLE_DASHED
  > - ratatui::symbols::border::LIGHT_QUADRUPLE_DASHED
  > - ratatui::symbols::border::HEAVY_QUADRUPLE_DASHED
  >
  > And corresponding variants to the ratatui::widgets::BorderType enum
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1355

-
[4c301e8](4c301e891d)
*(text)* Implement `AddAssign` for `Text` by @acuteenvy in
[#1956](https://github.com/ratatui/ratatui/pull/1956)

> This makes it possible to add a second `Text` instance to a first one
using the += operator.
  >
  > ```rust
  > let mut text = Text::from("line 1");
  > text += Text::from("line 2");
  > ```
  >
> Style and alignment applied to the second text is ignored (though
styles and alignment of lines and spans are copied).

-
[ce4856a](ce4856a65f)
*(widgets)* Add the missing constructor to canvas types by @orhun in
[#1538](https://github.com/ratatui/ratatui/pull/1538)

> Allows constructing `Rectangle`, `Points` and `Circle` using the `new`
  > method instead of initializing with the public fields directly.

-
[22610b0](22610b019b)
*(uncategorized)* Support adding an Offset to Position by @joshka in
[#2239](https://github.com/ratatui/ratatui/pull/2239)

  > Adds Position::offset() and arithmentic ops (Position + Offset and
  > Position - Offset)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/2018

-
[24e3133](24e3133456)
*(uncategorized)* Add Rect::resize() method by @joshka in
[#2240](https://github.com/ratatui/ratatui/pull/2240)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1440

-
[96d097e](96d097ef76)
*(uncategorized)* Implement Rect ops for moving by @joshka in
[#1596](https://github.com/ratatui/ratatui/pull/1596)
  >
  > feat:implement Rect ops for moving
  >
  > Implemented `Add`, `AddAssign`, `Sub`, and `SubAssign` on `Rect` for
  > `Offset`. This makes it possible to move rects
  >
  > ```rust
  > let rect = Rect::new(1, 2, 3, 4);
  > let moved = rect + Offset(1, 2);
  > let moved = rect - Offset(1, 2);
  > let moved = rect + Offset(-1, -2);
  > ```
  >
> Additionally Rect, Size, Offset, and Position now all have MIN and MAX
  > consts.

-
[e869cb9](e869cb9750)
*(uncategorized)* Add Size::area() by @joshka in
[#2226](https://github.com/ratatui/ratatui/pull/2226)

  > Add Size::area() returning u32 to avoid u16 overflow
  > Fixes https://github.com/ratatui/ratatui/issues/2204

-
[b6588fd](b6588fd1fa)
*(uncategorized)* Implement `From<Size>` for `(u16, u16)` by @0xb002f0
in [#2223](https://github.com/ratatui/ratatui/pull/2223)

-
[75b78be](75b78be09f)
*(uncategorized)* Add width() impl for tabs by @joshka in
[#2049](https://github.com/ratatui/ratatui/pull/2049)

> The purpose of this is to make it easy for apps to easily calculate
the
  > total tab width including all dividers and padding.

-
[8188ed3](8188ed3950)
*(uncategorized)* Implement UnicodeWidthStr for Text/Line/Span by
@joshka in [#2030](https://github.com/ratatui/ratatui/pull/2030)

  > You can now calculate the width of any Text/Line/Span using the
> UnicodeWidthStr trait instead of the width method on the type. This
also
  > makes it possible to use the width_cjk() method if needed.

-
[c845fec](c845fec765)
*(uncategorized)* Add conversion from Size to Rect by @joshka in
[#2028](https://github.com/ratatui/ratatui/pull/2028)
  >
  > `Rect::from(size)` returns a new Rect at the origin (0, 0) with the
  > specified `Size`

-
[017af11](017af11b2b)
*(uncategorized)* Preserve block titles when merging borders by @j-g00da
in [#1977](https://github.com/ratatui/ratatui/pull/1977)
  >
  > Resolves #1939

-
[6dcd53b](6dcd53bc6b)
*(uncategorized)* Add ergonomic methods for layouting Rects by @joshka
in [#1909](https://github.com/ratatui/ratatui/pull/1909)

> This commit introduces new methods for the `Rect` struct that simplify
> the process of splitting a `Rect` into sub-rects according to a given
> `Layout`. By putting these methods on the `Rect` struct, we make it a
> bit more natural that a layout is applied to the `Rect` itself, rather
  > than passing a `Rect` to the `Layout` struct to be split.
  >
> Adds:- `Rect::layout` and `Rect::try_layout` methods that allow
splitting a
  >   `Rect` into an array of sub-rects according to a given `Layout`.
  > - `Rect::layout_vec` method that returns a `Vec` of sub-rects.
> - `Layout::try_areas` method that returns an array of sub-rects, with
  >   compile-time checks for the number of constraints. This is added
  >   mainly for consistency with the new `Rect` methods.
  >
  > ```rust
  > use ratatui_core::layout::{Layout, Constraint, Rect};
  > let area = Rect::new(0, 0, 10, 10);
  > let layout = Layout::vertical([Constraint::Fill(1); 2]);
  >
  > // Rect::layout() infers the number of constraints at compile time:
  > let [top, main] = area.layout(&layout);
  >
> // Rect::try_layout() and Layout::try_areas() do the same, but return
a
  > // Result:
  > let [top, main] = area.try_layout(&layout)?;
  > let [top, main] = layout.try_areas(area)?;
  >
  > // Rect::layout_vec() returns a Vec of sub-rects:
  > let areas_vec = area.layout_vec(&layout);
  >
  > // you can also explicitly specify the number of constraints:
  > let areas = area.layout::<2>(&layout);
  > let areas = area.try_layout::<2>(&layout)?;
  > let areas = layout.try_areas::<2>(area)?;
  > ```

-
[0c3872f](0c3872f1c5)
*(uncategorized)* Add Rect::outer() by @joshka in
[#1929](https://github.com/ratatui/ratatui/pull/1929)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/211

-
[7bc78bc](7bc78bca1b)
*(uncategorized)* Add ratatui::run() method by @joshka in
[#1707](https://github.com/ratatui/ratatui/pull/1707)

> This introduces a new `ratatui::run()` method which runs a closure
with
> a terminal initialized with reasonable defaults for most applications.
  > This calls `ratatui::init()` before running the closure and
> `ratatui::restore()` after the closure completes, and returns the
result
  > of the closure.
  >
  > A minimal hello world example using the new `ratatui::run()` method:
  >
  > ```rust
  > fn main() -> Result<(), Box<dyn std::error::Error>> {
  >     ratatui::run(|terminal| {
  >         loop {
> terminal.draw(|frame| frame.render_widget("Hello World!",
frame.area()))?;
  >             if crossterm::event::read()?.is_key_press() {
  >                 break Ok(());
  >             }
  >         }
  >     })
  > }
  > ```
  >
  > Of course, this also works both with apps that use free methods and
  > structs:
  >
  > ```rust
> fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
  >
  > ratatui::run(run)?;
  > ```
  >
  > ```rust
  > struct App { ... }
  >
  > impl App {
  >     fn new() -> Self { ... }
> fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(),
AppError> { ... }
  > }
  >
  > ratatui::run(|terminal| App::new().run(terminal))?;
  > ```

-
[b6fbfcd](b6fbfcdd1c)
*(uncategorized)* Add lifetime to symbol sets by @joshka in
[#1935](https://github.com/ratatui/ratatui/pull/1935)

> This makes it possible to create symbol sets at runtime with
non-static
  > lifetimes.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1722

-
[488e5f0](488e5f020f)
*(uncategorized)* Make `border!` work without importing `Borders` by
@j-g00da in [#1918](https://github.com/ratatui/ratatui/pull/1918)

> Currently using `border!` macro requires explicit import of `Borders`
  > which is unnecessary.

-
[671c2b4](671c2b4fd4)
*(uncategorized)* Support merging the borders of blocks by @j-g00da

> When two borders overlap, they will automatically merge into a single,
  > clean border instead of overlapping.
  >
> This improves visual clarity and reduces rendering glitches around
corners.
  >
  > For example:
  >
  > ```
> assert_eq!(Cell::new("┘").merge_symbol("┏",
MergeStrategy::Exact).symbol(), "╆");
  > ```

-
[702fff5](702fff501c)
*(uncategorized)* Implement stylize methods directly on Style by @joshka
in [#1572](https://github.com/ratatui/ratatui/pull/1572) [**breaking**]

> This makes it possible to create constants using the shorthand
methods.
  >
  > ```rust
  > const MY_STYLE: Style = Style::new().blue().on_black();
  > ```
  >
  > Rather than implementing Styled for Style and then adding extension
  > methods that implement the Stylize shorthands, this implements the
  > methods as const functions directly on Style.
  >
  > BREAKING CHANGE:`Style` no longer implements `Styled`. Any calls to
  > methods implemented by the blanket implementation of Stylize are now
> defined directly on Style. Remove the Stylize import if it is no
longer
  > used by your code.
  >
> The `reset()` method does not have a direct replacement, as it clashes
  > with the existing `reset()` method. Use `Style::reset()` rather than
  > `some_style.reset()`
  >
  > Fixes:#1158

-
[4fcd238](4fcd238e1e)
*(uncategorized)* Support no-std for calendar widget by @joshka in
[#1852](https://github.com/ratatui/ratatui/pull/1852)

> Removes the CalendarEventStore::today() function in no-std
environments

-
[53cdbbc](53cdbbccd5)
*(uncategorized)* Enable serde propagation to backend crates (crossterm,
termion) by @ArjunKrish7356 in
[#1812](https://github.com/ratatui/ratatui/pull/1812)

> This PR propagates the serde feature from the main ratatui crate to
the
  > ratatui-crossterm and ratatui-termion backend crates. Solves #1805

-
[6836a69](6836a6903e)
*(uncategorized)* Implement styled for other primitives by @aschey in
[#1684](https://github.com/ratatui/ratatui/pull/1684)

-
[fcb47d6](fcb47d60f3)
*(uncategorized)* Rename Alignment to HorizontalAlignment and add
VerticalAlignment by @joshka in
[#1735](https://github.com/ratatui/ratatui/pull/1735) [**breaking**]

> We don't anticipate removing or deprecating the type alias in the near
  > future, but it is recommended to update your imports to use the new
  > name.
  >
> Added a VerticalAlignment enum to make the API more consistent. We
don't
> have a specific use case for it yet, but it's better to add it now and
  > be able to use it in the future.
  >
  > BREAKING-CHANGE:The `Alignment` enum has been renamed to
> `HorizontalAlignment` to better reflect its purpose. A type alias has
> been added to maintain backwards compatibility, however there are some
  > cases where type aliases are not enough to maintain backwards
  > compatibility. E.g. when using glob imports to import all the enum
> variants. This should not affect most users, but it is recommended to
  > update your imports to use the new name.
  >
  > ```diff
  > - use ratatui::layout::Alignment;
  > + use ratatui::layout::HorizontalAlignment;
  >
  > - use Alignment::*;
  > + use HorizontalAlignment::*;
  > ```

-
[2714d6b](2714d6b9c3)
*(uncategorized)* Add array and tuple RGB color conversion methods by
@joshka in [#1703](https://github.com/ratatui/ratatui/pull/1703)

> Other crates (e.g. colorgrad) that deal with colors can convert colors
> to a tuple of 3 or 4 u8 values. This commit adds conversion methods
from
  > these types to a `Color::Rgb` instance. Any alpha value is ignored.
  >
  > ```rust
  > Color::from([255, 0, 0]);
  > Color::from((255, 0, 0));
  > Color::from([255, 0, 0, 255]);
  > Color::from((255, 0, 0, 255));
  > ```

-
[50ba965](50ba96518f)
*(uncategorized)* Add a new RatatuiMascot widget by @Its-Just-Nans in
[#1584](https://github.com/ratatui/ratatui/pull/1584)

  > Move the Mascot from Demo2 into a new widget.
  > Make the Rat grey and adjust the other colors.
  >
  > ```rust
  > frame.render_widget(RatatuiMascot::default(), frame.area());
  > ```

-
[1d28c89](1d28c89fe5)
*(uncategorized)* Add conversions for anstyle by @joshka in
[#1581](https://github.com/ratatui/ratatui/pull/1581)
  >
> https://crates.io/crates/anstyle makes it possible to define colors in
> an interoperable way. This makes it possible for applications to
easily
  > load colors from a variety of formats.
  >
> This is gated by the anstyle feature flag which is disabled by
default.
  >
  > ---------

### Bug Fixes

-
[a89d3d6](a89d3d62ff)
*(buffer)* Clear behavior with VS16 wide emojis by @nornagon in
[#2063](https://github.com/ratatui/ratatui/pull/2063)

  > This fixes a bug where certain emojis like ⌨️ would sometimes be
> "overlaid" onto existing content from the buffer, instead of properly
  > clearing.
  >
  > [example demonstrating
>
bug](https://gist.github.com/nornagon/11a79d7a1f2e98aa129fedb4abccc530)
  >
  > This PR was generated by Codex, and validated by me:
> 1. Behavior of the above example code was buggy before this fix
(showed
  > overlaying "b" on top of the keyboard emoji), and fixed after.
> 2. The U+FE0F check is not strictly required, but I did note that
emoji
  > without this char don't exhibit the buggy behavior, even without the
  > fix.
  >
  > ---------

-
[ec30390](ec30390446)
*(canvas)* Round coordinates to nearest grid cell by @joshka in
[#1507](https://github.com/ratatui/ratatui/pull/1507)

  > Previously the canvas coordinates were rounded towards zero, which
> causes the rendering to be off by one pixel in some cases. It also
meant
> that pixels at the extreme edges of the canvas can only be drawn if
the
  > point was exactly on the edge of the canvas. This commit rounds the
> coordinates to the nearest integer instead. This may change the output
  > for some apps using Canvas / Charts.

-
[afd1ce1](afd1ce179b)
*(canvas)* Lines that start outside the visible grid are now drawn by
@renesat in [#1501](https://github.com/ratatui/ratatui/pull/1501)

> Previously lines with points that were outside the canvas bounds were
> not drawn at all. Now they are clipped to the bounds of the canvas so
  > that the portion of the line within the canvas is draw.
  >
> To facilitate this, a new `Painter::bounds()` method which returns the
  > bounds of the canvas is added.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1489

-
[2b0a044](2b0a044ced)
*(ci)* Add contents write permission to release-plz PR by @marcoieni in
[#2119](https://github.com/ratatui/ratatui/pull/2119)
  >
  > https://release-plz.dev/docs/github/quickstart#3-setup-the-workflow
  >
  > Fixes https://github.com/release-plz/release-plz/issues/2439

-
[18e70d3](18e70d3d51)
*(crossterm)* Terminal should keep Bold when removing Dim by @MarSik in
[#1541](https://github.com/ratatui/ratatui/pull/1541)

  > The Dim removal should behave the same as the logic for Bold removal
> that sends NormalIntensity sequence and then restores Dim when needed.

-
[16b76e3](16b76e36ee)
*(demo)* Update the width of demo2 tape by @orhun in
[#2164](https://github.com/ratatui/ratatui/pull/2164)

>
![](https://github.com/ratatui/ratatui/blob/images/examples/demo2.gif?raw=true)
  >
  > fixes #1721

-
[dca331c](dca331c748)
*(demo)* Support tab key in demo2 example by @orhun in
[#1726](https://github.com/ratatui/ratatui/pull/1726)
  >
  > see #1721
  >
> Not sure what caused this - it's been there for a while probably and
we
  > didn't realize it since we used `demo2-destroy` mostly.

-
[0fd4753](0fd4753e6b)
*(examples)* Run the correct example for chart by @orhun in
[#1679](https://github.com/ratatui/ratatui/pull/1679)
  >
  > fixes #1678

-
[39479e2](39479e298c)
*(examples)* Ensure that example projects are not published by @orhun in
[#1672](https://github.com/ratatui/ratatui/pull/1672)

-
[9314312](93143126b3)
*(layout)* Feature flag cache related types by @joshka in
[#1842](https://github.com/ratatui/ratatui/pull/1842)

-
[2dd1977](2dd1977c59)
*(layout-cache)* Import `NonZeroUsize` only when `layout-cache` is
enabled by @j-g00da in
[#1839](https://github.com/ratatui/ratatui/pull/1839)

> This silences unused import warning, when `layout-cache` is disabled.

-
[564a9d7](564a9d76fc)
*(line-gauge)* Pad default label to display 3 numbers by @martinetd in
[#2053](https://github.com/ratatui/ratatui/pull/2053)

> Display the default label of the LineGauge widget padded to fill 3
cells.
> This makes it so that the label doesn't shift around when going from a
  > single digit to double / triple digits.
  >
> To maintain the existing behavior, use a custom label by calling
`.label()`
  > on the LineGauge.

-
[a692a6e](a692a6e371)
*(lint)* Apply rust 1.84 clippy suggestions by @joshka in
[#1612](https://github.com/ratatui/ratatui/pull/1612)

  > The canvas map constants are now statics instead.
  > Fixes
>
https://rust-lang.github.io/rust-clippy/master/index.html\#large_const_arrays

-
[2e54d5e](2e54d5e22c)
*(macros)* Use $crate re-export in text macro by @airblast-dev in
[#1832](https://github.com/ratatui/ratatui/pull/1832)

-
[79d5165](79d5165cae)
*(no_std)* Propagate `std` feature flag to dependencies by @j-g00da in
[#1838](https://github.com/ratatui/ratatui/pull/1838)

> Disables `std` feature flags in dependencies and only enables them
with
> `ratatui` and `ratatui-core`'s `std` feature flag. This partially
fixes the
> issue of still depending on `std`, when `std` feature flag is
disabled.

-
[00da8c6](00da8c6203)
*(no_std)* Provide `f64` polyfills for `no_std` compatibility by
@j-g00da in [#1840](https://github.com/ratatui/ratatui/pull/1840)
  >
  > Related:https://github.com/rust-lang/rust/issues/137578

-
[3b13240](3b13240728)
*(scrollbar)* Check for area.is_empty() before rendering by @farmeroy in
[#1529](https://github.com/ratatui/ratatui/pull/1529)

> This adds the `area.is_empty()` back into the scrollbar render method.
  > Without it, the widget panics if the height is 0.

-
[f57b696](f57b696fdc)
*(span)* Dont render control characters by @EdJoPaTo in
[#1312](https://github.com/ratatui/ratatui/pull/1312)

-
[2ce958e](2ce958e38c)
*(table)* Allow display of additional table row, if row height > 1 by
@Lunderberg in [#1452](https://github.com/ratatui/ratatui/pull/1452)

-
[0a25bc1](0a25bc166d)
*(tests)* Update the stderr snapshot for ratatui-macros by @orhun in
[#2161](https://github.com/ratatui/ratatui/pull/2161)

  > New 🦀 broke the CI

-
[5fa342c](5fa342cc52)
*(widgets)* Fix centered block title truncation by @ognis1205 in
[#1973](https://github.com/ratatui/ratatui/pull/1973)

  > Previously block titles that were aligned center were
  > truncated poorly (aligned to the left, and the last
  > non-fitting title would be truncated on the left and right.
  > This now truncates the titles more obviously centered.

-
[f919b25](f919b25ea6)
*(uncategorized)* String_to_string lint is now part of implicit_clone by
@joshka in [#2173](https://github.com/ratatui/ratatui/pull/2173)

-
[1fe64de](1fe64de09a)
*(uncategorized)* Include underline color in anstyle conversion by
@aschey in [#2004](https://github.com/ratatui/ratatui/pull/2004)

  > Underline color wasn't included in the style conversion logic.

-
[c1b8528](c1b8528b69)
*(uncategorized)* Panic when rendering widgets on too small buffer by
@j-g00da in [#1996](https://github.com/ratatui/ratatui/pull/1996)

> Fixes panic on overflow on horizontal `Barchart` and `RatatuiMascot`
and adds proper tests to all widgets.
  >
  > ---------

-
[08b21fa](08b21fa55c)
*(uncategorized)* Fix panic when rendering a `Paragraph` out of bounds
by @jwodder in [#1670](https://github.com/ratatui/ratatui/pull/1670)
  >
  > Fixes #1667.

-
[80bc818](80bc818723)
*(uncategorized)* Fix truncation of left aligned block titles by @joshka
in [#1931](https://github.com/ratatui/ratatui/pull/1931)

> truncate the right side of left aligned titles rather than the left
side
> of right aligned titles. This is more obvious as the left side of text
  > often contains more important information. And we generally read
  > left to right.
  >
  > This change makes centered titles overwrite left aligned titles and
  > right aligned titles overwrite centered or left aligned titles.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/358

-
[21e3b59](21e3b598ce)
*(uncategorized)* Fix handling of multi-byte chars in bar chart by
@joshka in [#1934](https://github.com/ratatui/ratatui/pull/1934)

  > The split_at method requires that the split point is at a valid utf8
  > character boundary.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1928

-
[e1e4004](e1e400406c)
*(uncategorized)* Derive copy for list state by @janTatesa in
[#1921](https://github.com/ratatui/ratatui/pull/1921)

-
[12cb5a2](12cb5a28fe)
*(uncategorized)* Allow canvas area to exceed u16::MAX by @Daksh14 in
[#1891](https://github.com/ratatui/ratatui/pull/1891)

> This allows Canvas grids where the width * height exceeds u16::MAX by
  > converting values to usize earlier in several methods.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1449

-
[09cc9ef](09cc9ef57d)
*(uncategorized)* Typo in changelog by @joshka in
[#1857](https://github.com/ratatui/ratatui/pull/1857)

-
[c238aca](c238aca83a)
*(uncategorized)* `padding_right()` should set right padding instead of
left by @sxyazi in [#1837](https://github.com/ratatui/ratatui/pull/1837)

  > Fixes https://github.com/ratatui/ratatui/issues/1836

-
[c90ba97](c90ba9781e)
*(uncategorized)* Avoid unnecessary imports in minimal build by @cgzones
in [#1787](https://github.com/ratatui/ratatui/pull/1787)
  >
  > core::ops::Range is only used with the feature `scrolling-regions`.
  > Ensure a minimal `cargo check` reports no warnings.

-
[416ebdf](416ebdf8c8)
*(uncategorized)* Correct clippy errors introduced by rust 1.86.0 update
by @j-g00da in [#1755](https://github.com/ratatui/ratatui/pull/1755)

  > New version of rust (1.86.0) caused CI to fail.

-
[4eac5b2](4eac5b2849)
*(uncategorized)* Make deprecation notes more helpful by @joshka in
[#1702](https://github.com/ratatui/ratatui/pull/1702)

> AI coding assistants use the deprecation notes to automatically
suggest
> fixes. This commit updates the deprecation notes to push those tools
to
  > suggest the correct replacement methods and types.
  >
> Specifically, AI tools often suggest using `Buffer::get(x, y)`,
because
  > of their training data where this was prevalent. When fixing these
> deprecations, they often incorrectly suggest using `Buffer::get(x, y)`
  > instead of `Buffer[(x, y)]`.

-
[35a8642](35a86427ab)
*(uncategorized)* `Rect::positions()` should be empty when width is 0
and height is nonzero by @jwodder in
[#1669](https://github.com/ratatui/ratatui/pull/1669)
  >
  > Fixes #1666.

-
[f5fc819](f5fc8197ff)
*(uncategorized)* Avoid extra line break on whitespace only lines when
wrapping paragraphs by @dotdash in
[#1636](https://github.com/ratatui/ratatui/pull/1636)

  > Currently whitespace only lines produces an extra line break when
  > trimming is disabled, because both the trimmed as well as the
  > non-trimmed line get inserted. Fix this by only inserting the
  > non-trimmed one.

-
[2892bdd](2892bddce6)
*(uncategorized)* Rust 1.83 clippy lints by @joshka in
[#1527](https://github.com/ratatui/ratatui/pull/1527)
  >
>
https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes

-
[36e2d1b](36e2d1bda1)
*(uncategorized)* Add feature(doc_cfg) when generating docs by @joshka
in [#1506](https://github.com/ratatui/ratatui/pull/1506)

-
[4d7704f](4d7704fba5)
*(uncategorized)* Make StatefulWidget and Ref work with unsized State by
@thscharler in [#1505](https://github.com/ratatui/ratatui/pull/1505)
  >
  > StatefulWidget::State and StatefulWidgetRef::State are now ?Sized.
  >
> This allows implementations of the traits to use unsized types for the
  > State associated type. This is turn is useful when doing things like
  > boxing different stateful widget types with State which implements
  > `Any`, are slices or any other dynamically sized type.

-
[7b87509](7b875091e1)
*(uncategorized)* Typo by @marcoieni in
[#1480](https://github.com/ratatui/ratatui/pull/1480)

### Refactor

-
[8d60e96](8d60e96b2b)
*(examples)* Use crossterm event methods by @joshka in
[#1792](https://github.com/ratatui/ratatui/pull/1792)

> Crossterm 0.29 introduced methods to easily check / extract the event
  > type. E.g. as_key_press_event() and is_key_press(). This commit
  > updates the examples to use these methods instead of matching on
  > the event type. This makes the code cleaner and easier to read.
  >
> Also does a general cleanup of the event handling code in the
examples.

-
[07bec55](07bec55b7d)
*(no_std)* Make usages of std explicit in ratatui-core. by @ed-2100 in
[#1782](https://github.com/ratatui/ratatui/pull/1782)

  > ### This commit does the following:
  >
  > - Adds `#[no_std]` to `lib.rs`.
  > - Adds `extern crate std;` to `lib.rs`.
> - Updates `ratatui-core` to explicitly `use` items from std and alloc.
  > - Prefers `use`-ing alloc over std when possible.
  >
  > ### Explanation:
  >
> This allows usages of `std` in `ratatui-core` to be clearly pointed
out
  > and dealt with individually.
  >
  > Eventually, when `std` is to be feature gated, the associated commit
  > will be much cleaner.

-
[f132fa1](f132fa1715)
*(table)* Small readability improvements by @joshka in
[#1510](https://github.com/ratatui/ratatui/pull/1510)

-
[c7c3498](c7c3498025)
*(uncategorized)* Use saturating_add in Rect::new by @pharrison31415 in
[#2216](https://github.com/ratatui/ratatui/pull/2216)

-
[02e53de](02e53de0f8)
*(uncategorized)* Make use of iter::repeat_n() by @cgzones in
[#1788](https://github.com/ratatui/ratatui/pull/1788)

  > Applied via clippy --fix.
  > Available since 1.82.0.

-
[a195d59](a195d59a47)
*(uncategorized)* Move xtask commands to small modules by @joshka in
[#1620](https://github.com/ratatui/ratatui/pull/1620)

-
[904b0aa](904b0aa723)
*(uncategorized)* Move symbols to modules by @joshka in
[#1594](https://github.com/ratatui/ratatui/pull/1594)

-
[7c8573f](7c8573f575)
*(uncategorized)* Rearrange selection_spacing code by @raylu in
[#1540](https://github.com/ratatui/ratatui/pull/1540)

-
[217c57c](217c57cd60)
*(uncategorized)* Modularize backends by @orhun in
[#1508](https://github.com/ratatui/ratatui/pull/1508)

> Backend code is now moved to `ratatui-crossterm`, `ratatui-termion`
and
> `ratatui-termwiz`. This should be backwards compatible with existing
code.

-
[e461b72](e461b724a6)
*(uncategorized)* Move {Stateful,}Widget{,Ref} types into individual
files by @joshka in
[#1479](https://github.com/ratatui/ratatui/pull/1479)

> This is a preparatory refactoring for modularization. No user visible
  > changes.

### Documentation

-
[40e96a2](40e96a2a04)
*(block)* Add collapsed border example by @joshka in
[#1899](https://github.com/ratatui/ratatui/pull/1899)

-
[d291042](d291042e69)
*(block)* Revise the block example by @orhun in
[#1520](https://github.com/ratatui/ratatui/pull/1520)

  > - Moves the block example from `ratatui` to `ratatui-widgets`
  > - Simplifies the example (bordered, styled, custom borders)
  >
  > see #1512

-
[0951da5](0951da52f9)
*(breaking-changes)* Improve migration guide for `Backend::Error` by
@j-g00da in [#1908](https://github.com/ratatui/ratatui/pull/1908)
  >
  > Related:https://github.com/fujiapple852/trippy/pull/1588

-
[bbe1cf9](bbe1cf9497)
*(breaking-changes)* Change MSRV to 1.85 by @j-g00da in
[#1896](https://github.com/ratatui/ratatui/pull/1896)

> The minimum supported Rust version is now for `ratatui` v0.30 is 1.85

-
[c7912f3](c7912f3990)
*(breaking-changes)* Fix header level by @j-g00da in
[#1825](https://github.com/ratatui/ratatui/pull/1825)

-
[fcde9cb](fcde9cb9c3)
*(changelog)* Fix typo by @orhun in
[#1463](https://github.com/ratatui/ratatui/pull/1463)

-
[73488ab](73488abb45)
*(contributing)* Fix link to `widgets_block_renders` test by @ognis1205
in [#2101](https://github.com/ratatui/ratatui/pull/2101)

  > The `CONTRIBUTING.md` referenced `tests/widgets_block.rs`, but the
> correct path is `ratatui/tests/widgets_block.rs`. Updated the link so
  > that readers can navigate to the test example without 404 error.
  >
  > ---------

-
[0b025db](0b025db72b)
*(contributing)* Fix grammar by @j-g00da in
[#1958](https://github.com/ratatui/ratatui/pull/1958)

-
[1197b2a](1197b2a02c)
*(contributing)* Add note about using nightly for formatting by @joshka
in [#1816](https://github.com/ratatui/ratatui/pull/1816)

-
[3ae6bf1](3ae6bf1d6f)
*(contributing)* Use cargo-xtask for instructions by @orhun in
[#1509](https://github.com/ratatui/ratatui/pull/1509)

  > - Updates `CONTRIBUTING.md` about the usage of `xtask`
  > - Removes `Makefile.toml`

-
[22e3e84](22e3e84de8)
*(core)* Remove link to Paragraph widget by @orhun in
[#1683](https://github.com/ratatui/ratatui/pull/1683)

-
[b65788c](b65788ce14)
*(examples)* Remove duplicated link by @matthiasbeyer in
[#2212](https://github.com/ratatui/ratatui/pull/2212)

-
[200b217](200b217722)
*(examples)* Add VHS tapes and docs for widget examples by @orhun in
[#2114](https://github.com/ratatui/ratatui/pull/2114)
  >
  > fixes #1982
  >
> Later on I'll figure out an easy way to regenerate this in the CI and
  > possibly do the same for the app examples' VHS tapes. That's why I
  > haven't added a script or mentioned anything in the docs yet (hint:
  > #1721)
  >
  > ---------

-
[861fbdf](861fbdf5cf)
*(examples)* Fix a typo by @j-g00da in
[#1890](https://github.com/ratatui/ratatui/pull/1890)

  > Makes CI typos check pass again

-
[882cc3c](882cc3c6c6)
*(examples)* Update app examples with tapes by @orhun in
[#1673](https://github.com/ratatui/ratatui/pull/1673)

-
[4393fae](4393fae54c)
*(examples)* Move scrollbar example to examples folder by @orhun in
[#1665](https://github.com/ratatui/ratatui/pull/1665)

-
[9ea70e2](9ea70e28c6)
*(examples)* Move widget-impl example to examples folder by @orhun in
[#1663](https://github.com/ratatui/ratatui/pull/1663)

-
[774ab78](774ab788d4)
*(examples)* Move widget-ref-container example to examples folder by
@orhun in [#1664](https://github.com/ratatui/ratatui/pull/1664)
  >
  > see #1512

-
[910d16e](910d16e63a)
*(examples)* Move user-input example to examples folder by @orhun in
[#1659](https://github.com/ratatui/ratatui/pull/1659)

-
[dbfb7da](dbfb7da9e3)
*(examples)* Move table example to examples folder by @orhun in
[#1657](https://github.com/ratatui/ratatui/pull/1657)

-
[cb2a58a](cb2a58aaa0)
*(examples)* Move tracing example to examples folder by @orhun in
[#1658](https://github.com/ratatui/ratatui/pull/1658)

-
[7e00b64](7e00b646fc)
*(examples)* Move panic example to examples folder by @orhun in
[#1655](https://github.com/ratatui/ratatui/pull/1655)

-
[8127590](8127590812)
*(examples)* Move modifiers example to examples folder by @orhun in
[#1654](https://github.com/ratatui/ratatui/pull/1654)

-
[7c40c0b](7c40c0bbdd)
*(examples)* Move popup example to examples folder by @orhun in
[#1656](https://github.com/ratatui/ratatui/pull/1656)
  >
  > see #1512

-
[d87354f](d87354f400)
*(examples)* Move list example to examples folder by @orhun in
[#1653](https://github.com/ratatui/ratatui/pull/1653)
  >
  > see #1512
  >
  > also renames it to todo-list

-
[621226f](621226f2e2)
*(examples)* Move inline example to examples folder by @orhun in
[#1651](https://github.com/ratatui/ratatui/pull/1651)

-
[9ba7d25](9ba7d25b71)
*(examples)* Move hyperlink example to examples folder by @orhun in
[#1650](https://github.com/ratatui/ratatui/pull/1650)

-
[bb94d1c](bb94d1c0fa)
*(examples)* Move minimal example to examples folder by @orhun in
[#1649](https://github.com/ratatui/ratatui/pull/1649)

-
[9f399ac](9f399ac7a6)
*(examples)* Move gauge example to examples folder by @orhun in
[#1646](https://github.com/ratatui/ratatui/pull/1646)

-
[104d6a6](104d6a6c2b)
*(examples)* Move custom-widget example to examples folder by @orhun in
[#1644](https://github.com/ratatui/ratatui/pull/1644)

-
[fa8ca01](fa8ca0121a)
*(examples)* Move flex example to examples folder by @orhun in
[#1642](https://github.com/ratatui/ratatui/pull/1642)

-
[f5fde0e](f5fde0ef53)
*(examples)* Move constraints example to examples folder by @orhun in
[#1641](https://github.com/ratatui/ratatui/pull/1641)

-
[fc70288](fc70288954)
*(examples)* Move constraint-explorer example to examples folder by
@orhun in [#1640](https://github.com/ratatui/ratatui/pull/1640)

-
[325f961](325f96102a)
*(examples)* Move hello-world example to examples folder by @orhun in
[#1647](https://github.com/ratatui/ratatui/pull/1647)

-
[867c4bc](867c4bc4e9)
*(examples)* Move colors-rgb example to examples folder by @joshka in
[#1582](https://github.com/ratatui/ratatui/pull/1582)

  > - **docs: move colors-rgb example to examples folder**
  > - **docs: update main examples README**
  >
  > ---------

-
[72334ed](72334ed61c)
*(layout)* Update documentation to point to `kasuari` solver by @a-kenji
in [#2003](https://github.com/ratatui/ratatui/pull/2003)

-
[2be9ccb](2be9ccb120)
*(layout)* Remove unnecessary path prefix by @j-g00da in
[#1766](https://github.com/ratatui/ratatui/pull/1766)

-
[b669ceb](b669cebcaf)
*(layout)* Change `cassowary` to `kasuari` crate reference by @j-g00da
in [#1765](https://github.com/ratatui/ratatui/pull/1765)

-
[f907c74](f907c74bb3)
*(license)* Update copyright years by @LVivona in
[#1639](https://github.com/ratatui/ratatui/pull/1639)

  > Update MIT Licence to copyright year 2025

-
[68b9f67](68b9f67f59)
*(readme)* Add `Built with Ratatui` badge for downstream projects by
@harilvfs in [#1905](https://github.com/ratatui/ratatui/pull/1905)

-
[088aac1](088aac136d)
*(readme)* Tweak links and badges by @joshka in
[#1598](https://github.com/ratatui/ratatui/pull/1598)

-
[6e43672](6e436725e4)
*(readme)* Reimagine README.md by @orhun in
[#1569](https://github.com/ratatui/ratatui/pull/1569)

> This is the result of the re-imagination of a more suitable README.md.
It
  > is simpler and shorter: not giving more information to the user than
  > they actually need.
  >
> Also updates the quickstart code with the up-to-date version and adds
  > link to templates which was missing.
  >
  > ---------

-
[8f28247](8f282473b2)
*(readme)* Correct examples links by @HoKim98 in
[#1484](https://github.com/ratatui/ratatui/pull/1484)

-
[9f90f74](9f90f7495f)
*(readme)* Fix broken link by @nilsmartel in
[#1485](https://github.com/ratatui/ratatui/pull/1485)

-
[260af68](260af68a34)
*(readme)* Include iocraft as an alternative by @kdheepak in
[#1483](https://github.com/ratatui/ratatui/pull/1483)

-
[8e5151f](8e5151f83d)
*(rect)* Fix typo in the Rect::outer function comments by @orhun in
[#2123](https://github.com/ratatui/ratatui/pull/2123)

-
[40f13c6](40f13c6a6c)
*(rect)* Update the outdated comment for Rect::area() by @isgin01 in
[#2100](https://github.com/ratatui/ratatui/pull/2100)

> The return value of Rect.area() is no longer of u16 type, and the
value
  > is not being clumped anymore.

-
[ce16692](ce16692b9a)
*(release)* Fix typo by @j-g00da in
[#1754](https://github.com/ratatui/ratatui/pull/1754)

-
[9a930a6](9a930a6e99)
*(terminal)* Made usage of Terminal::get_frame() clearer by @Blaeriz in
[#2071](https://github.com/ratatui/ratatui/pull/2071)

  > Closes : https://github.com/ratatui/ratatui/issues/1200
  >
  > ---------

-
[b08b4cb](b08b4cbd5e)
*(terminal)* Add disclaimer about panics to Terminal::new by
@lolbinarycat in [#2088](https://github.com/ratatui/ratatui/pull/2088)

  >
  > part of #2087
  >
  > cc @orhun
  >
  > ---------

-
[dafb716](dafb716f9d)
*(widgets)* Add example for grouped barchart by @orhun in
[#1566](https://github.com/ratatui/ratatui/pull/1566)
  >
  > related #1512
  >
  > ---------

-
[ed5dd73](ed5dd73084)
*(widgets)* Add example for tabs by @orhun in
[#1559](https://github.com/ratatui/ratatui/pull/1559)
  >
  > related #1512
  >
> Also removes the tabs example from ratatui crate since it overlaps
with
> this new example in terms of functionality and it was not following
the
  > general theme of other examples.

-
[fab5321](fab532171d)
*(widgets)* Add example for scrollbar by @orhun in
[#1545](https://github.com/ratatui/ratatui/pull/1545)

  > Related to: #1512

-
[898aef6](898aef6e2f)
*(widgets)* Add example for list by @orhun in
[#1542](https://github.com/ratatui/ratatui/pull/1542)

  > Related to: #1512

-
[452366a](452366aa9e)
*(widgets)* Add example for sparkline by @orhun in
[#1556](https://github.com/ratatui/ratatui/pull/1556)
  >
  > related #1512
  >
> Also removes the sparkline example from ratatui crate since this
example
  > is a simplified and easier to understand version of that

-
[6ddde0e](6ddde0e8a8)
*(widgets)* Add example for table by @orhun in
[#1557](https://github.com/ratatui/ratatui/pull/1557)
  >
  > related #1512

-
[93ad6b8](93ad6b828c)
*(widgets)* Update values in chart example by @orhun in
[#1558](https://github.com/ratatui/ratatui/pull/1558)

  > better stonks

-
[15f442a](15f442a71e)
*(widgets)* Add example for paragraph by @orhun in
[#1544](https://github.com/ratatui/ratatui/pull/1544)
  >
  > related #1512
  >
> Also removes the paragraph example from `ratatui` since these examples
  > are more or less the same.

-
[17bba14](17bba14540)
*(widgets)* Move the logo example to widgets by @orhun in
[#1543](https://github.com/ratatui/ratatui/pull/1543)
  >
  > related #1512
  >
  > Also updates the code to make it consistent with the other examples

-
[f2451e7](f2451e7f1e)
*(widgets)* Add example for gauge by @orhun in
[#1539](https://github.com/ratatui/ratatui/pull/1539)
  >
  > related #1512

-
[4f0a8b2](4f0a8b21af)
*(widgets)* Add example for canvas by @orhun in
[#1533](https://github.com/ratatui/ratatui/pull/1533)
  >
  > related #1512

-
[91147c4](91147c4d75)
*(widgets)* Add example for chart by @orhun in
[#1536](https://github.com/ratatui/ratatui/pull/1536)

  > stonks

-
[6dd25a3](6dd25a3111)
*(widgets)* Add example for calendar by @orhun in
[#1532](https://github.com/ratatui/ratatui/pull/1532)
  >
  > related #1512

-
[99ac005](99ac005b06)
*(widgets)* Add simple barchart example by @joshka in
[#1511](https://github.com/ratatui/ratatui/pull/1511)

-
[b1d47e7](b1d47e7718)
*(uncategorized)* Discourage use of `Buffer`'s `pos_of`, `index_of` by
@pharrison31415 in [#2225](https://github.com/ratatui/ratatui/pull/2225)

> These methods assume that the backing store of any buffer / area is
linearly indexable. There are other ways that we might want to
experiment in the future with how to store the values (trees, 2D
allocated areas that are non-contiguous etc.). The index <-> pos
conversion there isn't particularly useful. This should be an internal
implementation detail of the buffer, rather than something that we
expose, but we're not deprecating this for now at least.

-
[f8b0594](f8b0594363)
*(uncategorized)* Fix: fix typos by @j-g00da in
[#2129](https://github.com/ratatui/ratatui/pull/2129)

  > This fixes the pipeline after bumping typos.

-
[9998000](9998000e36)
*(uncategorized)* Use shields.io badge by @LitoMore in
[#2040](https://github.com/ratatui/ratatui/pull/2040)

  > Related to:
  > - https://github.com/simple-icons/simple-icons/pull/13593
  > - https://github.com/ratatui/ratatui/pull/1967
  >
  > The Ratatui icon is available on shields.io now ✌️
  >
  > And it's customizable. There are more configurations at
  > https://shields.io/badges.
  >
  > Here are some examples:
  >
  > ```markdown
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  > ```
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
  >
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  >
> I also created a PR to the ratatui-website project to update the
badge.
  > Here is the PR:
  >
  > - https://github.com/ratatui/ratatui-website/pull/924

-
[71ef65b](71ef65b624)
*(uncategorized)* Add section on collaborative development to
contributing doc by @joshka in
[#2029](https://github.com/ratatui/ratatui/pull/2029)

-
[cba5cca](cba5cca2bd)
*(uncategorized)* Update heading image for Ratatui 0.30.0 release 🎉 by
@j-g00da in [#2000](https://github.com/ratatui/ratatui/pull/2000)

-
[9836f07](9836f0760d)
*(uncategorized)* Add AI contribution guidelines by @joshka in
[#2013](https://github.com/ratatui/ratatui/pull/2013)

-
[98f85b8](98f85b8650)
*(uncategorized)* Update link to scrollable widgets RFC by @MatrixFrog
in [#1994](https://github.com/ratatui/ratatui/pull/1994)

-
[055522e](055522ef7b)
*(uncategorized)* Add docs for authoring widget crates by @j-g00da in
[#1955](https://github.com/ratatui/ratatui/pull/1955)

  > - added Authoring Widget Libraries sub-section
  > - moved built-in and third-party widgets sections higher

-
[617d318](617d31851a)
*(uncategorized)* Improve Block docs by @joshka in
[#1953](https://github.com/ratatui/ratatui/pull/1953)

-
[8e2d568](8e2d568428)
*(uncategorized)* Improve layout related docs by @joshka in
[#1948](https://github.com/ratatui/ratatui/pull/1948)

> Adds module level docs and more comprehensive docs on all the types in
  > the layout module
  >
  > Fixes #1937

-
[4c708dd](4c708ddf8a)
*(uncategorized)* Improve docs for run/init/restore etc. by @joshka in
[#1947](https://github.com/ratatui/ratatui/pull/1947)

  > - **docs: document the init module**
  > - **docs: use the ratatui::run() methods in the main doc**
> - **docs: add more intradoc / website links and historical perspective
  > on Terminal / backend**
  > - **docs: add notes about new run/init/restore methods and the
  > defaultterminal type to terminal docs**

-
[5620e06](5620e06b1a)
*(uncategorized)* Add crate organization sections to workspace by
@joshka in [#1946](https://github.com/ratatui/ratatui/pull/1946)

  > Adds summary-level crate organization documentation to all crates
> explaining the modular workspace structure and when to use each crate.
  > Links to ARCHITECTURE.md for detailed information.

-
[cfb65e6](cfb65e64ba)
*(uncategorized)* Add examples for handling state by @joshka in
[#1849](https://github.com/ratatui/ratatui/pull/1849)

> Added comprehensive state management examples covering both immutable
  > and mutable patterns and documentation to help developers choose the
  > right approach for their applications.

-
[3de41a8](3de41a8249)
*(uncategorized)* Document widgets module by @joshka in
[#1932](https://github.com/ratatui/ratatui/pull/1932)

  > Adds a good overview of the use and implementation of widget traits.
  >
  > Goals with the doc rewrite:
> - document the rationale for the ratatui-widgets crate with info for
app
  > builders and widget makers.
  > - Show how to use the widgets for rendering as well as implement the
  > traits- document the differences and reasons for each trait
  > - document the historical perspective (to make it easy to understand
  > older Ratatui apps as well as migrate to newer approaches
  > - give recommended approaches to implementing traits
  > - explain the differences between Consuming and Shared / Mutable
  > Reference implementations of Widget
  > - explain the differences between using StatefulWidget and Mutable
  > References
  > - Explain the use case for WidgetRef and StatefulWidgetRef
  > - Link out to third part widget lists
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/366
  >
  > ---------

-
[ca2ad4a](ca2ad4a1f9)
*(uncategorized)* Simplify ratatui-macro docs by @joshka in
[#1923](https://github.com/ratatui/ratatui/pull/1923)

-
[92b6a16](92b6a16bde)
*(uncategorized)* Fix grammar in ratatui-widgets README by @sevki in
[#1885](https://github.com/ratatui/ratatui/pull/1885)

-
[da05957](da05957fa0)
*(uncategorized)* Add widget-ref-container example by @joshka in
[#1603](https://github.com/ratatui/ratatui/pull/1603)

  > Implements ideas alluded to by
>
<https://discord.com/channels/1070692720437383208/1072907135664529508/1323061053990637640>
  > and followup conversations.

-
[1798512](1798512e94)
*(uncategorized)* Fix wording in user_input example by @dawedawe in
[#1611](https://github.com/ratatui/ratatui/pull/1611)

  > Fix wording in `user_input.rs` example.

-
[03066d8](03066d81bf)
*(uncategorized)* Fix punctuation in canvas.rs documentation by
@dawedawe in [#1583](https://github.com/ratatui/ratatui/pull/1583)

  > Fix end of sentence punctuation in canvas.rs docs.

-
[e411d9e](e411d9ec3e)
*(uncategorized)* Add input form example by @joshka in
[#1551](https://github.com/ratatui/ratatui/pull/1551)

  > Demonstrates how to manage the cursor and input focus with a simple
  > form. Uses an enum to track the current input field and passes the
  > input events to the active field.
  >
> This is similar to the json tutorial on the website, but a bit simpler

-
[ed071f3](ed071f3723)
*(uncategorized)* Add mouse-drawing example by @joshka in
[#1546](https://github.com/ratatui/ratatui/pull/1546)

  > Demonstrates how to handle mouse events

-
[46902f5](46902f5587)
*(uncategorized)* Improve docs for workspace crates by @orhun in
[#1490](https://github.com/ratatui/ratatui/pull/1490)

> Overall makes improvements in the documentation of the workspace
crates and checking them.

-
[a6b5792](a6b579223f)
*(uncategorized)* Fix example link in readme by @thomas-tacquet in
[#1462](https://github.com/ratatui/ratatui/pull/1462)

### Performance

-
[1f41a61](1f41a61008)
*(paragraph)* Avoid unnecessary work when rendering by @alexpasmantier
in [#1622](https://github.com/ratatui/ratatui/pull/1622)

  > Improve render times for paragraphs that are scrolled.
  >
> Currently all `LineComposer`s are considered to be state machines
which
> means rendering a paragraph with a given Y offset requires computing
the
  > entire state up to Y before being able to render from Y onwards.
  >
> While this makes sense for Composers such as the `WordWrapper` (where
> one needs to consider all previous lines to determine where a given
line
> will end up), it means it also penalizes Composers which can render a
> given line "statelessely" (such as the `LineTruncator`) which actually
> end up doing a lot of unnecessary work (and on the critical rendering
  > path) when the offset gets high.

-
[ba9eed7](ba9eed7742)
*(table)* Replace while loop with simple min operation by @EdJoPaTo in
[#1747](https://github.com/ratatui/ratatui/pull/1747)

### Styling

-
[345f47e](345f47e044)
*(rect)* Use plus operator for offset by @pharrison31415 in
[#2251](https://github.com/ratatui/ratatui/pull/2251)

  > ## Summary
  > Use `+` operator to move `Rect` by an `Offset` as added
  > [here](https://github.com/ratatui/ratatui/pull/1596).
  >
  > Includes change to use `Offset::new()` in place of `Offset { ... }`

-
[ac60de3](ac60de3960)
*(uncategorized)* Fix wrapping in doc comment by @joshka in
[#2104](https://github.com/ratatui/ratatui/pull/2104)

-
[2739391](2739391950)
*(uncategorized)* Use Module imports_granularity by @joshka in
[#1728](https://github.com/ratatui/ratatui/pull/1728)

> I was swayed by the arguments about this made by the compiler team In
> <https://github.com/rust-lang/compiler-team/issues/750> and decided to
> look at how this organization affects ratatui. I found this reduces
the
> number of lines across the codebase by about 350 and makes the imports
  > more readable and definitely more greppable as you usually only have
> to read a single line. I've found in the past that maintaining imports
  > regularly leads to merge conflicts which have to be resolved by hand
  > and this change should reduce the likelihood of that happening.
  >
  > Main change is in rustfmt.toml, and the rest is just the result of
  > running `cargo xtask format`.
  >
  > While implementing this, cargo machete brings up that the various
  > backend crates are unused by the example crates.
  >
> The re-export of each backend crate under ratatui is to make it
possible
  > for libs that rely on a specific version of ratatui to use the same
  > version of the backend crate. Apps in general should use the backend
> crate directly rather than through ratatui as this is less confusing.
  >
> - Removes all usages of `ratatui::{crossterm, termion, termwiz}`` in
the
  >   examples.
> - Adds the backend crate to the dependencies of the examples that use
  >   the backend crate directly.

### Testing

-
[db65aa0](db65aa0ef7)
*(bench)* Add benchmark for text by @orhun in
[#2160](https://github.com/ratatui/ratatui/pull/2160)

  > #2138
  >
  > ---------

-
[a21501f](a21501f7f4)
*(bench)* Added a benchmark for constraints by @kashregister in
[#2043](https://github.com/ratatui/ratatui/pull/2043)

  > I've added a new benchmark for constraints, which only takes into
> account the time it takes to generate a full layout using a single
type
  > of constraints only. Avoided rendering here as it resulted in more
> inaccurate benchmarks, and i believe it should be separated
nonetheless.

-
[94ba82e](94ba82e9ca)
*(gauge)* Add benchmarks for gauge by @WaterWhisperer in
[#2221](https://github.com/ratatui/ratatui/pull/2221)

-
[39cd313](39cd313b3b)
*(layout)* Add visual buffer tests for Rect methods by @orhun in
[#2124](https://github.com/ratatui/ratatui/pull/2124)

-
[8aefc06](8aefc06a90)
*(macros)* Regenerate trybuild stderr by @ognis1205 in
[#2093](https://github.com/ratatui/ratatui/pull/2093)

  > ### Overview
  >
  > Updated the `.stderr` file corresponding to the
  > `ratatui-macros/tests/ui/fails.rs` compile-fail test.
  >
  > ### Changes
  >
  > - Updated `tests/ui/fails.stderr` to match the new compiler output.
  >
  > ### Impact
  >
  > - Affects only the trybuild UI tests
  > - No impact on production code
  >
  > ### Notes
  >
  > - The `.stderr` was generated using `TRYBUILD=overwrite cargo test`.
  >
  > Closes https://github.com/ratatui/ratatui/issues/2094

-
[55a95e6](55a95e67bc)
*(rect)* Mutual intersection agreement by @pharrison31415 in
[#2252](https://github.com/ratatui/ratatui/pull/2252)

-
[deb1b8e](deb1b8ec43)
*(uncategorized)* Ensure Style::new() and Style::default() are
equivalent by @cgzones in
[#1789](https://github.com/ratatui/ratatui/pull/1789)

### Miscellaneous Tasks

-
[abe2f27](abe2f27328)
*(backend)* Change From<T> impls to new backend specific IntoBackend and
FromBackend traits by @joshka in
[#1464](https://github.com/ratatui/ratatui/pull/1464) [**breaking**]

  > Adds two traits `IntoCrossterm` and `FromCrossterm` for converting
> between ratatui and crossterm types. This is necessary in order to
avoid
> the orphan rule when implementing `From` for crossterm types once the
  > crossterm types are moved to a separate crate.
  >
> Similarly Termwiz and Termwiz gain FromTermion, IntoTermion,
FromTermwiz
  > and IntoTermwiz traits.
  >
> BREAKING CHANGE:The `From` and `Into` impls for backend types are now
  > replaced
  > with specific backend traits.
  >
  > ```diff
  > + use ratatui::backend::{FromCrossterm, IntoCrossterm};
  >
  > let crossterm_color = crossterm::style::Color::Black;
  > - let ratatui_color = crossterm_color.into();
  > - let ratatui_color = ratatui::style::Color::from(crossterm_color);
> + let ratatui_color =
ratatui::style::Color::from_crossterm(crossterm_color);
  > - let crossterm_color = ratatui_color.into();
> - let crossterm_color = crossterm::style::Color::from(ratatui_color);
  > + let crossterm_color = ratatui_color.into_crossterm();
  >
  > let crossterm_attribute = crossterm::style::types::Attribute::Bold;
  > - let ratatui_modifier = crossterm_attribute.into();
> - let ratatui_modifier =
ratatui::style::Modifier::from(crossterm_attribute);
> + let ratatui_modifier =
ratatui::style::Modifier::from_crossterm(crossterm_attribute);
  > - let crossterm_attribute = ratatui_modifier.into();
> - let crossterm_attribute =
crossterm::style::types::Attribute::from(ratatui_modifier);
  > + let crossterm_attribute = ratatui_modifier.into_crossterm();
  > ```
  >
> Similar conversions for `ContentStyle` -> `Style` and `Attributes` ->
  > `Modifier` exist for Crossterm,
  > and all the Termion and Termwiz types.
  >
  > ---------

-
[0a47ebd](0a47ebd94b)
*(bencher)* Update bencher CLI usage by @epompeii in
[#1470](https://github.com/ratatui/ratatui/pull/1470)

-
[b46778d](b46778dd1d)
*(breaking-changes)* Add details to `no_std`-related breaking changes by
@j-g00da in [#1828](https://github.com/ratatui/ratatui/pull/1828)

  > Some corrections and added details to BREAKING-CHANGES.md.
  >
  > I decided to remove:
  >
  > - `Backend` now uses `Self::Error` for error handling instead of
  > `std::io::Error`
  > - `Terminal<B>` now uses `B::Error` for error handling instead of
  > `std::io::Error`
  >
> ...as we are still using `std::io::Error` in built-in backends, so
this
> will only be breaking if a third-party backend decides to use a custom
> error other than `std::io::Error`, which would be a breaking change in
  > downstream and not `ratatui`.
  >
  > The exception to that is `TestBackend`, which uses `Infallible`, but
  > this already has its own breaking changes entry.

-
[a0979d6](a0979d6871)
*(build)* Remove cargo lint by @joshka in
[#1549](https://github.com/ratatui/ratatui/pull/1549)

  > Duplicate crate lint is too noisy and sensitive to upstream changes

-
[3812f69](3812f69997)
*(cargo)* Update the documentation metadata for crates by @orhun in
[#2170](https://github.com/ratatui/ratatui/pull/2170)

  > also follows the same format for the entries (`name` -> `version` ->
  > `description` -> etc. in order)

-
[ae43ea7](ae43ea796a)
*(cell)* Use Option instead of space (" ") for symbol by @joshka

> This change makes the `Cell::symbol` field an `Option<CompactString>`,
  > allowing it to represent an empty cell as `None` instead of an empty
  > string. The rationale for this is to later allow the merge symbol
> functionality to act differently based on whether a cell has
previously
> held a symbol or not, rather than always merging with an empty string.
> This will help make it possible to merge borders with titles with
spaces
  > and other symbols, without assuming that an empty string is always
  > equivalent to no symbol.
  >
  > - Default is now derived as `Option::None` works correctly.
> - PartialEq and Eq implementations are updated to treat `None` the
same
  >   as an empty string.
  > - merge_symbol against an empty cell will now just set the symbol
  >   rather than calling MergeStrategy::merge with an empty string.
  > - PartialEq, and Hash are manually implemented instead of being
  >   derived, and are updated to treat `None` equal to an empty string.

-
[0fbefe9](0fbefe9389)
*(ci)* Don't fail on cargo-deny advisories by @joshka in
[#2237](https://github.com/ratatui/ratatui/pull/2237)

> Instead of failing on advisories, run the cargo-deny check, and report
  > the failure.
  >
  > Uses the cargo-deny-action instead of installing this manually.
  >
>
https://github.com/EmbarkStudios/cargo-deny-action/tree/v2?tab=readme-ov-file#recommended-pipeline-if-using-advisories-to-avoid-sudden-breakages
  > (bumped to use rust stable, and log level info)

-
[887a636](887a6366e5)
*(ci)* Override RUSTUP_TOOLCHAIN for the check step by @ognis1205 in
[#2116](https://github.com/ratatui/ratatui/pull/2116)

  > Summary
  > Fixes an issue where the "check" CI jobs for MSRV and stable were
> unintentionally using the stable toolchain from `rust-toolchain.toml`
  > instead of the matrix-specified toolchain.
  >
  > Details
> - Added `RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}` to the "check" job
  > in CI configuration.
  >
  > Additional Context
  > - https://github.com/ratatui/ratatui/pull/2106
  > -
>
https://discord.com/channels/1070692720437383208/1072879985762762812/1422345357131780177
  > - https://rust-lang.github.io/rustup/overrides.html#overrides

-
[34baaf1](34baaf1137)
*(ci)* Override the toolchain for CI runs by @ognis1205 in
[#2106](https://github.com/ratatui/ratatui/pull/2106)

  > ### Summary
  > Fixes an issue where the beta CI jobs were unintentionally using the
  > stable
  > toolchain from `rust-toolchain.toml` instead of the matrix-specified
  > toolchain.
  > This caused clippy to run against the wrong version.
  >
  > ### Details
  > - Added `RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}` to the CI
  > configuration
  >
  > ### Additional Context
  > -
>
https://discord.com/channels/1070692720437383208/1072879985762762812/1421990770482745415
  > - https://rust-lang.github.io/rustup/overrides.html#overrides

-
[e48aa9e](e48aa9ec09)
*(ci)* Stop publish-alpha from running on forks by @j-g00da in
[#1916](https://github.com/ratatui/ratatui/pull/1916)

> I can't sleep because every Saturday alpha release fails on my ratatui
  > fork. This should fix my insomnia.

-
[b3f3c9b](b3f3c9bfd5)
*(ci)* Disable running release-plz on forked repositories by @orhun in
[#1730](https://github.com/ratatui/ratatui/pull/1730)

  > See https://github.com/jdssl/ratatui/pull/1#issuecomment-2739366609

-
[eaa4038](eaa403856e)
*(ci)* Install pre-built binaries for cargo-rdme by @orhun in
[#1477](https://github.com/ratatui/ratatui/pull/1477)

> `install-action` uses `cargo-binstall` to install the pre-built
binaries
  > of `cargo-rdme` (which was released in
  > https://github.com/orium/cargo-rdme/releases/tag/v1.4.7).
  >
> This will make the `check-readme` step faster in CI (now takes only 10
  > seconds).

-
[e5e2316](e5e2316451)
*(ci)* Add check for keeping README.md up-to-date by @orhun in
[#1473](https://github.com/ratatui/ratatui/pull/1473)

-
[2ef3583](2ef3583eff)
*(ci)* Replace cargo-make with a custom cargo-xtask by @joshka in
[#1461](https://github.com/ratatui/ratatui/pull/1461)

> This removes the need for cargo-make and replaces it with a custom
xtask
  > binary. See <https://github.com/matklad/cargo-xtask> for info.
  >
  > Rearranges the CI workflow to use the new xtask and simplify which
  > workflows that run.
  >
  > ---------

-
[98df774](98df774d7f)
*(core)* Move core types to ratatui-core by @joshka in
[#1460](https://github.com/ratatui/ratatui/pull/1460)

> The buffer, layout, style, symbols, text, and the top level of widgets
  > modules are moved to ratatui-core. This is the first step in
  > modularizing the library so that the core types can be used in other
  > projects without the need for the backend / widgets types.
  >
  > This helps reduce the need for updating other crates as often due to
  > semver changes outside of the core types.
  >
  > ---------

-
[35eba76](35eba76b4d)
*(example)* Move demo2 to top level folder by @joshka in
[#1524](https://github.com/ratatui/ratatui/pull/1524)

-
[5f57d35](5f57d35234)
*(examples)* Add colors explorer demo app by @orhun in
[#1580](https://github.com/ratatui/ratatui/pull/1580)
  >
  > related #1512
  >
  > Moves the colors examples to apps

-
[5c021bf](5c021bf344)
*(examples)* Add chart demo app by @orhun in
[#1579](https://github.com/ratatui/ratatui/pull/1579)
  >
  > related #1512
  >
  > Moves the chart example to apps

-
[9721300](9721300a47)
*(examples)* Add canvas demo app by @orhun in
[#1578](https://github.com/ratatui/ratatui/pull/1578)
  >
  > related #1512
  >
> This moves the canvas example to the apps and adds some interactivity
  > via changing the marker by pressing enter.

-
[a6a1368](a6a1368250)
*(examples)* Add calendar explorer demo app by @orhun in
[#1571](https://github.com/ratatui/ratatui/pull/1571)

  > Related to #1512
  >
  > As discussed, this moves the calendar example from ratatui to app
> examples as an "explorer" example. It also adds interactivity where
you
  > can press s to toggle between different styles of calendars.
  >
  > ---------

-
[819e92c](819e92cd44)
*(examples)* Add weather demo app by @orhun in
[#1567](https://github.com/ratatui/ratatui/pull/1567)

  > related to #1512

-
[b5f7e44](b5f7e44183)
*(examples)* Move async example to apps by @joshka in
[#1503](https://github.com/ratatui/ratatui/pull/1503)

  > Move async example to examples/apps/async as full project.
  > Simplify a little by removing the need for the github api token.

-
[17316ec](17316ec5d0)
*(github)* Enable sponsorship button by @orhun in
[#1478](https://github.com/ratatui/ratatui/pull/1478)

-
[d02995f](d02995fda1)
*(gitignore)* Add `.env` to `.gitignore` by @j-g00da in
[#1949](https://github.com/ratatui/ratatui/pull/1949)

-
[b4a71e5](b4a71e5fd5)
*(lint)* Add `std` instead of `core`/`alloc` lints to `ratatui-widgets`
by @j-g00da in [#1763](https://github.com/ratatui/ratatui/pull/1763)
  >
  > Resolves #1761

-
[cef617c](cef617cc35)
*(lint)* Add `std` instead of `core`/`alloc` lints to `ratatui-core` by
@j-g00da in [#1759](https://github.com/ratatui/ratatui/pull/1759)
  >
  > Resolves #1752

-
[d3f01eb](d3f01ebf6e)
*(lint)* Ensure lint config is correct by @joshka in
[#1528](https://github.com/ratatui/ratatui/pull/1528)

  > - Move lints to workspace manifest
  > - Add lint config to backend crates
  > - Fix one small lint error

-
[9fb0544](9fb054453d)
*(release)* Initialize release-plz by @orhun in
[#1550](https://github.com/ratatui/ratatui/pull/1550)

  > See https://github.com/ratatui/ratatui/pull/1550

-
[60a8191](60a81913ed)
*(widgets)* Move crossterm to dev-dependencies by @j-g00da in
[#1834](https://github.com/ratatui/ratatui/pull/1834)

  > Crossterm in widgets is used only in tests.

-
[2b7ec5c](2b7ec5cb7f)
*(widgets)* Enable calendar widget as default by @orhun in
[#1521](https://github.com/ratatui/ratatui/pull/1521)

  > We now expect that you disable the default features if you want less
  > dependencies

-
[714c658](714c6584c3)
*(workspace)* Use ratatui dependency from the workspace by @orhun in
[#2169](https://github.com/ratatui/ratatui/pull/2169)
  >
  > Fix #2166

-
[d201b8e](d201b8e5dd)
*(xtask)* Check lints for only library targets by @orhun in
[#1531](https://github.com/ratatui/ratatui/pull/1531)

  > Makes it possible to filter workspace packages by their targets.
> (e.g. when we want to retrieve all the binary targets / examples,
etc.)

-
[b7ecef0](b7ecef086d)
*(uncategorized)* Expose crossterm 0.28/0.29 feature flags in Ratatui by
@orhun in [#2270](https://github.com/ratatui/ratatui/pull/2270)

> In docs we currently say that individual versions of crossterm could
be
  > enabled like this:
  >
  > ```toml
  > ratatui = { version = "0.30.0-beta", features = ["crossterm_0_28"] }
  > ```
  >
  > However this wasn't actually possible:
  >
  > ```
> package `x` depends on `ratatui` with feature `crossterm_0_28` but
`ratatui` does not have that feature.
  >
> failed to select a version for `ratatui` which could resolve this
conflict
  > ```
  >
  > This PR fixes that by exposing respective feature flags.
  > (Tested locally)
  >
  > ---------

-
[297d264](297d264c6b)
*(uncategorized)* Update maintainers by @orhun in
[#2122](https://github.com/ratatui/ratatui/pull/2122)

-
[91fa249](91fa249cd4)
*(uncategorized)* Remove obsolete doc_auto_cfg feature by @ognis1205 in
[#2103](https://github.com/ratatui/ratatui/pull/2103)

  > The doc_auto_cfg feature was incorporated into the doc_cfg feature
  > in https://github.com/rust-lang/rust/pull/138907
  >
  > Closes #2102

-
[46e7c6c](46e7c6cbbf)
*(uncategorized)* Document rustfmt options by @joshka in
[#2055](https://github.com/ratatui/ratatui/pull/2055)

-
[719badb](719badb5b8)
*(uncategorized)* Skip `alpha` and `beta` tags in `cliff.toml` by
@j-g00da in [#2026](https://github.com/ratatui/ratatui/pull/2026)
  >
  > https://github.com/ratatui/ratatui/pull/2025#issuecomment-3135177683

-
[0afb1a9](0afb1a99af)
*(uncategorized)* Ignore `beta` and `rc` tags in `cliff.toml` by
@j-g00da in [#2025](https://github.com/ratatui/ratatui/pull/2025)

-
[5ae224b](5ae224b244)
*(uncategorized)* Prepare for beta release by @j-g00da in
[#2022](https://github.com/ratatui/ratatui/pull/2022)

-
[cfebd68](cfebd68e18)
*(uncategorized)* Fix typo in CONTRIBUTING.md by @kdheepak in
[#2001](https://github.com/ratatui/ratatui/pull/2001)

  > Removes a hanging opening code block:
  >
  > ````
  > ```suggestion
  > ````

-
[572749f](572749f388)
*(uncategorized)* Update contributing guidelines and add
copilot-instructions by @joshka in
[#1998](https://github.com/ratatui/ratatui/pull/1998)

  > See
>
https://docs.github.com/en/copilot/how-tos/agents/copilot-code-review/using-copilot-code-review
  >
> These instructions will be used by copilot when it performs automated
PR
> reviews, and helps provide guardrails for our standards. Over time we
> might grow these to capture any consistent problems that we start
seeing
  > when reviewing.
  >
  > ---------

-
[0148b62](0148b62f0c)
*(uncategorized)* Remove cargo_metadata dep from xtask by @joshka in
[#1993](https://github.com/ratatui/ratatui/pull/1993)

  > Removed due to hard N-2 MSRV requirement, whereas we use a soft N-2
> (only update when necessary). This makes it painful to be able to test
> our actual msrv (as the xtask has to be built with the version that
its
> deps support, while still wanting to check the msrv version, so we'd
end
  > up with 2 versions in the one CI task and this would get annoying to
  > check).
  >
> See https://github.com/rust-lang/cargo/issues/15746 for more details.
  >
> Partially implements #1820 - mainly as a problem solution rather than
a
  > specific goal to use cargo-hack

-
[9bc5739](9bc573931c)
*(uncategorized)* Remove clap-cargo from xtask by @joshka in
[#1992](https://github.com/ratatui/ratatui/pull/1992)

  > Removed to avoid needing to bump our msrv. See
>
https://github.com/rust-lang/cargo/issues/15746\#issuecomment-3071774343
  > for more details.

-
[0e10170](0e10170e19)
*(uncategorized)* Change Borders::NONE to a proper const by @joshka in
[#1985](https://github.com/ratatui/ratatui/pull/1985)
  >
  > https://docs.rs/bitflags/latest/bitflags/#zero-bit-flags
  >
  > > Flags with no bits set should be avoided because they interact
  > strangely with
  >
>
[Flags::contains](https://docs.rs/bitflags/latest/bitflags/trait.Flags.html#method.contains)
  > and
  >
>
[Flags::intersects](https://docs.rs/bitflags/latest/bitflags/trait.Flags.html#method.intersects).
> A zero-bit flag is always contained, but is never intersected. The
names
  > of zero-bit flags can be parsed, but are never formatted.
  >
> Removing this simplifies the manual Debug impl that previously had to
  > check for Borders::NONE and now does not.

-
[8e3bd11](8e3bd11d60)
*(uncategorized)* Add svg logo asset by @LitoMore in
[#1967](https://github.com/ratatui/ratatui/pull/1967)

> Added a shields.io style svg logo and a nicer version of the original
logo.
> The simplified icon will be added and available directly from
shields.io via:
  > - https://github.com/simple-icons/simple-icons/pull/13593

-
[92bb9b2](92bb9b2219)
*(uncategorized)* Remove `Title` references by @j-g00da in
[#1943](https://github.com/ratatui/ratatui/pull/1943)

-
[d6647db](d6647db744)
*(uncategorized)* Remove some allow attributes for fixed clippy bugs by
@joshka in [#1944](https://github.com/ratatui/ratatui/pull/1944)

-
[3f48bde](3f48bde3c6)
*(uncategorized)* Remove OpenSSL license by @joshka in
[#1942](https://github.com/ratatui/ratatui/pull/1942)

  > Only keep licenses in the allow list that are actually used

-
[4c86513](4c86513790)
*(uncategorized)* Remove block::Title by @joshka in
[#1926](https://github.com/ratatui/ratatui/pull/1926)

> The title alignment is better expressed in the `Line` as this fits
more
  > coherently with the rest of the library.
  >
  > BREAKING CHANGES:
  > - `widgets::block` is no longer exported
  > - `widgets::block::Title` no longer exists
  > - `widgets::block::Position` is now `widgets::TitlePosition`
> - `Block::title()` now accepts `Into::<Line>` instead of `Into<Title>`
  > - `BlockExt` is now exported at widgets::`BlockExt`
  >
  > Closes:https://github.com/ratatui/ratatui/issues/738

-
[272f5c0](272f5c05dc)
*(uncategorized)* Fix new lints by @joshka in
[#1922](https://github.com/ratatui/ratatui/pull/1922)

-
[770cb7c](770cb7c3c3)
*(uncategorized)* Add tests for combining list styles by @joshka in
[#1884](https://github.com/ratatui/ratatui/pull/1884)

-
[dbfb2c3](dbfb2c3399)
*(uncategorized)* Upgrade to Rust Edition 2024 by @MatrixFrog in
[#1863](https://github.com/ratatui/ratatui/pull/1863)
  >
  > https://doc.rust-lang.org/edition-guide/rust-2024/index.html
  >
  > Fixes #1727

-
[7cb35d4](7cb35d4be1)
*(uncategorized)* Update to Rust version 1.85.0 by @MatrixFrog in
[#1860](https://github.com/ratatui/ratatui/pull/1860)

  > This is a small step toward fixing #1727

-
[a07f5be](a07f5bec20)
*(uncategorized)* Move dependency management to workspace by @joshka in
[#1858](https://github.com/ratatui/ratatui/pull/1858)

  > Move all dependency management to the workspace level. This makes it
> easier to manage dependencies across multiple crates in the workspace.
  >
> This also changes the versions of each dependency to track based on
the
> semver compatible version of the dependency (e.g. 0.1 instead of 0.1.0
  > or 2.9 instead of 2.9.0 to avoid having to regularly update the toml
  > files and to communicate that Ratatui will still generally work with
> versions of the dependencies that are not the fully latest version.
The
  > exact version of the dependencies is still tracked in the Cargo.lock
  > file.
  >
> Several dependencies that are fairly stable are changed to track a
less
  > specific version (e.g. serde 1 instead of 1.0.x).
  >
  > The following dependencies are updated to their latest versions:
  > - bitflags (2.3 -> 2.9)
  > - strum (0.26 -> 0.27)
  > - strum_macros (0.26 -> 0.27)
  > - all other semver compatible updates

-
[1874b9d](1874b9dd55)
*(uncategorized)* Move time to dev-dependencies by @j-g00da in
[#1835](https://github.com/ratatui/ratatui/pull/1835)

-
[d88cd29](d88cd29079)
*(uncategorized)* Add 'const' to functions where possible. by
@MatrixFrog in [#1802](https://github.com/ratatui/ratatui/pull/1802)

> The Clippy check for this (missing_const_for_fn) is already enabled,
but
  > catches more cases in upcoming toolchain versions.
  >
  > This is part of the work to unblock #1727

-
[bb06889](bb068892c9)
*(uncategorized)* Fix io_other_error clippy lints by @joshka in
[#1756](https://github.com/ratatui/ratatui/pull/1756)

> Pre-emptive fix for new lint to be added in 1.87 (currently in beta).
  >
>
https://rust-lang.github.io/rust-clippy/master/index.html\#io_other_error

-
[0f80c5e](0f80c5e87e)
*(uncategorized)* Use expect() instead of allow() for lint overrides by
@cgzones in [#1786](https://github.com/ratatui/ratatui/pull/1786)
[**breaking**]
  >
  > BREAKING CHANGE:MSRV is now 1.81

-
[fe8577c](fe8577c070)
*(uncategorized)* Remove paste dependency by @joshka in
[#1713](https://github.com/ratatui/ratatui/pull/1713)

> The paste crate is no longer maintained. Replaces the usages of this
in
> the Stylize declarative macros with hard coded values. These macros
are
> internal implementation detail to ratatui and so the changes should
have
  > no impact on users.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1712

-
[255e466](255e4661a8)
*(uncategorized)* Cargo update - pull in fixed version of ring crate by
@joshka in [#1710](https://github.com/ratatui/ratatui/pull/1710)

-
[f05feac](f05feac337)
*(uncategorized)* Sort dependencies in Cargo.toml by @canac in
[#1662](https://github.com/ratatui/ratatui/pull/1662)

-
[7eab88f](7eab88fe9a)
*(uncategorized)* Remove unused deps by @joshka in
[#1661](https://github.com/ratatui/ratatui/pull/1661)

-
[37a1c6f](37a1c6f89b)
*(uncategorized)* Remove some examples by @orhun in
[#1645](https://github.com/ratatui/ratatui/pull/1645)

-
[6f21319](6f213191ef)
*(uncategorized)* Rename examples with clashing names by @joshka in
[#1597](https://github.com/ratatui/ratatui/pull/1597)

> These will eventually be moved / consolidated elsewhere, but this
clears
  > the warnings while building for now.

-
[11cbb2b](11cbb2ba87)
*(uncategorized)* Use cargo xtask for bacon clippy command by @joshka in
[#1592](https://github.com/ratatui/ratatui/pull/1592)

-
[b544e39](b544e394c9)
*(uncategorized)* Use clap instead of argh for demo example by @joshka
in [#1591](https://github.com/ratatui/ratatui/pull/1591)

-
[9a54198](9a541981b8)
*(uncategorized)* Make source files non-executable by @orhun in
[#1577](https://github.com/ratatui/ratatui/pull/1577)

  > ```bash
> find . -type f -not -path './.git/*' -not -name '*.bash' -exec chmod
644 {} +
  > ```
  >
  > fixes #1576

-
[357ae7e](357ae7e251)
*(uncategorized)* Move terminal types to ratatui-core by @joshka in
[#1530](https://github.com/ratatui/ratatui/pull/1530) [**breaking**]

  > - Move Terminal, TerminalOptions, ViewPort, CompletedFrame, Frame to
  >   ratatui-core crate
> - Move render_widget_ref() and render_stateful_widget_ref() to
extension
  >   trait (FrameExt) due as the Ref types are unstable and kept in the
  >   main lib instead of -core
  > - Fix rustdoc errors / feature config issues
  >
  > BREAKING CHANGE:to call `Frame::render_widget_ref()` or
  >
  > `Frame::render_stateful_widget_ref()` you now need to import the
  > FrameExt trait from `ratatui::widgets` and enable the
  > `unstable-widget-ref` feature.

-
[21e62d8](21e62d84c2)
*(uncategorized)* Move the demo example to main folder by @joshka in
[#1523](https://github.com/ratatui/ratatui/pull/1523)

  > Add a top level examples folder for more app-ish examples
  > Move the demo example into the top level folder.
  >
  > ---------

-
[fbf6050](fbf6050c86)
*(uncategorized)* Prepare alpha modularization release by @joshka in
[#1525](https://github.com/ratatui/ratatui/pull/1525)

> This is the first modularization -alpha release. It captures the
changes
  > necessary to manual publish. And ensures all the crates are properly
> setup and to set a baseline for comparison in future release checks
etc.
  >
  > This does not update / check the git-cliff setup / changelog
  >
  > Part of: #1388

-
[e4e95bc](e4e95bcecf)
*(uncategorized)* Remove --color always flags from bacon.toml by @joshka
in [#1502](https://github.com/ratatui/ratatui/pull/1502)

  > No longer necessary as of bacon 3.3

-
[a41c97b](a41c97b413)
*(uncategorized)* Move unstable widget refs to ratatui by @joshka in
[#1491](https://github.com/ratatui/ratatui/pull/1491) [**breaking**]

  > These are less stable than the non-ref traits as we have not yet
  > committed to the exact API. This change moves them to ratatui from
  > ratatui-core.
  >
  > To facilitate this:
> - implementations of WidgetRef for all internal widgets are removed
and
  >   replaced with implementations of Widget for references to those
  >   widgets.
> - Widget is now implemented for Option<W> where W: Widget, allowing
for
  >   rendering of optional widgets.
> - The blanket implementation of Widget for WidgetRef is reversed, to
be
  >   a blanket implementation of WidgetRef for all &W where W: Widget.
  >
> BREAKING CHANGE:implementations of WidgetRef no longer have a blanket
  > implementation of Widget, so Widgets should generally implement the
  > Widget trait on a reference to the widget rather than implementing
  > WidgetRef directly. This has the advantage of not requiring unstable
  > features to be enabled.
  >
  > Part of: https://github.com/ratatui/ratatui/issues/1388

-
[e7085e3](e7085e3a3e)
*(uncategorized)* Move widgets into ratatui-widgets crate by @joshka in
[#1474](https://github.com/ratatui/ratatui/pull/1474)

> All the widgets now live in their own ratatui-widgets crate, but are
re-exported in the main ratatui crate.
> This makes it easier to use portions of the ratatui library and is
part of the effort to modularize
  >
  > Part of: #1388
  >
  > ---------

-
[f1d0a18](f1d0a18375)
*(uncategorized)* Move ratatui crate into workspace folder by @joshka in
[#1459](https://github.com/ratatui/ratatui/pull/1459)

  > This is the first step towards modularization. Handling the move
  > as a separate step rather than combining it should make it easier
  > to rebase other PRs when necessary.
  >
  > ---------

-
[55fb2d2](55fb2d2e56)
*(uncategorized)* Update repo links to ratatui instead of ratatui-org by
@joshka in [#1458](https://github.com/ratatui/ratatui/pull/1458)

### Continuous Integration

-
[c01b7d4](c01b7d43ea)
*(uncategorized)* Remove old release workflows by @joshka in
[#2015](https://github.com/ratatui/ratatui/pull/2015)

-
[02ca587](02ca5870c5)
*(uncategorized)* Add environment to release workflow by @joshka in
[#1983](https://github.com/ratatui/ratatui/pull/1983)
  >
>
https://github.com/rust-lang/crates.io/issues/11564#issuecomment-3066696820

-
[821611f](821611f76f)
*(uncategorized)* Use trusted publishing by @joshka in
[#1981](https://github.com/ratatui/ratatui/pull/1981)
  >
>
https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/
  >
  > https://crates.io/docs/trusted-publishing

-
[1f0c2ee](1f0c2ee18e)
*(uncategorized)* Audit github workflows with zizmor by @joshka in
[#1961](https://github.com/ratatui/ratatui/pull/1961)

  > Fixes https://github.com/ratatui/ratatui/issues/1950

-
[a0746ba](a0746bad7e)
*(uncategorized)* Add job to check no-std build by @joshka in
[#1851](https://github.com/ratatui/ratatui/pull/1851)

> Uses x86_64-unknown-none as an arbitrary target that does not support
  > the std library
  >
  > Resolves:https://github.com/ratatui/ratatui/issues/1843

-
[5a3be12](5a3be12ebd)
*(uncategorized)* Run clippy using rust stable and beta by @joshka in
[#1757](https://github.com/ratatui/ratatui/pull/1757)

> This makes it possible to pre-emptively catch upcoming clippy issues.
We
  > should not block PRs on these generally (unless the PR introduces a
> valid clippy warning), so the workflow is set up to not fail on beta.

-
[e7defb3](e7defb36de)
*(uncategorized)* Remove bencher workflows by @joshka in
[#1719](https://github.com/ratatui/ratatui/pull/1719)

  > These actions are currently unused as we haven't
  > invested the time necessary to understand how best
  > to use them. We can always re-add them later if we
  > find them useful.

-
[9398a25](9398a2550a)
*(uncategorized)* Add workflow_dispatch trigger for release-plz by
@joshka in [#1693](https://github.com/ratatui/ratatui/pull/1693)

-
[57c2326](57c2326574)
*(uncategorized)* Run cargo-deny directly rather than via action by
@joshka in [#1621](https://github.com/ratatui/ratatui/pull/1621)

  > Improves CI time

-
[4a871f9](4a871f993e)
*(uncategorized)* Refactor xtask / toml formatting by @joshka in
[#1602](https://github.com/ratatui/ratatui/pull/1602)

  > - format toml files using taplo
  > - add toml formatting check to CI
  > - use xtask consistently from bacon
> - refactor xtask commands to take params instead of multiple commands

### Reverted Commits

-
[cace1e0](cace1e099c)
*(release)* Prepare for beta release by @orhun in
[#2117](https://github.com/ratatui/ratatui/pull/2117)

  > This reverts commit 5ae224b244 so that
  > `release-plz` is being triggered again.
  >
> See
https://github.com/ratatui/ratatui/pull/2022#issuecomment-3349094310
  > for rationale.
  >
  >

### New Contributors

* @sxyazi made their first contribution in
[#2267](https://github.com/ratatui/ratatui/pull/2267)
* @pharrison31415 made their first contribution in
[#2252](https://github.com/ratatui/ratatui/pull/2252)
* @sbarral made their first contribution in
[#2235](https://github.com/ratatui/ratatui/pull/2235)
* @j-g00da made their first contribution in
[#2236](https://github.com/ratatui/ratatui/pull/2236)
* @WaterWhisperer made their first contribution in
[#2221](https://github.com/ratatui/ratatui/pull/2221)
* @0xb002f0 made their first contribution in
[#2223](https://github.com/ratatui/ratatui/pull/2223)
* @matthiasbeyer made their first contribution in
[#2212](https://github.com/ratatui/ratatui/pull/2212)
* @b-guild made their first contribution in
[#2197](https://github.com/ratatui/ratatui/pull/2197)
* @github-actions[bot] made their first contribution in
[#2162](https://github.com/ratatui/ratatui/pull/2162)
* @marcoieni made their first contribution in
[#2119](https://github.com/ratatui/ratatui/pull/2119)
* @Blaeriz made their first contribution in
[#2071](https://github.com/ratatui/ratatui/pull/2071)
* @ognis1205 made their first contribution in
[#2116](https://github.com/ratatui/ratatui/pull/2116)
* @isgin01 made their first contribution in
[#2100](https://github.com/ratatui/ratatui/pull/2100)
* @nornagon made their first contribution in
[#2063](https://github.com/ratatui/ratatui/pull/2063)
* @lolbinarycat made their first contribution in
[#2088](https://github.com/ratatui/ratatui/pull/2088)
* @rcorre made their first contribution in
[#2057](https://github.com/ratatui/ratatui/pull/2057)
* @martinetd made their first contribution in
[#2053](https://github.com/ratatui/ratatui/pull/2053)
* @kashregister made their first contribution in
[#2043](https://github.com/ratatui/ratatui/pull/2043)
* @LitoMore made their first contribution in
[#2040](https://github.com/ratatui/ratatui/pull/2040)
* @aschey made their first contribution in
[#2004](https://github.com/ratatui/ratatui/pull/2004)
* @dtolnay made their first contribution in
[#1999](https://github.com/ratatui/ratatui/pull/1999)
* @MatrixFrog made their first contribution in
[#1994](https://github.com/ratatui/ratatui/pull/1994)
* @jwodder made their first contribution in
[#1670](https://github.com/ratatui/ratatui/pull/1670)
* @acuteenvy made their first contribution in
[#1956](https://github.com/ratatui/ratatui/pull/1956)
* @harilvfs made their first contribution in
[#1905](https://github.com/ratatui/ratatui/pull/1905)
* @Daksh14 made their first contribution in
[#1891](https://github.com/ratatui/ratatui/pull/1891)
* @sevki made their first contribution in
[#1885](https://github.com/ratatui/ratatui/pull/1885)
* @aurreland made their first contribution in
[#1883](https://github.com/ratatui/ratatui/pull/1883)
* @ArjunKrish7356 made their first contribution in
[#1812](https://github.com/ratatui/ratatui/pull/1812)
* @cgzones made their first contribution in
[#1789](https://github.com/ratatui/ratatui/pull/1789)
* @ed-2100 made their first contribution in
[#1782](https://github.com/ratatui/ratatui/pull/1782)
* @musicinmybrain made their first contribution in
[#1783](https://github.com/ratatui/ratatui/pull/1783)
* @LecrisUT made their first contribution in
[#1777](https://github.com/ratatui/ratatui/pull/1777)
* @canac made their first contribution in
[#1662](https://github.com/ratatui/ratatui/pull/1662)
* @LVivona made their first contribution in
[#1639](https://github.com/ratatui/ratatui/pull/1639)
* @alexpasmantier made their first contribution in
[#1622](https://github.com/ratatui/ratatui/pull/1622)
* @theotchlx made their first contribution in
[#1573](https://github.com/ratatui/ratatui/pull/1573)
* @dawedawe made their first contribution in
[#1611](https://github.com/ratatui/ratatui/pull/1611)
* @Its-Just-Nans made their first contribution in
[#1584](https://github.com/ratatui/ratatui/pull/1584)
* @MarSik made their first contribution in
[#1541](https://github.com/ratatui/ratatui/pull/1541)
* @raylu made their first contribution in
[#1540](https://github.com/ratatui/ratatui/pull/1540)
* @renesat made their first contribution in
[#1501](https://github.com/ratatui/ratatui/pull/1501)
* @HoKim98 made their first contribution in
[#1484](https://github.com/ratatui/ratatui/pull/1484)
* @nilsmartel made their first contribution in
[#1485](https://github.com/ratatui/ratatui/pull/1485)
* @epompeii made their first contribution in
[#1470](https://github.com/ratatui/ratatui/pull/1470)
* @thomas-tacquet made their first contribution in
[#1462](https://github.com/ratatui/ratatui/pull/1462)

**Full Changelog**:
https://github.com/ratatui/ratatui/compare/v0.29.0...v0.30.0

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2025-12-26 12:41:00 +03:00
Orhun Parmaksız
8c620d64ae docs(widgets): add link to no-std concept page (#2288)
closes #1959
2025-12-26 11:12:46 +03:00
github-actions[bot]
686d95574e chore: re-release 0.30.0-beta.1 (#2292)
## 🤖 New release

* `ratatui-widgets`: 0.3.0-beta.0 -> 0.3.0-beta.1
* `ratatui-macros`: 0.7.0-beta.0 -> 0.7.0-beta.1
* `ratatui-termwiz`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui-termion`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui`: 0.30.0-beta.0 -> 0.30.0-beta.1

<details><summary><i><b>Changelog</b></i></summary><p>

## `ratatui-widgets`

<blockquote>

##
[v0.30.0-beta.0](https://github.com/ratatui/ratatui/releases/tag/v0.30.0-beta.0)
- 2025-12-23

> _"Rats don't just survive; they discover; they create. ... I mean,
just look at what they do with
the terminal!" – Remy & Orhun_

We are excited to announce the biggest release of `ratatui` so far - a
Rust library that's all about cooking up TUIs 👨‍🍳🐀

📢 Please note that this is a beta release, and we encourage you to try
it out and provide feedback!

 **WIP Release highlights**:
<https://github.com/ratatui/ratatui-website/blob/ratatui-0.30/src/content/docs/highlights/v0.30.md>

⚠️ List of breaking changes can be found
[here](https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md).

### Features

-
[90a77aa](90a77aaf8b)
*(direction)* Add `Direction::perpendicular(self)` by @b-guild in
[#2197](https://github.com/ratatui/ratatui/pull/2197)

-
[56d5e05](56d5e05762)
*(bar)* Update label and text_value to accept Into<> by @Emivvvvv in
[#1471](https://github.com/ratatui/ratatui/pull/1471) [**breaking**]
  >
> BREAKING CHANGE:label and text_value now accept `Into<>` types, which
  > breaks type inference.
  >
  > ```diff
  > - Bar::default().label("foo".into());
  > + Bar::default().label("foo");
  > ```
  >
  > ```diff
  > - Bar::default().text_value("bar".into());
  > + Bar::default().text_value("bar");
  > ```

-
[b76ad3b](b76ad3b02e)
*(bar)* Impl Styled for Bar by @Emivvvvv in
[#1476](https://github.com/ratatui/ratatui/pull/1476)
  >
  > Related:https://github.com/ratatui/ratatui/issues/683

-
[e15fefa](e15fefa922)
*(barchar)* Add BarChart::grouped constructor by @joshka in
[#1513](https://github.com/ratatui/ratatui/pull/1513)

> Add a new constructor to the `BarChart` widget that allows creating a
  > grouped barchart with multiple groups of bars.
  >
> Also add a new constructor to the `BarGroup` widget that allows
creating
  > a group of bars with a label.

-
[369b18e](369b18eef2)
*(barchart)* Reduce barchart creation verbosity by @Emivvvvv in
[#1453](https://github.com/ratatui/ratatui/pull/1453)

  > Adds constructor methods for BarChart, BarGroup, and Bar

-
[1dc18bf](1dc18bf3cf)
*(calendar)* Add width and height functions by @joshka in
[#2198](https://github.com/ratatui/ratatui/pull/2198)

  > Fixes https://github.com/ratatui/ratatui/issues/2016
  >
  > ---------

-
[f18bcbf](f18bcbf06b)
*(canvas)* Add quadrant, sextant and octant markers by @sbarral in
[#2235](https://github.com/ratatui/ratatui/pull/2235) [**breaking**]

> The octant marker is an alternative to the Braille marker with the
same
> resolution, but offering densely packed, regular pseudo-pixels,
without
  > visible bands between rows and columns.
  >
  > Quadrant and Sextants are also added to support 2x2 and 2x3.
  >
> Sextant and Octant unicode characters that are less widely supported
at
  > the moment, which is why `Braille` was left as the default.
  >
  > BREAKING CHANGE:addition of new variants to `Marker` and removal of
  > no longer used constants in `ratatui::symbols::braille`.

-
[26b05de](26b05dee59)
*(chart)* Render Braille over Blocks in Charts and Canvas by @j-g00da in
[#2165](https://github.com/ratatui/ratatui/pull/2165)

> This makes it possible to stack charts, and write text over block
symbols in
> Charts and Canvas while still showing the block symbols behind the
text.

-
[bf84c62](bf84c6229b)
*(core)* Add a `has_modifier()` method to `Style` by @sxyazi in
[#2267](https://github.com/ratatui/ratatui/pull/2267)

  > Resolves https://github.com/ratatui/ratatui/issues/2264

-
[2d713d7](2d713d723d)
*(crossterm)* Allow multiple crossterm versions by @joshka in
[#1841](https://github.com/ratatui/ratatui/pull/1841)

  > This commit introduces feature flags to make it possible for widget
  > library authors to depend on a specific version of crossterm without
> causing version conflicts. This should make it easier for libraries
and
  > apps to update crossterm versions more easily.
  >
> The available feature flags are `crossterm_0_28` and `crossterm_0_29`.
> By default, the latest version is enabled. If a multiple features are
  > enabled we choose the latest version. We will in general support at
  > least the last two major (0.x) versions of crossterm, and will only
  > remove versions in a major version bump.

-
[d99984f](d99984f1e9)
*(layout)* Add `Flex::SpaceEvenly` by @kdheepak in
[#1952](https://github.com/ratatui/ratatui/pull/1952) [**breaking**]

  > Resolves https://github.com/ratatui/ratatui/issues/1951
  >
> BREAKING CHANGE:Old `Flex::SpaceAround` behavior is available by using
  >
  > `Flex::SpaceEvenly` and new
  >
  > `Flex::SpaceAround` now distributes space evenly around each element
  > except the middle spacers
  >     are twice the size of first and last elements
  >
  > With this change, the following variants of `Flex` are supported:
  >
> - `Flex::Start`: Aligns items to the start; excess space appears at
the
  > end.
  > - `Flex::End`: Aligns items to the end; excess space appears at the
  > start.
  > - `Flex::Center`: Centers items with equal space on both sides.
> - `Flex::SpaceAround` (**new**): Distributes space _around_ items;
space
  > between items is _twice_ the edge spacing.
> - `Flex::SpaceBetween`: Distributes space _evenly between_ items
except
  > no space at the edges.
> - `Flex::SpaceEvenly` (**previously `Flex::SpaceAround`**):
Distributes
  > space _evenly between_ items and edges.
> - `Flex::Legacy`: Preserves legacy behavior, placing all excess space
at
  > the end.
  >
  > This aligns behavior of `Flex` with CSS flexbox more closely.
  >
  > The following is a screenshot in action:
  >
  > <img width="1090" alt="image"
  >
>
src="https://github.com/user-attachments/assets/2c7cd797-27bd-4242-a824-4565d369227b"
  > />
  >
  > ---------

-
[9275d34](9275d3421c)
*(layout)* Add Offset::new() constructor by @joshka in
[#1547](https://github.com/ratatui/ratatui/pull/1547)

-
[7ad9c29](7ad9c29eac)
*(linegauge)* Customized symbols by @sectore in
[#1601](https://github.com/ratatui/ratatui/pull/1601)

  > With this PR any symbol (`&str`) can be used to render `filled` and
  > `unfilled` parts of `LineGauge` now. Before that change, only
>
[`symbols::line::Set`](https://docs.rs/ratatui/latest/ratatui/symbols/line/struct.Set.html)
  > was accepted.
  >
  > Note:New methods are introduced to define those symbols:
  > `filled_symbol` and `unfilled_symbol`. The method
>
[`line_set`](https://docs.rs/ratatui/latest/ratatui/widgets/struct.LineGauge.html#method.line_set)
  > is still there, but marked as `deprecated`.
  >
>
![line_gauge](https://github.com/user-attachments/assets/cae308b8-151b-461d-8af6-9a20012adf2f)

-
[92a19cb](92a19cb604)
*(list)* Highlight symbol styling by @airblast-dev in
[#1595](https://github.com/ratatui/ratatui/pull/1595) [**breaking**]

  > Allow styling for `List`'s highlight symbol
  >
  > This change makes it so anything that implements `Into<Line>` can be
  > used as a highlight symbol.
  >
> BREAKING CHANGE:`List::highlight_symbol` can no longer be used in
const
  > context
  >
  > BREAKING CHANGE:`List::highlight_symbol` accepted `&str`. Conversion
  > methods that rely on type inference will need to be rewritten as the
  > compiler cannot infer the type.
  >
  > closes:https://github.com/ratatui/ratatui/issues/1443
  >
  > ---------

-
[e89a526](e89a526aab)
*(no_std)* Portable-atomic integration for targets with no atomic types
by @j-g00da in [#2076](https://github.com/ratatui/ratatui/pull/2076)

  > Improves compatibility with no-std targets that don't support atomic
  > types.
  >
  > We support three different scenarios depending on the target:
  > 1. Terminal applications and other std targets (e.g. espidf):
  > - `std` enabled, `portable-atomic` disabled
  > 2. Embedded targets with atomic types, bare metal x86, etc.:
  > - `std` disabled `portable-atomic` disabled
  > 3. Embedded targets without atomic types (e.g. single-core MCUs):
  > - `std` disabled, `portable-atomic` enabled
  >
> Turning on `portable-atomic` together with `std` will fall back to
`std`
  > atomic.

-
[1399d95](1399d95ae0)
*(no_std)* Make palette and serde features depends on std by @j-g00da in
[#1919](https://github.com/ratatui/ratatui/pull/1919)

-
[b32f781](b32f78195b)
*(no_std)* Make `ratatui-macros` no-std by @j-g00da in
[#1865](https://github.com/ratatui/ratatui/pull/1865)

-
[3e1c72f](3e1c72fb27)
*(no_std)* Make ratatui compatible with `#![no_std]` by @j-g00da in
[#1794](https://github.com/ratatui/ratatui/pull/1794) [**breaking**]
  >
  > Resolves #1781
  >
  > This PR makes it possible to compile ratatui with `#![no_std]`.
  > Also makes me answer "We Are So Embedded" to "Are We Embedded Yet?"

-
[ab48c06](ab48c06171)
*(no_std)* Option to disable layout cache for `no_std` compatibility by
@j-g00da in [#1795](https://github.com/ratatui/ratatui/pull/1795)
[**breaking**]
  >
  > Resolves #1780
  >
  > BREAKING CHANGE:Disabling `default-features` will now disable layout
  > cache, which can have a negative impact on performance.
  >
  > `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only
  > available if `layout-cache` feature is enabled.

-
[09173d1](09173d1829)
*(no_std)* Make `TestBackend::Error` `Infallible` by @j-g00da in
[#1823](https://github.com/ratatui/ratatui/pull/1823) [**breaking**]
  >
> BREAKING CHANGE:`TestBackend` now uses `core::convert::Infallible` for
  > error handling instead of `std::io::Error`

-
[007713e](007713e50a)
*(no_std)* Replace `Backend`'s `io::Error` usages with associated
`Error` type by @j-g00da in
[#1778](https://github.com/ratatui/ratatui/pull/1778) [**breaking**]
  >
  > Resolves #1775
  >
> BREAKING CHANGE:Custom backends now have to implement `Backend::Error`
> and `Backend::clear_region`. Additionally some generic `Backend` usage
  > will have to explicitly set trait bounds for `Backend::Error`.

-
[a42a17e](a42a17e184)
*(no_std)* Make `ratatui-widgets` `no_std` by @j-g00da in
[#1779](https://github.com/ratatui/ratatui/pull/1779)
  >
  > Resolves #1776

-
[5a232a3](5a232a3115)
*(no_std)* Remove redundant `std` usages in `ratatui-widgets` by
@j-g00da in [#1762](https://github.com/ratatui/ratatui/pull/1762)

-
[ebe10cd](ebe10cd81f)
*(no_std)* Remove redundant `std` usages in `ratatui-core` by @j-g00da
in [#1753](https://github.com/ratatui/ratatui/pull/1753)

  > Resolves https://github.com/ratatui/ratatui/issues/1751

-
[08b08cc](08b08cc45b)
*(rect)* Centering by @janTatesa in
[#1814](https://github.com/ratatui/ratatui/pull/1814)
  >
  > Resolves #617

-
[ff729b7](ff729b7607)
*(scrollbar)* Support retrieving the current position of state by @orhun
in [#1552](https://github.com/ratatui/ratatui/pull/1552)

> As of now it is possible to change the position of the Scrollbar but
not
  > possible to retrieve the position for further use. e.g.
  >
  > ```rust
  > let mut state = ScrollbarState::default();
  > state.next();
  > ```
  >
> This commit adds a new method "`current_position`" (since `position`
is
  > already taken by the fluent setter) for that purpose:
  >
  > ```rust
  > let index = state.get_position(); // yay
  > ```
  >
  > See #1545 for the concrete usage of this.

-
[4c3c054](4c3c0540cd)
*(serde)* Handle null modifiers in serde Style by @joshka in
[#2172](https://github.com/ratatui/ratatui/pull/2172)

  > Allow `Style`'s `add_modifier` and `sub_modifier` fields to
  > deserialize from `null`

-
[b9da192](b9da1926a0)
*(serde)* Derive Serialize/Deserialize for alignment enums by @j-g00da
in [#1957](https://github.com/ratatui/ratatui/pull/1957)
  >
  > Resolves #1954

-
[89b7421](89b74214d9)
*(serde)* Derive Serialize/Deserialize for additional structs/enums by
@aurreland in [#1883](https://github.com/ratatui/ratatui/pull/1883)

  > This PR adds `#[derive(Serialize, Deserialize)]` to the following
  > structs:
  > - `Constraint`
  > - `Direction`
  > - `Spacing`
  > - `Layout`
  > - `AccentedPalette`
  > - `NonAccentedPalette`
  > - `Palette`
  > - `Padding`
  > - `Borders`
  > - `BorderType`
  > - `ListDirection`
  > - `ScrollbarOrientation`
  > - `ScrollDirection`
  > - `RenderDirection`
  > - `HighlightSpacing`
  >
  > Fixes #1877

-
[03f3f6d](03f3f6df35)
*(style)* Allow add/sub modifiers to be omitted in Style serialization.
by @rcorre in [#2057](https://github.com/ratatui/ratatui/pull/2057)

  > It's really useful that Style supports Deserialize, this allows TUI
  > apps to have configurable theming without much extra code.
  >
  > However, deserializing a style currently fails if `add_modifier` and
  > `sub_modifier` are
  > not specified. That means the following TOML config:
  >
  > ```toml
  > [theme.highlight]
  > fg = "white"
  > bg = "black"
  > ```
  >
> Will fail to deserialize with "missing field `add_modifier`". It
should
  > be possible
  > to omit modifiers and have them default to "none".

-
[ee67347](ee673476d3)
*(symbols)* Make `Marker` non-exhaustive by @j-g00da in
[#2236](https://github.com/ratatui/ratatui/pull/2236) [**breaking**]

> This will allow us to add new markers without causing further breaking
  > changes.
  >
  > BREAKING CHANGE:`Marker` is now non-exhaustive

-
[985cd05](985cd05573)
*(symbols)* Add dashed borders by @theotchlx in
[#1573](https://github.com/ratatui/ratatui/pull/1573)

  > Adds several new border sets:
  > - ratatui::symbols::border::LIGHT_DOUBLE_DASHED
  > - ratatui::symbols::border::HEAVY_DOUBLE_DASHED
  > - ratatui::symbols::border::LIGHT_TRIPLE_DASHED
  > - ratatui::symbols::border::HEAVY_TRIPLE_DASHED
  > - ratatui::symbols::border::LIGHT_QUADRUPLE_DASHED
  > - ratatui::symbols::border::HEAVY_QUADRUPLE_DASHED
  >
  > And corresponding variants to the ratatui::widgets::BorderType enum
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1355

-
[4c301e8](4c301e891d)
*(text)* Implement `AddAssign` for `Text` by @acuteenvy in
[#1956](https://github.com/ratatui/ratatui/pull/1956)

> This makes it possible to add a second `Text` instance to a first one
using the += operator.
  >
  > ```rust
  > let mut text = Text::from("line 1");
  > text += Text::from("line 2");
  > ```
  >
> Style and alignment applied to the second text is ignored (though
styles and alignment of lines and spans are copied).

-
[ce4856a](ce4856a65f)
*(widgets)* Add the missing constructor to canvas types by @orhun in
[#1538](https://github.com/ratatui/ratatui/pull/1538)

> Allows constructing `Rectangle`, `Points` and `Circle` using the `new`
  > method instead of initializing with the public fields directly.

-
[22610b0](22610b019b)
*(uncategorized)* Support adding an Offset to Position by @joshka in
[#2239](https://github.com/ratatui/ratatui/pull/2239)

  > Adds Position::offset() and arithmentic ops (Position + Offset and
  > Position - Offset)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/2018

-
[24e3133](24e3133456)
*(uncategorized)* Add Rect::resize() method by @joshka in
[#2240](https://github.com/ratatui/ratatui/pull/2240)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1440

-
[96d097e](96d097ef76)
*(uncategorized)* Implement Rect ops for moving by @joshka in
[#1596](https://github.com/ratatui/ratatui/pull/1596)
  >
  > feat:implement Rect ops for moving
  >
  > Implemented `Add`, `AddAssign`, `Sub`, and `SubAssign` on `Rect` for
  > `Offset`. This makes it possible to move rects
  >
  > ```rust
  > let rect = Rect::new(1, 2, 3, 4);
  > let moved = rect + Offset(1, 2);
  > let moved = rect - Offset(1, 2);
  > let moved = rect + Offset(-1, -2);
  > ```
  >
> Additionally Rect, Size, Offset, and Position now all have MIN and MAX
  > consts.

-
[e869cb9](e869cb9750)
*(uncategorized)* Add Size::area() by @joshka in
[#2226](https://github.com/ratatui/ratatui/pull/2226)

  > Add Size::area() returning u32 to avoid u16 overflow
  > Fixes https://github.com/ratatui/ratatui/issues/2204

-
[b6588fd](b6588fd1fa)
*(uncategorized)* Implement `From<Size>` for `(u16, u16)` by @0xb002f0
in [#2223](https://github.com/ratatui/ratatui/pull/2223)

-
[75b78be](75b78be09f)
*(uncategorized)* Add width() impl for tabs by @joshka in
[#2049](https://github.com/ratatui/ratatui/pull/2049)

> The purpose of this is to make it easy for apps to easily calculate
the
  > total tab width including all dividers and padding.

-
[8188ed3](8188ed3950)
*(uncategorized)* Implement UnicodeWidthStr for Text/Line/Span by
@joshka in [#2030](https://github.com/ratatui/ratatui/pull/2030)

  > You can now calculate the width of any Text/Line/Span using the
> UnicodeWidthStr trait instead of the width method on the type. This
also
  > makes it possible to use the width_cjk() method if needed.

-
[c845fec](c845fec765)
*(uncategorized)* Add conversion from Size to Rect by @joshka in
[#2028](https://github.com/ratatui/ratatui/pull/2028)
  >
  > `Rect::from(size)` returns a new Rect at the origin (0, 0) with the
  > specified `Size`

-
[017af11](017af11b2b)
*(uncategorized)* Preserve block titles when merging borders by @j-g00da
in [#1977](https://github.com/ratatui/ratatui/pull/1977)
  >
  > Resolves #1939

-
[6dcd53b](6dcd53bc6b)
*(uncategorized)* Add ergonomic methods for layouting Rects by @joshka
in [#1909](https://github.com/ratatui/ratatui/pull/1909)

> This commit introduces new methods for the `Rect` struct that simplify
> the process of splitting a `Rect` into sub-rects according to a given
> `Layout`. By putting these methods on the `Rect` struct, we make it a
> bit more natural that a layout is applied to the `Rect` itself, rather
  > than passing a `Rect` to the `Layout` struct to be split.
  >
> Adds:- `Rect::layout` and `Rect::try_layout` methods that allow
splitting a
  >   `Rect` into an array of sub-rects according to a given `Layout`.
  > - `Rect::layout_vec` method that returns a `Vec` of sub-rects.
> - `Layout::try_areas` method that returns an array of sub-rects, with
  >   compile-time checks for the number of constraints. This is added
  >   mainly for consistency with the new `Rect` methods.
  >
  > ```rust
  > use ratatui_core::layout::{Layout, Constraint, Rect};
  > let area = Rect::new(0, 0, 10, 10);
  > let layout = Layout::vertical([Constraint::Fill(1); 2]);
  >
  > // Rect::layout() infers the number of constraints at compile time:
  > let [top, main] = area.layout(&layout);
  >
> // Rect::try_layout() and Layout::try_areas() do the same, but return
a
  > // Result:
  > let [top, main] = area.try_layout(&layout)?;
  > let [top, main] = layout.try_areas(area)?;
  >
  > // Rect::layout_vec() returns a Vec of sub-rects:
  > let areas_vec = area.layout_vec(&layout);
  >
  > // you can also explicitly specify the number of constraints:
  > let areas = area.layout::<2>(&layout);
  > let areas = area.try_layout::<2>(&layout)?;
  > let areas = layout.try_areas::<2>(area)?;
  > ```

-
[0c3872f](0c3872f1c5)
*(uncategorized)* Add Rect::outer() by @joshka in
[#1929](https://github.com/ratatui/ratatui/pull/1929)
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/211

-
[7bc78bc](7bc78bca1b)
*(uncategorized)* Add ratatui::run() method by @joshka in
[#1707](https://github.com/ratatui/ratatui/pull/1707)

> This introduces a new `ratatui::run()` method which runs a closure
with
> a terminal initialized with reasonable defaults for most applications.
  > This calls `ratatui::init()` before running the closure and
> `ratatui::restore()` after the closure completes, and returns the
result
  > of the closure.
  >
  > A minimal hello world example using the new `ratatui::run()` method:
  >
  > ```rust
  > fn main() -> Result<(), Box<dyn std::error::Error>> {
  >     ratatui::run(|terminal| {
  >         loop {
> terminal.draw(|frame| frame.render_widget("Hello World!",
frame.area()))?;
  >             if crossterm::event::read()?.is_key_press() {
  >                 break Ok(());
  >             }
  >         }
  >     })
  > }
  > ```
  >
  > Of course, this also works both with apps that use free methods and
  > structs:
  >
  > ```rust
> fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
  >
  > ratatui::run(run)?;
  > ```
  >
  > ```rust
  > struct App { ... }
  >
  > impl App {
  >     fn new() -> Self { ... }
> fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(),
AppError> { ... }
  > }
  >
  > ratatui::run(|terminal| App::new().run(terminal))?;
  > ```

-
[b6fbfcd](b6fbfcdd1c)
*(uncategorized)* Add lifetime to symbol sets by @joshka in
[#1935](https://github.com/ratatui/ratatui/pull/1935)

> This makes it possible to create symbol sets at runtime with
non-static
  > lifetimes.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1722

-
[488e5f0](488e5f020f)
*(uncategorized)* Make `border!` work without importing `Borders` by
@j-g00da in [#1918](https://github.com/ratatui/ratatui/pull/1918)

> Currently using `border!` macro requires explicit import of `Borders`
  > which is unnecessary.

-
[671c2b4](671c2b4fd4)
*(uncategorized)* Support merging the borders of blocks by @j-g00da

> When two borders overlap, they will automatically merge into a single,
  > clean border instead of overlapping.
  >
> This improves visual clarity and reduces rendering glitches around
corners.
  >
  > For example:
  >
  > ```
> assert_eq!(Cell::new("┘").merge_symbol("┏",
MergeStrategy::Exact).symbol(), "╆");
  > ```

-
[702fff5](702fff501c)
*(uncategorized)* Implement stylize methods directly on Style by @joshka
in [#1572](https://github.com/ratatui/ratatui/pull/1572) [**breaking**]

> This makes it possible to create constants using the shorthand
methods.
  >
  > ```rust
  > const MY_STYLE: Style = Style::new().blue().on_black();
  > ```
  >
  > Rather than implementing Styled for Style and then adding extension
  > methods that implement the Stylize shorthands, this implements the
  > methods as const functions directly on Style.
  >
  > BREAKING CHANGE:`Style` no longer implements `Styled`. Any calls to
  > methods implemented by the blanket implementation of Stylize are now
> defined directly on Style. Remove the Stylize import if it is no
longer
  > used by your code.
  >
> The `reset()` method does not have a direct replacement, as it clashes
  > with the existing `reset()` method. Use `Style::reset()` rather than
  > `some_style.reset()`
  >
  > Fixes:#1158

-
[4fcd238](4fcd238e1e)
*(uncategorized)* Support no-std for calendar widget by @joshka in
[#1852](https://github.com/ratatui/ratatui/pull/1852)

> Removes the CalendarEventStore::today() function in no-std
environments

-
[53cdbbc](53cdbbccd5)
*(uncategorized)* Enable serde propagation to backend crates (crossterm,
termion) by @ArjunKrish7356 in
[#1812](https://github.com/ratatui/ratatui/pull/1812)

> This PR propagates the serde feature from the main ratatui crate to
the
  > ratatui-crossterm and ratatui-termion backend crates. Solves #1805

-
[6836a69](6836a6903e)
*(uncategorized)* Implement styled for other primitives by @aschey in
[#1684](https://github.com/ratatui/ratatui/pull/1684)

-
[fcb47d6](fcb47d60f3)
*(uncategorized)* Rename Alignment to HorizontalAlignment and add
VerticalAlignment by @joshka in
[#1735](https://github.com/ratatui/ratatui/pull/1735) [**breaking**]

> We don't anticipate removing or deprecating the type alias in the near
  > future, but it is recommended to update your imports to use the new
  > name.
  >
> Added a VerticalAlignment enum to make the API more consistent. We
don't
> have a specific use case for it yet, but it's better to add it now and
  > be able to use it in the future.
  >
  > BREAKING-CHANGE:The `Alignment` enum has been renamed to
> `HorizontalAlignment` to better reflect its purpose. A type alias has
> been added to maintain backwards compatibility, however there are some
  > cases where type aliases are not enough to maintain backwards
  > compatibility. E.g. when using glob imports to import all the enum
> variants. This should not affect most users, but it is recommended to
  > update your imports to use the new name.
  >
  > ```diff
  > - use ratatui::layout::Alignment;
  > + use ratatui::layout::HorizontalAlignment;
  >
  > - use Alignment::*;
  > + use HorizontalAlignment::*;
  > ```

-
[2714d6b](2714d6b9c3)
*(uncategorized)* Add array and tuple RGB color conversion methods by
@joshka in [#1703](https://github.com/ratatui/ratatui/pull/1703)

> Other crates (e.g. colorgrad) that deal with colors can convert colors
> to a tuple of 3 or 4 u8 values. This commit adds conversion methods
from
  > these types to a `Color::Rgb` instance. Any alpha value is ignored.
  >
  > ```rust
  > Color::from([255, 0, 0]);
  > Color::from((255, 0, 0));
  > Color::from([255, 0, 0, 255]);
  > Color::from((255, 0, 0, 255));
  > ```

-
[50ba965](50ba96518f)
*(uncategorized)* Add a new RatatuiMascot widget by @Its-Just-Nans in
[#1584](https://github.com/ratatui/ratatui/pull/1584)

  > Move the Mascot from Demo2 into a new widget.
  > Make the Rat grey and adjust the other colors.
  >
  > ```rust
  > frame.render_widget(RatatuiMascot::default(), frame.area());
  > ```

-
[1d28c89](1d28c89fe5)
*(uncategorized)* Add conversions for anstyle by @joshka in
[#1581](https://github.com/ratatui/ratatui/pull/1581)
  >
> https://crates.io/crates/anstyle makes it possible to define colors in
> an interoperable way. This makes it possible for applications to
easily
  > load colors from a variety of formats.
  >
> This is gated by the anstyle feature flag which is disabled by
default.
  >
  > ---------

### Bug Fixes

-
[a89d3d6](a89d3d62ff)
*(buffer)* Clear behavior with VS16 wide emojis by @nornagon in
[#2063](https://github.com/ratatui/ratatui/pull/2063)

  > This fixes a bug where certain emojis like ⌨️ would sometimes be
> "overlaid" onto existing content from the buffer, instead of properly
  > clearing.
  >
  > [example demonstrating
>
bug](https://gist.github.com/nornagon/11a79d7a1f2e98aa129fedb4abccc530)
  >
  > This PR was generated by Codex, and validated by me:
> 1. Behavior of the above example code was buggy before this fix
(showed
  > overlaying "b" on top of the keyboard emoji), and fixed after.
> 2. The U+FE0F check is not strictly required, but I did note that
emoji
  > without this char don't exhibit the buggy behavior, even without the
  > fix.
  >
  > ---------

-
[ec30390](ec30390446)
*(canvas)* Round coordinates to nearest grid cell by @joshka in
[#1507](https://github.com/ratatui/ratatui/pull/1507)

  > Previously the canvas coordinates were rounded towards zero, which
> causes the rendering to be off by one pixel in some cases. It also
meant
> that pixels at the extreme edges of the canvas can only be drawn if
the
  > point was exactly on the edge of the canvas. This commit rounds the
> coordinates to the nearest integer instead. This may change the output
  > for some apps using Canvas / Charts.

-
[afd1ce1](afd1ce179b)
*(canvas)* Lines that start outside the visible grid are now drawn by
@renesat in [#1501](https://github.com/ratatui/ratatui/pull/1501)

> Previously lines with points that were outside the canvas bounds were
> not drawn at all. Now they are clipped to the bounds of the canvas so
  > that the portion of the line within the canvas is draw.
  >
> To facilitate this, a new `Painter::bounds()` method which returns the
  > bounds of the canvas is added.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1489

-
[2b0a044](2b0a044ced)
*(ci)* Add contents write permission to release-plz PR by @marcoieni in
[#2119](https://github.com/ratatui/ratatui/pull/2119)
  >
  > https://release-plz.dev/docs/github/quickstart#3-setup-the-workflow
  >
  > Fixes https://github.com/release-plz/release-plz/issues/2439

-
[18e70d3](18e70d3d51)
*(crossterm)* Terminal should keep Bold when removing Dim by @MarSik in
[#1541](https://github.com/ratatui/ratatui/pull/1541)

  > The Dim removal should behave the same as the logic for Bold removal
> that sends NormalIntensity sequence and then restores Dim when needed.

-
[16b76e3](16b76e36ee)
*(demo)* Update the width of demo2 tape by @orhun in
[#2164](https://github.com/ratatui/ratatui/pull/2164)

>
![](https://github.com/ratatui/ratatui/blob/images/examples/demo2.gif?raw=true)
  >
  > fixes #1721

-
[dca331c](dca331c748)
*(demo)* Support tab key in demo2 example by @orhun in
[#1726](https://github.com/ratatui/ratatui/pull/1726)
  >
  > see #1721
  >
> Not sure what caused this - it's been there for a while probably and
we
  > didn't realize it since we used `demo2-destroy` mostly.

-
[0fd4753](0fd4753e6b)
*(examples)* Run the correct example for chart by @orhun in
[#1679](https://github.com/ratatui/ratatui/pull/1679)
  >
  > fixes #1678

-
[39479e2](39479e298c)
*(examples)* Ensure that example projects are not published by @orhun in
[#1672](https://github.com/ratatui/ratatui/pull/1672)

-
[9314312](93143126b3)
*(layout)* Feature flag cache related types by @joshka in
[#1842](https://github.com/ratatui/ratatui/pull/1842)

-
[2dd1977](2dd1977c59)
*(layout-cache)* Import `NonZeroUsize` only when `layout-cache` is
enabled by @j-g00da in
[#1839](https://github.com/ratatui/ratatui/pull/1839)

> This silences unused import warning, when `layout-cache` is disabled.

-
[564a9d7](564a9d76fc)
*(line-gauge)* Pad default label to display 3 numbers by @martinetd in
[#2053](https://github.com/ratatui/ratatui/pull/2053)

> Display the default label of the LineGauge widget padded to fill 3
cells.
> This makes it so that the label doesn't shift around when going from a
  > single digit to double / triple digits.
  >
> To maintain the existing behavior, use a custom label by calling
`.label()`
  > on the LineGauge.

-
[a692a6e](a692a6e371)
*(lint)* Apply rust 1.84 clippy suggestions by @joshka in
[#1612](https://github.com/ratatui/ratatui/pull/1612)

  > The canvas map constants are now statics instead.
  > Fixes
>
https://rust-lang.github.io/rust-clippy/master/index.html\#large_const_arrays

-
[2e54d5e](2e54d5e22c)
*(macros)* Use $crate re-export in text macro by @airblast-dev in
[#1832](https://github.com/ratatui/ratatui/pull/1832)

-
[79d5165](79d5165cae)
*(no_std)* Propagate `std` feature flag to dependencies by @j-g00da in
[#1838](https://github.com/ratatui/ratatui/pull/1838)

> Disables `std` feature flags in dependencies and only enables them
with
> `ratatui` and `ratatui-core`'s `std` feature flag. This partially
fixes the
> issue of still depending on `std`, when `std` feature flag is
disabled.

-
[00da8c6](00da8c6203)
*(no_std)* Provide `f64` polyfills for `no_std` compatibility by
@j-g00da in [#1840](https://github.com/ratatui/ratatui/pull/1840)
  >
  > Related:https://github.com/rust-lang/rust/issues/137578

-
[3b13240](3b13240728)
*(scrollbar)* Check for area.is_empty() before rendering by @farmeroy in
[#1529](https://github.com/ratatui/ratatui/pull/1529)

> This adds the `area.is_empty()` back into the scrollbar render method.
  > Without it, the widget panics if the height is 0.

-
[f57b696](f57b696fdc)
*(span)* Dont render control characters by @EdJoPaTo in
[#1312](https://github.com/ratatui/ratatui/pull/1312)

-
[2ce958e](2ce958e38c)
*(table)* Allow display of additional table row, if row height > 1 by
@Lunderberg in [#1452](https://github.com/ratatui/ratatui/pull/1452)

-
[0a25bc1](0a25bc166d)
*(tests)* Update the stderr snapshot for ratatui-macros by @orhun in
[#2161](https://github.com/ratatui/ratatui/pull/2161)

  > New 🦀 broke the CI

-
[5fa342c](5fa342cc52)
*(widgets)* Fix centered block title truncation by @ognis1205 in
[#1973](https://github.com/ratatui/ratatui/pull/1973)

  > Previously block titles that were aligned center were
  > truncated poorly (aligned to the left, and the last
  > non-fitting title would be truncated on the left and right.
  > This now truncates the titles more obviously centered.

-
[f919b25](f919b25ea6)
*(uncategorized)* String_to_string lint is now part of implicit_clone by
@joshka in [#2173](https://github.com/ratatui/ratatui/pull/2173)

-
[1fe64de](1fe64de09a)
*(uncategorized)* Include underline color in anstyle conversion by
@aschey in [#2004](https://github.com/ratatui/ratatui/pull/2004)

  > Underline color wasn't included in the style conversion logic.

-
[c1b8528](c1b8528b69)
*(uncategorized)* Panic when rendering widgets on too small buffer by
@j-g00da in [#1996](https://github.com/ratatui/ratatui/pull/1996)

> Fixes panic on overflow on horizontal `Barchart` and `RatatuiMascot`
and adds proper tests to all widgets.
  >
  > ---------

-
[08b21fa](08b21fa55c)
*(uncategorized)* Fix panic when rendering a `Paragraph` out of bounds
by @jwodder in [#1670](https://github.com/ratatui/ratatui/pull/1670)
  >
  > Fixes #1667.

-
[80bc818](80bc818723)
*(uncategorized)* Fix truncation of left aligned block titles by @joshka
in [#1931](https://github.com/ratatui/ratatui/pull/1931)

> truncate the right side of left aligned titles rather than the left
side
> of right aligned titles. This is more obvious as the left side of text
  > often contains more important information. And we generally read
  > left to right.
  >
  > This change makes centered titles overwrite left aligned titles and
  > right aligned titles overwrite centered or left aligned titles.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/358

-
[21e3b59](21e3b598ce)
*(uncategorized)* Fix handling of multi-byte chars in bar chart by
@joshka in [#1934](https://github.com/ratatui/ratatui/pull/1934)

  > The split_at method requires that the split point is at a valid utf8
  > character boundary.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1928

-
[e1e4004](e1e400406c)
*(uncategorized)* Derive copy for list state by @janTatesa in
[#1921](https://github.com/ratatui/ratatui/pull/1921)

-
[12cb5a2](12cb5a28fe)
*(uncategorized)* Allow canvas area to exceed u16::MAX by @Daksh14 in
[#1891](https://github.com/ratatui/ratatui/pull/1891)

> This allows Canvas grids where the width * height exceeds u16::MAX by
  > converting values to usize earlier in several methods.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1449

-
[09cc9ef](09cc9ef57d)
*(uncategorized)* Typo in changelog by @joshka in
[#1857](https://github.com/ratatui/ratatui/pull/1857)

-
[c238aca](c238aca83a)
*(uncategorized)* `padding_right()` should set right padding instead of
left by @sxyazi in [#1837](https://github.com/ratatui/ratatui/pull/1837)

  > Fixes https://github.com/ratatui/ratatui/issues/1836

-
[c90ba97](c90ba9781e)
*(uncategorized)* Avoid unnecessary imports in minimal build by @cgzones
in [#1787](https://github.com/ratatui/ratatui/pull/1787)
  >
  > core::ops::Range is only used with the feature `scrolling-regions`.
  > Ensure a minimal `cargo check` reports no warnings.

-
[416ebdf](416ebdf8c8)
*(uncategorized)* Correct clippy errors introduced by rust 1.86.0 update
by @j-g00da in [#1755](https://github.com/ratatui/ratatui/pull/1755)

  > New version of rust (1.86.0) caused CI to fail.

-
[4eac5b2](4eac5b2849)
*(uncategorized)* Make deprecation notes more helpful by @joshka in
[#1702](https://github.com/ratatui/ratatui/pull/1702)

> AI coding assistants use the deprecation notes to automatically
suggest
> fixes. This commit updates the deprecation notes to push those tools
to
  > suggest the correct replacement methods and types.
  >
> Specifically, AI tools often suggest using `Buffer::get(x, y)`,
because
  > of their training data where this was prevalent. When fixing these
> deprecations, they often incorrectly suggest using `Buffer::get(x, y)`
  > instead of `Buffer[(x, y)]`.

-
[35a8642](35a86427ab)
*(uncategorized)* `Rect::positions()` should be empty when width is 0
and height is nonzero by @jwodder in
[#1669](https://github.com/ratatui/ratatui/pull/1669)
  >
  > Fixes #1666.

-
[f5fc819](f5fc8197ff)
*(uncategorized)* Avoid extra line break on whitespace only lines when
wrapping paragraphs by @dotdash in
[#1636](https://github.com/ratatui/ratatui/pull/1636)

  > Currently whitespace only lines produces an extra line break when
  > trimming is disabled, because both the trimmed as well as the
  > non-trimmed line get inserted. Fix this by only inserting the
  > non-trimmed one.

-
[2892bdd](2892bddce6)
*(uncategorized)* Rust 1.83 clippy lints by @joshka in
[#1527](https://github.com/ratatui/ratatui/pull/1527)
  >
>
https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes

-
[36e2d1b](36e2d1bda1)
*(uncategorized)* Add feature(doc_cfg) when generating docs by @joshka
in [#1506](https://github.com/ratatui/ratatui/pull/1506)

-
[4d7704f](4d7704fba5)
*(uncategorized)* Make StatefulWidget and Ref work with unsized State by
@thscharler in [#1505](https://github.com/ratatui/ratatui/pull/1505)
  >
  > StatefulWidget::State and StatefulWidgetRef::State are now ?Sized.
  >
> This allows implementations of the traits to use unsized types for the
  > State associated type. This is turn is useful when doing things like
  > boxing different stateful widget types with State which implements
  > `Any`, are slices or any other dynamically sized type.

-
[7b87509](7b875091e1)
*(uncategorized)* Typo by @marcoieni in
[#1480](https://github.com/ratatui/ratatui/pull/1480)

### Refactor

-
[8d60e96](8d60e96b2b)
*(examples)* Use crossterm event methods by @joshka in
[#1792](https://github.com/ratatui/ratatui/pull/1792)

> Crossterm 0.29 introduced methods to easily check / extract the event
  > type. E.g. as_key_press_event() and is_key_press(). This commit
  > updates the examples to use these methods instead of matching on
  > the event type. This makes the code cleaner and easier to read.
  >
> Also does a general cleanup of the event handling code in the
examples.

-
[07bec55](07bec55b7d)
*(no_std)* Make usages of std explicit in ratatui-core. by @ed-2100 in
[#1782](https://github.com/ratatui/ratatui/pull/1782)

  > ### This commit does the following:
  >
  > - Adds `#[no_std]` to `lib.rs`.
  > - Adds `extern crate std;` to `lib.rs`.
> - Updates `ratatui-core` to explicitly `use` items from std and alloc.
  > - Prefers `use`-ing alloc over std when possible.
  >
  > ### Explanation:
  >
> This allows usages of `std` in `ratatui-core` to be clearly pointed
out
  > and dealt with individually.
  >
  > Eventually, when `std` is to be feature gated, the associated commit
  > will be much cleaner.

-
[f132fa1](f132fa1715)
*(table)* Small readability improvements by @joshka in
[#1510](https://github.com/ratatui/ratatui/pull/1510)

-
[c7c3498](c7c3498025)
*(uncategorized)* Use saturating_add in Rect::new by @pharrison31415 in
[#2216](https://github.com/ratatui/ratatui/pull/2216)

-
[02e53de](02e53de0f8)
*(uncategorized)* Make use of iter::repeat_n() by @cgzones in
[#1788](https://github.com/ratatui/ratatui/pull/1788)

  > Applied via clippy --fix.
  > Available since 1.82.0.

-
[a195d59](a195d59a47)
*(uncategorized)* Move xtask commands to small modules by @joshka in
[#1620](https://github.com/ratatui/ratatui/pull/1620)

-
[904b0aa](904b0aa723)
*(uncategorized)* Move symbols to modules by @joshka in
[#1594](https://github.com/ratatui/ratatui/pull/1594)

-
[7c8573f](7c8573f575)
*(uncategorized)* Rearrange selection_spacing code by @raylu in
[#1540](https://github.com/ratatui/ratatui/pull/1540)

-
[217c57c](217c57cd60)
*(uncategorized)* Modularize backends by @orhun in
[#1508](https://github.com/ratatui/ratatui/pull/1508)

> Backend code is now moved to `ratatui-crossterm`, `ratatui-termion`
and
> `ratatui-termwiz`. This should be backwards compatible with existing
code.

-
[e461b72](e461b724a6)
*(uncategorized)* Move {Stateful,}Widget{,Ref} types into individual
files by @joshka in
[#1479](https://github.com/ratatui/ratatui/pull/1479)

> This is a preparatory refactoring for modularization. No user visible
  > changes.

### Documentation

-
[40e96a2](40e96a2a04)
*(block)* Add collapsed border example by @joshka in
[#1899](https://github.com/ratatui/ratatui/pull/1899)

-
[d291042](d291042e69)
*(block)* Revise the block example by @orhun in
[#1520](https://github.com/ratatui/ratatui/pull/1520)

  > - Moves the block example from `ratatui` to `ratatui-widgets`
  > - Simplifies the example (bordered, styled, custom borders)
  >
  > see #1512

-
[0951da5](0951da52f9)
*(breaking-changes)* Improve migration guide for `Backend::Error` by
@j-g00da in [#1908](https://github.com/ratatui/ratatui/pull/1908)
  >
  > Related:https://github.com/fujiapple852/trippy/pull/1588

-
[bbe1cf9](bbe1cf9497)
*(breaking-changes)* Change MSRV to 1.85 by @j-g00da in
[#1896](https://github.com/ratatui/ratatui/pull/1896)

> The minimum supported Rust version is now for `ratatui` v0.30 is 1.85

-
[c7912f3](c7912f3990)
*(breaking-changes)* Fix header level by @j-g00da in
[#1825](https://github.com/ratatui/ratatui/pull/1825)

-
[fcde9cb](fcde9cb9c3)
*(changelog)* Fix typo by @orhun in
[#1463](https://github.com/ratatui/ratatui/pull/1463)

-
[73488ab](73488abb45)
*(contributing)* Fix link to `widgets_block_renders` test by @ognis1205
in [#2101](https://github.com/ratatui/ratatui/pull/2101)

  > The `CONTRIBUTING.md` referenced `tests/widgets_block.rs`, but the
> correct path is `ratatui/tests/widgets_block.rs`. Updated the link so
  > that readers can navigate to the test example without 404 error.
  >
  > ---------

-
[0b025db](0b025db72b)
*(contributing)* Fix grammar by @j-g00da in
[#1958](https://github.com/ratatui/ratatui/pull/1958)

-
[1197b2a](1197b2a02c)
*(contributing)* Add note about using nightly for formatting by @joshka
in [#1816](https://github.com/ratatui/ratatui/pull/1816)

-
[3ae6bf1](3ae6bf1d6f)
*(contributing)* Use cargo-xtask for instructions by @orhun in
[#1509](https://github.com/ratatui/ratatui/pull/1509)

  > - Updates `CONTRIBUTING.md` about the usage of `xtask`
  > - Removes `Makefile.toml`

-
[22e3e84](22e3e84de8)
*(core)* Remove link to Paragraph widget by @orhun in
[#1683](https://github.com/ratatui/ratatui/pull/1683)

-
[b65788c](b65788ce14)
*(examples)* Remove duplicated link by @matthiasbeyer in
[#2212](https://github.com/ratatui/ratatui/pull/2212)

-
[200b217](200b217722)
*(examples)* Add VHS tapes and docs for widget examples by @orhun in
[#2114](https://github.com/ratatui/ratatui/pull/2114)
  >
  > fixes #1982
  >
> Later on I'll figure out an easy way to regenerate this in the CI and
  > possibly do the same for the app examples' VHS tapes. That's why I
  > haven't added a script or mentioned anything in the docs yet (hint:
  > #1721)
  >
  > ---------

-
[861fbdf](861fbdf5cf)
*(examples)* Fix a typo by @j-g00da in
[#1890](https://github.com/ratatui/ratatui/pull/1890)

  > Makes CI typos check pass again

-
[882cc3c](882cc3c6c6)
*(examples)* Update app examples with tapes by @orhun in
[#1673](https://github.com/ratatui/ratatui/pull/1673)

-
[4393fae](4393fae54c)
*(examples)* Move scrollbar example to examples folder by @orhun in
[#1665](https://github.com/ratatui/ratatui/pull/1665)

-
[9ea70e2](9ea70e28c6)
*(examples)* Move widget-impl example to examples folder by @orhun in
[#1663](https://github.com/ratatui/ratatui/pull/1663)

-
[774ab78](774ab788d4)
*(examples)* Move widget-ref-container example to examples folder by
@orhun in [#1664](https://github.com/ratatui/ratatui/pull/1664)
  >
  > see #1512

-
[910d16e](910d16e63a)
*(examples)* Move user-input example to examples folder by @orhun in
[#1659](https://github.com/ratatui/ratatui/pull/1659)

-
[dbfb7da](dbfb7da9e3)
*(examples)* Move table example to examples folder by @orhun in
[#1657](https://github.com/ratatui/ratatui/pull/1657)

-
[cb2a58a](cb2a58aaa0)
*(examples)* Move tracing example to examples folder by @orhun in
[#1658](https://github.com/ratatui/ratatui/pull/1658)

-
[7e00b64](7e00b646fc)
*(examples)* Move panic example to examples folder by @orhun in
[#1655](https://github.com/ratatui/ratatui/pull/1655)

-
[8127590](8127590812)
*(examples)* Move modifiers example to examples folder by @orhun in
[#1654](https://github.com/ratatui/ratatui/pull/1654)

-
[7c40c0b](7c40c0bbdd)
*(examples)* Move popup example to examples folder by @orhun in
[#1656](https://github.com/ratatui/ratatui/pull/1656)
  >
  > see #1512

-
[d87354f](d87354f400)
*(examples)* Move list example to examples folder by @orhun in
[#1653](https://github.com/ratatui/ratatui/pull/1653)
  >
  > see #1512
  >
  > also renames it to todo-list

-
[621226f](621226f2e2)
*(examples)* Move inline example to examples folder by @orhun in
[#1651](https://github.com/ratatui/ratatui/pull/1651)

-
[9ba7d25](9ba7d25b71)
*(examples)* Move hyperlink example to examples folder by @orhun in
[#1650](https://github.com/ratatui/ratatui/pull/1650)

-
[bb94d1c](bb94d1c0fa)
*(examples)* Move minimal example to examples folder by @orhun in
[#1649](https://github.com/ratatui/ratatui/pull/1649)

-
[9f399ac](9f399ac7a6)
*(examples)* Move gauge example to examples folder by @orhun in
[#1646](https://github.com/ratatui/ratatui/pull/1646)

-
[104d6a6](104d6a6c2b)
*(examples)* Move custom-widget example to examples folder by @orhun in
[#1644](https://github.com/ratatui/ratatui/pull/1644)

-
[fa8ca01](fa8ca0121a)
*(examples)* Move flex example to examples folder by @orhun in
[#1642](https://github.com/ratatui/ratatui/pull/1642)

-
[f5fde0e](f5fde0ef53)
*(examples)* Move constraints example to examples folder by @orhun in
[#1641](https://github.com/ratatui/ratatui/pull/1641)

-
[fc70288](fc70288954)
*(examples)* Move constraint-explorer example to examples folder by
@orhun in [#1640](https://github.com/ratatui/ratatui/pull/1640)

-
[325f961](325f96102a)
*(examples)* Move hello-world example to examples folder by @orhun in
[#1647](https://github.com/ratatui/ratatui/pull/1647)

-
[867c4bc](867c4bc4e9)
*(examples)* Move colors-rgb example to examples folder by @joshka in
[#1582](https://github.com/ratatui/ratatui/pull/1582)

  > - **docs: move colors-rgb example to examples folder**
  > - **docs: update main examples README**
  >
  > ---------

-
[72334ed](72334ed61c)
*(layout)* Update documentation to point to `kasuari` solver by @a-kenji
in [#2003](https://github.com/ratatui/ratatui/pull/2003)

-
[2be9ccb](2be9ccb120)
*(layout)* Remove unnecessary path prefix by @j-g00da in
[#1766](https://github.com/ratatui/ratatui/pull/1766)

-
[b669ceb](b669cebcaf)
*(layout)* Change `cassowary` to `kasuari` crate reference by @j-g00da
in [#1765](https://github.com/ratatui/ratatui/pull/1765)

-
[f907c74](f907c74bb3)
*(license)* Update copyright years by @LVivona in
[#1639](https://github.com/ratatui/ratatui/pull/1639)

  > Update MIT Licence to copyright year 2025

-
[68b9f67](68b9f67f59)
*(readme)* Add `Built with Ratatui` badge for downstream projects by
@harilvfs in [#1905](https://github.com/ratatui/ratatui/pull/1905)

-
[088aac1](088aac136d)
*(readme)* Tweak links and badges by @joshka in
[#1598](https://github.com/ratatui/ratatui/pull/1598)

-
[6e43672](6e436725e4)
*(readme)* Reimagine README.md by @orhun in
[#1569](https://github.com/ratatui/ratatui/pull/1569)

> This is the result of the re-imagination of a more suitable README.md.
It
  > is simpler and shorter: not giving more information to the user than
  > they actually need.
  >
> Also updates the quickstart code with the up-to-date version and adds
  > link to templates which was missing.
  >
  > ---------

-
[8f28247](8f282473b2)
*(readme)* Correct examples links by @HoKim98 in
[#1484](https://github.com/ratatui/ratatui/pull/1484)

-
[9f90f74](9f90f7495f)
*(readme)* Fix broken link by @nilsmartel in
[#1485](https://github.com/ratatui/ratatui/pull/1485)

-
[260af68](260af68a34)
*(readme)* Include iocraft as an alternative by @kdheepak in
[#1483](https://github.com/ratatui/ratatui/pull/1483)

-
[8e5151f](8e5151f83d)
*(rect)* Fix typo in the Rect::outer function comments by @orhun in
[#2123](https://github.com/ratatui/ratatui/pull/2123)

-
[40f13c6](40f13c6a6c)
*(rect)* Update the outdated comment for Rect::area() by @isgin01 in
[#2100](https://github.com/ratatui/ratatui/pull/2100)

> The return value of Rect.area() is no longer of u16 type, and the
value
  > is not being clumped anymore.

-
[ce16692](ce16692b9a)
*(release)* Fix typo by @j-g00da in
[#1754](https://github.com/ratatui/ratatui/pull/1754)

-
[9a930a6](9a930a6e99)
*(terminal)* Made usage of Terminal::get_frame() clearer by @Blaeriz in
[#2071](https://github.com/ratatui/ratatui/pull/2071)

  > Closes : https://github.com/ratatui/ratatui/issues/1200
  >
  > ---------

-
[b08b4cb](b08b4cbd5e)
*(terminal)* Add disclaimer about panics to Terminal::new by
@lolbinarycat in [#2088](https://github.com/ratatui/ratatui/pull/2088)

  >
  > part of #2087
  >
  > cc @orhun
  >
  > ---------

-
[dafb716](dafb716f9d)
*(widgets)* Add example for grouped barchart by @orhun in
[#1566](https://github.com/ratatui/ratatui/pull/1566)
  >
  > related #1512
  >
  > ---------

-
[ed5dd73](ed5dd73084)
*(widgets)* Add example for tabs by @orhun in
[#1559](https://github.com/ratatui/ratatui/pull/1559)
  >
  > related #1512
  >
> Also removes the tabs example from ratatui crate since it overlaps
with
> this new example in terms of functionality and it was not following
the
  > general theme of other examples.

-
[fab5321](fab532171d)
*(widgets)* Add example for scrollbar by @orhun in
[#1545](https://github.com/ratatui/ratatui/pull/1545)

  > Related to: #1512

-
[898aef6](898aef6e2f)
*(widgets)* Add example for list by @orhun in
[#1542](https://github.com/ratatui/ratatui/pull/1542)

  > Related to: #1512

-
[452366a](452366aa9e)
*(widgets)* Add example for sparkline by @orhun in
[#1556](https://github.com/ratatui/ratatui/pull/1556)
  >
  > related #1512
  >
> Also removes the sparkline example from ratatui crate since this
example
  > is a simplified and easier to understand version of that

-
[6ddde0e](6ddde0e8a8)
*(widgets)* Add example for table by @orhun in
[#1557](https://github.com/ratatui/ratatui/pull/1557)
  >
  > related #1512

-
[93ad6b8](93ad6b828c)
*(widgets)* Update values in chart example by @orhun in
[#1558](https://github.com/ratatui/ratatui/pull/1558)

  > better stonks

-
[15f442a](15f442a71e)
*(widgets)* Add example for paragraph by @orhun in
[#1544](https://github.com/ratatui/ratatui/pull/1544)
  >
  > related #1512
  >
> Also removes the paragraph example from `ratatui` since these examples
  > are more or less the same.

-
[17bba14](17bba14540)
*(widgets)* Move the logo example to widgets by @orhun in
[#1543](https://github.com/ratatui/ratatui/pull/1543)
  >
  > related #1512
  >
  > Also updates the code to make it consistent with the other examples

-
[f2451e7](f2451e7f1e)
*(widgets)* Add example for gauge by @orhun in
[#1539](https://github.com/ratatui/ratatui/pull/1539)
  >
  > related #1512

-
[4f0a8b2](4f0a8b21af)
*(widgets)* Add example for canvas by @orhun in
[#1533](https://github.com/ratatui/ratatui/pull/1533)
  >
  > related #1512

-
[91147c4](91147c4d75)
*(widgets)* Add example for chart by @orhun in
[#1536](https://github.com/ratatui/ratatui/pull/1536)

  > stonks

-
[6dd25a3](6dd25a3111)
*(widgets)* Add example for calendar by @orhun in
[#1532](https://github.com/ratatui/ratatui/pull/1532)
  >
  > related #1512

-
[99ac005](99ac005b06)
*(widgets)* Add simple barchart example by @joshka in
[#1511](https://github.com/ratatui/ratatui/pull/1511)

-
[b1d47e7](b1d47e7718)
*(uncategorized)* Discourage use of `Buffer`'s `pos_of`, `index_of` by
@pharrison31415 in [#2225](https://github.com/ratatui/ratatui/pull/2225)

> These methods assume that the backing store of any buffer / area is
linearly indexable. There are other ways that we might want to
experiment in the future with how to store the values (trees, 2D
allocated areas that are non-contiguous etc.). The index <-> pos
conversion there isn't particularly useful. This should be an internal
implementation detail of the buffer, rather than something that we
expose, but we're not deprecating this for now at least.

-
[f8b0594](f8b0594363)
*(uncategorized)* Fix: fix typos by @j-g00da in
[#2129](https://github.com/ratatui/ratatui/pull/2129)

  > This fixes the pipeline after bumping typos.

-
[9998000](9998000e36)
*(uncategorized)* Use shields.io badge by @LitoMore in
[#2040](https://github.com/ratatui/ratatui/pull/2040)

  > Related to:
  > - https://github.com/simple-icons/simple-icons/pull/13593
  > - https://github.com/ratatui/ratatui/pull/1967
  >
  > The Ratatui icon is available on shields.io now ✌️
  >
  > And it's customizable. There are more configurations at
  > https://shields.io/badges.
  >
  > Here are some examples:
  >
  > ```markdown
  > ![](https://img.shields.io/badge

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2025-12-24 00:18:58 +03:00
Orhun Parmaksız
04e86bbfa9 chore: revert the 0.30-beta.1 update to re-trigger release-plz (#2291) 2025-12-24 00:14:55 +03:00
Orhun Parmaksız
06a30ccc72 chore(widgets): disable scrape-examples and revert ratatui dev dep (#2290)
potentially fixes #2289
2025-12-23 22:42:01 +03:00
github-actions[bot]
3936b106dc chore: release 0.30.0-beta.1 (#2287)
## 🤖 New release

* `ratatui-core`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui-crossterm`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui-widgets`: 0.3.0-beta.0 -> 0.3.0-beta.1
* `ratatui-macros`: 0.7.0-beta.0 -> 0.7.0-beta.1
* `ratatui-termwiz`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui-termion`: 0.1.0-beta.0 -> 0.1.0-beta.1
* `ratatui`: 0.30.0-beta.0 -> 0.30.0-beta.1

<details><summary><i><b>Changelog</b></i></summary><p>

## `ratatui-core`

<blockquote>

##
[v0.30.0-beta.0](https://github.com/ratatui/ratatui/releases/tag/v0.30.0-beta.0)
- 2025-10-28

> _"Rats don't just survive; they discover; they create. ... I mean,
just look at what they do with
the terminal!" – Remy & Orhun_

We are excited to announce the biggest release of `ratatui` so far - a
Rust library that's all about cooking up TUIs 👨‍🍳🐀

📢 Please note that this is a beta release, and we encourage you to try
it out and provide feedback!

 **WIP Release highlights**:
<https://ratatui-0-30.ratatui.pages.dev/highlights/v030/>

⚠️ List of breaking changes can be found
[here](https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md).

### Features

-
[56d5e05](56d5e05762)
_(bar)_ Update label and text_value to accept Into<> by @Emivvvvv in
[#1471](https://github.com/ratatui/ratatui/pull/1471) [**breaking**]

> BREAKING CHANGE:label and text_value now accept `Into<>` types, which
  > breaks type inference.
  >
  > ```diff
  > - Bar::default().label("foo".into());
  > + Bar::default().label("foo");
  > ```
  >
  > ```diff
  > - Bar::default().text_value("bar".into());
  > + Bar::default().text_value("bar");
  > ```

-
[b76ad3b](b76ad3b02e)
_(bar)_ Impl Styled for Bar by @Emivvvvv in
[#1476](https://github.com/ratatui/ratatui/pull/1476)

  > Related:https://github.com/ratatui/ratatui/issues/683

-
[e15fefa](e15fefa922)
_(barchar)_ Add BarChart::grouped constructor by @joshka in
[#1513](https://github.com/ratatui/ratatui/pull/1513)

> Add a new constructor to the `BarChart` widget that allows creating a
  > grouped barchart with multiple groups of bars.
  >
> Also add a new constructor to the `BarGroup` widget that allows
creating
  > a group of bars with a label.

-
[369b18e](369b18eef2)
_(barchart)_ Reduce barchart creation verbosity by @Emivvvvv in
[#1453](https://github.com/ratatui/ratatui/pull/1453)

  > Adds constructor methods for BarChart, BarGroup, and Bar

-
[2d713d7](2d713d723d)
_(crossterm)_ Allow multiple crossterm versions by @joshka in
[#1841](https://github.com/ratatui/ratatui/pull/1841)

  > This commit introduces feature flags to make it possible for widget
  > library authors to depend on a specific version of crossterm without
> causing version conflicts. This should make it easier for libraries
and
  > apps to update crossterm versions more easily.
  >
> The available feature flags are `crossterm_0_28` and `crossterm_0_29`.
> By default, the latest version is enabled. If a multiple features are
  > enabled we choose the latest version. We will in general support at
  > least the last two major (0.x) versions of crossterm, and will only
  > remove versions in a major version bump.

-
[d99984f](d99984f1e9)
_(layout)_ Add `Flex::SpaceEvenly` by @kdheepak in
[#1952](https://github.com/ratatui/ratatui/pull/1952) [**breaking**]

  > Resolves https://github.com/ratatui/ratatui/issues/1951
  >
> BREAKING CHANGE:Old `Flex::SpaceAround` behavior is available by using
  >
  > `Flex::SpaceEvenly` and new
  >
  > `Flex::SpaceAround` now distributes space evenly around each element
  > except the middle spacers
  > are twice the size of first and last elements
  >
  > With this change, the following variants of `Flex` are supported:
  >
> - `Flex::Start`: Aligns items to the start; excess space appears at
the
  >   end.
  > - `Flex::End`: Aligns items to the end; excess space appears at the
  >   start.
  > - `Flex::Center`: Centers items with equal space on both sides.
> - `Flex::SpaceAround` (**new**): Distributes space _around_ items;
space
  >   between items is _twice_ the edge spacing.
> - `Flex::SpaceBetween`: Distributes space _evenly between_ items
except
  >   no space at the edges.
> - `Flex::SpaceEvenly` (**previously `Flex::SpaceAround`**):
Distributes
  >   space _evenly between_ items and edges.
> - `Flex::Legacy`: Preserves legacy behavior, placing all excess space
at
  >   the end.
  >
  > This aligns behavior of `Flex` with CSS flexbox more closely.
  >
  > The following is a screenshot in action:
  >
  > <img width="1090" alt="image"
  >
>
src="https://github.com/user-attachments/assets/2c7cd797-27bd-4242-a824-4565d369227b"
  > />
  >
  > ***

-
[9275d34](9275d3421c)
_(layout)_ Add Offset::new() constructor by @joshka in
[#1547](https://github.com/ratatui/ratatui/pull/1547)

-
[7ad9c29](7ad9c29eac)
_(linegauge)_ Customized symbols by @sectore in
[#1601](https://github.com/ratatui/ratatui/pull/1601)

  > With this PR any symbol (`&str`) can be used to render `filled` and
  > `unfilled` parts of `LineGauge` now. Before that change, only
>
[`symbols::line::Set`](https://docs.rs/ratatui/latest/ratatui/symbols/line/struct.Set.html)
  > was accepted.
  >
  > Note:New methods are introduced to define those symbols:
  > `filled_symbol` and `unfilled_symbol`. The method
>
[`line_set`](https://docs.rs/ratatui/latest/ratatui/widgets/struct.LineGauge.html#method.line_set)
  > is still there, but marked as `deprecated`.
  >
>
![line_gauge](https://github.com/user-attachments/assets/cae308b8-151b-461d-8af6-9a20012adf2f)

-
[92a19cb](92a19cb604)
_(list)_ Highlight symbol styling by @airblast-dev in
[#1595](https://github.com/ratatui/ratatui/pull/1595) [**breaking**]

  > Allow styling for `List`'s highlight symbol
  >
  > This change makes it so anything that implements `Into<Line>` can be
  > used as a highlight symbol.
  >
> BREAKING CHANGE:`List::highlight_symbol` can no longer be used in
const
  > context
  >
  > BREAKING CHANGE:`List::highlight_symbol` accepted `&str`. Conversion
  > methods that rely on type inference will need to be rewritten as the
  > compiler cannot infer the type.
  >
  > closes:https://github.com/ratatui/ratatui/issues/1443
  >
  > ***

-
[e89a526](e89a526aab)
_(no_std)_ Portable-atomic integration for targets with no atomic types
by @j-g00da in [#2076](https://github.com/ratatui/ratatui/pull/2076)

  > Improves compatibility with no-std targets that don't support atomic
  > types.
  >
  > We support three different scenarios depending on the target:
  >
  > 1. Terminal applications and other std targets (e.g. espidf):
  >
  > - `std` enabled, `portable-atomic` disabled
  >
  > 2. Embedded targets with atomic types, bare metal x86, etc.:
  >
  > - `std` disabled `portable-atomic` disabled
  >
  > 3. Embedded targets without atomic types (e.g. single-core MCUs):
  >
  > - `std` disabled, `portable-atomic` enabled
  >
> Turning on `portable-atomic` together with `std` will fall back to
`std`
  > atomic.

-
[1399d95](1399d95ae0)
_(no_std)_ Make palette and serde features depends on std by @j-g00da in
[#1919](https://github.com/ratatui/ratatui/pull/1919)

-
[b32f781](b32f78195b)
_(no_std)_ Make `ratatui-macros` no-std by @j-g00da in
[#1865](https://github.com/ratatui/ratatui/pull/1865)

-
[3e1c72f](3e1c72fb27)
_(no_std)_ Make ratatui compatible with `#![no_std]` by @j-g00da in
[#1794](https://github.com/ratatui/ratatui/pull/1794) [**breaking**]

  > Resolves #1781
  >
  > This PR makes it possible to compile ratatui with `#![no_std]`.
  > Also makes me answer "We Are So Embedded" to "Are We Embedded Yet?"

-
[ab48c06](ab48c06171)
_(no_std)_ Option to disable layout cache for `no_std` compatibility by
@j-g00da in [#1795](https://github.com/ratatui/ratatui/pull/1795)
[**breaking**]

  > Resolves #1780
  >
  > BREAKING CHANGE:Disabling `default-features` will now disable layout
  > cache, which can have a negative impact on performance.
  >
  > `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only
  > available if `layout-cache` feature is enabled.

-
[09173d1](09173d1829)
_(no_std)_ Make `TestBackend::Error` `Infallible` by @j-g00da in
[#1823](https://github.com/ratatui/ratatui/pull/1823) [**breaking**]

> BREAKING CHANGE:`TestBackend` now uses `core::convert::Infallible` for
  > error handling instead of `std::io::Error`

-
[007713e](007713e50a)
_(no_std)_ Replace `Backend`'s `io::Error` usages with associated
`Error` type by @j-g00da in
[#1778](https://github.com/ratatui/ratatui/pull/1778) [**breaking**]

  > Resolves #1775
  >
> BREAKING CHANGE:Custom backends now have to implement `Backend::Error`
> and `Backend::clear_region`. Additionally some generic `Backend` usage
  > will have to explicitly set trait bounds for `Backend::Error`.

-
[a42a17e](a42a17e184)
_(no_std)_ Make `ratatui-widgets` `no_std` by @j-g00da in
[#1779](https://github.com/ratatui/ratatui/pull/1779)

  > Resolves #1776

-
[5a232a3](5a232a3115)
_(no_std)_ Remove redundant `std` usages in `ratatui-widgets` by
@j-g00da in [#1762](https://github.com/ratatui/ratatui/pull/1762)

-
[ebe10cd](ebe10cd81f)
_(no_std)_ Remove redundant `std` usages in `ratatui-core` by @j-g00da
in [#1753](https://github.com/ratatui/ratatui/pull/1753)

  > Resolves https://github.com/ratatui/ratatui/issues/1751

-
[08b08cc](08b08cc45b)
_(rect)_ Centering by @janTatesa in
[#1814](https://github.com/ratatui/ratatui/pull/1814)

  > Resolves #617

-
[ff729b7](ff729b7607)
_(scrollbar)_ Support retrieving the current position of state by @orhun
in [#1552](https://github.com/ratatui/ratatui/pull/1552)

> As of now it is possible to change the position of the Scrollbar but
not
  > possible to retrieve the position for further use. e.g.
  >
  > ```rust
  > let mut state = ScrollbarState::default();
  > state.next();
  > ```
  >
> This commit adds a new method "`current_position`" (since `position`
is
  > already taken by the fluent setter) for that purpose:
  >
  > ```rust
  > let index = state.get_position(); // yay
  > ```
  >
  > See #1545 for the concrete usage of this.

-
[b9da192](b9da1926a0)
_(serde)_ Derive Serialize/Deserialize for alignment enums by @j-g00da
in [#1957](https://github.com/ratatui/ratatui/pull/1957)

  > Resolves #1954

-
[89b7421](89b74214d9)
_(serde)_ Derive Serialize/Deserialize for additional structs/enums by
@aurreland in [#1883](https://github.com/ratatui/ratatui/pull/1883)

  > This PR adds `#[derive(Serialize, Deserialize)]` to the following
  > structs:
  >
  > - `Constraint`
  > - `Direction`
  > - `Spacing`
  > - `Layout`
  > - `AccentedPalette`
  > - `NonAccentedPalette`
  > - `Palette`
  > - `Padding`
  > - `Borders`
  > - `BorderType`
  > - `ListDirection`
  > - `ScrollbarOrientation`
  > - `ScrollDirection`
  > - `RenderDirection`
  > - `HighlightSpacing`
  >
  > Fixes #1877

-
[03f3f6d](03f3f6df35)
_(style)_ Allow add/sub modifiers to be omitted in Style serialization.
by @rcorre in [#2057](https://github.com/ratatui/ratatui/pull/2057)

  > It's really useful that Style supports Deserialize, this allows TUI
  > apps to have configurable theming without much extra code.
  >
  > However, deserializing a style currently fails if `add_modifier` and
  > `sub_modifier` are
  > not specified. That means the following TOML config:
  >
  > ```toml
  > [theme.highlight]
  > fg = "white"
  > bg = "black"
  > ```
  >
> Will fail to deserialize with "missing field `add_modifier`". It
should
  > be possible
  > to omit modifiers and have them default to "none".

-
[985cd05](985cd05573)
_(symbols)_ Add dashed borders by @theotchlx in
[#1573](https://github.com/ratatui/ratatui/pull/1573)

  > Adds several new border sets:
  >
  > - ratatui::symbols::border::LIGHT_DOUBLE_DASHED
  > - ratatui::symbols::border::HEAVY_DOUBLE_DASHED
  > - ratatui::symbols::border::LIGHT_TRIPLE_DASHED
  > - ratatui::symbols::border::HEAVY_TRIPLE_DASHED
  > - ratatui::symbols::border::LIGHT_QUADRUPLE_DASHED
  > - ratatui::symbols::border::HEAVY_QUADRUPLE_DASHED
  >
  > And corresponding variants to the ratatui::widgets::BorderType enum
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1355

-
[4c301e8](4c301e891d)
_(text)_ Implement `AddAssign` for `Text` by @acuteenvy in
[#1956](https://github.com/ratatui/ratatui/pull/1956)

> This makes it possible to add a second `Text` instance to a first one
using the += operator.
  >
  > ```rust
  > let mut text = Text::from("line 1");
  > text += Text::from("line 2");
  > ```
  >
> Style and alignment applied to the second text is ignored (though
styles and alignment of lines and spans are copied).

-
[ce4856a](ce4856a65f)
_(widgets)_ Add the missing constructor to canvas types by @orhun in
[#1538](https://github.com/ratatui/ratatui/pull/1538)

> Allows constructing `Rectangle`, `Points` and `Circle` using the `new`
  > method instead of initializing with the public fields directly.

-
[75b78be](75b78be09f)
_(uncategorized)_ Add width() impl for tabs by @joshka in
[#2049](https://github.com/ratatui/ratatui/pull/2049)

> The purpose of this is to make it easy for apps to easily calculate
the
  > total tab width including all dividers and padding.

-
[8188ed3](8188ed3950)
_(uncategorized)_ Implement UnicodeWidthStr for Text/Line/Span by
@joshka in [#2030](https://github.com/ratatui/ratatui/pull/2030)

  > You can now calculate the width of any Text/Line/Span using the
> UnicodeWidthStr trait instead of the width method on the type. This
also
  > makes it possible to use the width_cjk() method if needed.

-
[c845fec](c845fec765)
_(uncategorized)_ Add conversion from Size to Rect by @joshka in
[#2028](https://github.com/ratatui/ratatui/pull/2028)

  > `Rect::from(size)` returns a new Rect at the origin (0, 0) with the
  > specified `Size`

-
[017af11](017af11b2b)
_(uncategorized)_ Preserve block titles when merging borders by @j-g00da
in [#1977](https://github.com/ratatui/ratatui/pull/1977)

  > Resolves #1939

-
[6dcd53b](6dcd53bc6b)
_(uncategorized)_ Add ergonomic methods for layouting Rects by @joshka
in [#1909](https://github.com/ratatui/ratatui/pull/1909)

> This commit introduces new methods for the `Rect` struct that simplify
> the process of splitting a `Rect` into sub-rects according to a given
> `Layout`. By putting these methods on the `Rect` struct, we make it a
> bit more natural that a layout is applied to the `Rect` itself, rather
  > than passing a `Rect` to the `Layout` struct to be split.
  >
> Adds:- `Rect::layout` and `Rect::try_layout` methods that allow
splitting a
  > `Rect` into an array of sub-rects according to a given `Layout`.
  >
  > - `Rect::layout_vec` method that returns a `Vec` of sub-rects.
> - `Layout::try_areas` method that returns an array of sub-rects, with
  >   compile-time checks for the number of constraints. This is added
  >   mainly for consistency with the new `Rect` methods.
  >
  > ```rust
  > use ratatui_core::layout::{Layout, Constraint, Rect};
  > let area = Rect::new(0, 0, 10, 10);
  > let layout = Layout::vertical([Constraint::Fill(1); 2]);
  >
  > // Rect::layout() infers the number of constraints at compile time:
  > let [top, main] = area.layout(&layout);
  >
> // Rect::try_layout() and Layout::try_areas() do the same, but return
a
  > // Result:
  > let [top, main] = area.try_layout(&layout)?;
  > let [top, main] = layout.try_areas(area)?;
  >
  > // Rect::layout_vec() returns a Vec of sub-rects:
  > let areas_vec = area.layout_vec(&layout);
  >
  > // you can also explicitly specify the number of constraints:
  > let areas = area.layout::<2>(&layout);
  > let areas = area.try_layout::<2>(&layout)?;
  > let areas = layout.try_areas::<2>(area)?;
  > ```

-
[0c3872f](0c3872f1c5)
_(uncategorized)_ Add Rect::outer() by @joshka in
[#1929](https://github.com/ratatui/ratatui/pull/1929)

  > Fixes:https://github.com/ratatui/ratatui/issues/211

-
[7bc78bc](7bc78bca1b)
_(uncategorized)_ Add ratatui::run() method by @joshka in
[#1707](https://github.com/ratatui/ratatui/pull/1707)

> This introduces a new `ratatui::run()` method which runs a closure
with
> a terminal initialized with reasonable defaults for most applications.
  > This calls `ratatui::init()` before running the closure and
> `ratatui::restore()` after the closure completes, and returns the
result
  > of the closure.
  >
  > A minimal hello world example using the new `ratatui::run()` method:
  >
  > ```rust
  > fn main() -> Result<(), Box<dyn std::error::Error>> {
  >     ratatui::run(|terminal| {
  >         loop {
> terminal.draw(|frame| frame.render_widget("Hello World!",
frame.area()))?;
  >             if crossterm::event::read()?.is_key_press() {
  >                 break Ok(());
  >             }
  >         }
  >     })
  > }
  > ```
  >
  > Of course, this also works both with apps that use free methods and
  > structs:
  >
  > ```rust
> fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
  >
  > ratatui::run(run)?;
  > ```
  >
  > ```rust
  > struct App { ... }
  >
  > impl App {
  >     fn new() -> Self { ... }
> fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(),
AppError> { ... }
  > }
  >
  > ratatui::run(|terminal| App::new().run(terminal))?;
  > ```

-
[b6fbfcd](b6fbfcdd1c)
_(uncategorized)_ Add lifetime to symbol sets by @joshka in
[#1935](https://github.com/ratatui/ratatui/pull/1935)

> This makes it possible to create symbol sets at runtime with
non-static
  > lifetimes.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1722

-
[488e5f0](488e5f020f)
_(uncategorized)_ Make `border!` work without importing `Borders` by
@j-g00da in [#1918](https://github.com/ratatui/ratatui/pull/1918)

> Currently using `border!` macro requires explicit import of `Borders`
  > which is unnecessary.

-
[671c2b4](671c2b4fd4)
_(uncategorized)_ Support merging the borders of blocks by @j-g00da

> When two borders overlap, they will automatically merge into a single,
  > clean border instead of overlapping.
  >
> This improves visual clarity and reduces rendering glitches around
corners.
  >
  > For example:
  >
  > ```
> assert_eq!(Cell::new("┘").merge_symbol("┏",
MergeStrategy::Exact).symbol(), "╆");
  > ```

-
[702fff5](702fff501c)
_(uncategorized)_ Implement stylize methods directly on Style by @joshka
in [#1572](https://github.com/ratatui/ratatui/pull/1572) [**breaking**]

> This makes it possible to create constants using the shorthand
methods.
  >
  > ```rust
  > const MY_STYLE: Style = Style::new().blue().on_black();
  > ```
  >
  > Rather than implementing Styled for Style and then adding extension
  > methods that implement the Stylize shorthands, this implements the
  > methods as const functions directly on Style.
  >
  > BREAKING CHANGE:`Style` no longer implements `Styled`. Any calls to
  > methods implemented by the blanket implementation of Stylize are now
> defined directly on Style. Remove the Stylize import if it is no
longer
  > used by your code.
  >
> The `reset()` method does not have a direct replacement, as it clashes
  > with the existing `reset()` method. Use `Style::reset()` rather than
  > `some_style.reset()`
  >
  > Fixes:#1158

-
[4fcd238](4fcd238e1e)
_(uncategorized)_ Support no-std for calendar widget by @joshka in
[#1852](https://github.com/ratatui/ratatui/pull/1852)

> Removes the CalendarEventStore::today() function in no-std
environments

-
[53cdbbc](53cdbbccd5)
_(uncategorized)_ Enable serde propagation to backend crates (crossterm,
termion) by @ArjunKrish7356 in
[#1812](https://github.com/ratatui/ratatui/pull/1812)

> This PR propagates the serde feature from the main ratatui crate to
the
  > ratatui-crossterm and ratatui-termion backend crates. Solves #1805

-
[6836a69](6836a6903e)
_(uncategorized)_ Implement styled for other primitives by @aschey in
[#1684](https://github.com/ratatui/ratatui/pull/1684)

-
[fcb47d6](fcb47d60f3)
_(uncategorized)_ Rename Alignment to HorizontalAlignment and add
VerticalAlignment by @joshka in
[#1735](https://github.com/ratatui/ratatui/pull/1735) [**breaking**]

> We don't anticipate removing or deprecating the type alias in the near
  > future, but it is recommended to update your imports to use the new
  > name.
  >
> Added a VerticalAlignment enum to make the API more consistent. We
don't
> have a specific use case for it yet, but it's better to add it now and
  > be able to use it in the future.
  >
  > BREAKING-CHANGE:The `Alignment` enum has been renamed to
> `HorizontalAlignment` to better reflect its purpose. A type alias has
> been added to maintain backwards compatibility, however there are some
  > cases where type aliases are not enough to maintain backwards
  > compatibility. E.g. when using glob imports to import all the enum
> variants. This should not affect most users, but it is recommended to
  > update your imports to use the new name.
  >
  > ```diff
  > - use ratatui::layout::Alignment;
  > + use ratatui::layout::HorizontalAlignment;
  >
  > - use Alignment::*;
  > + use HorizontalAlignment::*;
  > ```

-
[2714d6b](2714d6b9c3)
_(uncategorized)_ Add array and tuple RGB color conversion methods by
@joshka in [#1703](https://github.com/ratatui/ratatui/pull/1703)

> Other crates (e.g. colorgrad) that deal with colors can convert colors
> to a tuple of 3 or 4 u8 values. This commit adds conversion methods
from
  > these types to a `Color::Rgb` instance. Any alpha value is ignored.
  >
  > ```rust
  > Color::from([255, 0, 0]);
  > Color::from((255, 0, 0));
  > Color::from([255, 0, 0, 255]);
  > Color::from((255, 0, 0, 255));
  > ```

-
[50ba965](50ba96518f)
_(uncategorized)_ Add a new RatatuiMascot widget by @Its-Just-Nans in
[#1584](https://github.com/ratatui/ratatui/pull/1584)

  > Move the Mascot from Demo2 into a new widget.
  > Make the Rat grey and adjust the other colors.
  >
  > ```rust
  > frame.render_widget(RatatuiMascot::default(), frame.area());
  > ```

-
[1d28c89](1d28c89fe5)
_(uncategorized)_ Add conversions for anstyle by @joshka in
[#1581](https://github.com/ratatui/ratatui/pull/1581)
> https://crates.io/crates/anstyle makes it possible to define colors in
> an interoperable way. This makes it possible for applications to
easily
  > load colors from a variety of formats.
  >
> This is gated by the anstyle feature flag which is disabled by
default.
  >
  > ***

### Bug Fixes

-
[a89d3d6](a89d3d62ff)
_(buffer)_ Clear behavior with VS16 wide emojis by @nornagon in
[#2063](https://github.com/ratatui/ratatui/pull/2063)

  > This fixes a bug where certain emojis like ⌨️ would sometimes be
> "overlaid" onto existing content from the buffer, instead of properly
  > clearing.
  >
  > [example demonstrating
>
bug](https://gist.github.com/nornagon/11a79d7a1f2e98aa129fedb4abccc530)
  >
  > This PR was generated by Codex, and validated by me:
  >
> 1. Behavior of the above example code was buggy before this fix
(showed
  >    overlaying "b" on top of the keyboard emoji), and fixed after.
> 2. The U+FE0F check is not strictly required, but I did note that
emoji
> without this char don't exhibit the buggy behavior, even without the
  >    fix.
  >
  > ***

-
[ec30390](ec30390446)
_(canvas)_ Round coordinates to nearest grid cell by @joshka in
[#1507](https://github.com/ratatui/ratatui/pull/1507)

  > Previously the canvas coordinates were rounded towards zero, which
> causes the rendering to be off by one pixel in some cases. It also
meant
> that pixels at the extreme edges of the canvas can only be drawn if
the
  > point was exactly on the edge of the canvas. This commit rounds the
> coordinates to the nearest integer instead. This may change the output
  > for some apps using Canvas / Charts.

-
[afd1ce1](afd1ce179b)
_(canvas)_ Lines that start outside the visible grid are now drawn by
@renesat in [#1501](https://github.com/ratatui/ratatui/pull/1501)

> Previously lines with points that were outside the canvas bounds were
> not drawn at all. Now they are clipped to the bounds of the canvas so
  > that the portion of the line within the canvas is draw.
  >
> To facilitate this, a new `Painter::bounds()` method which returns the
  > bounds of the canvas is added.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1489

-
[2b0a044](2b0a044ced)
_(ci)_ Add contents write permission to release-plz PR by @marcoieni in
[#2119](https://github.com/ratatui/ratatui/pull/2119)

  > https://release-plz.dev/docs/github/quickstart#3-setup-the-workflow
  >
  > Fixes https://github.com/release-plz/release-plz/issues/2439

-
[18e70d3](18e70d3d51)
_(crossterm)_ Terminal should keep Bold when removing Dim by @MarSik in
[#1541](https://github.com/ratatui/ratatui/pull/1541)

  > The Dim removal should behave the same as the logic for Bold removal
> that sends NormalIntensity sequence and then restores Dim when needed.

-
[dca331c](dca331c748)
_(demo)_ Support tab key in demo2 example by @orhun in
[#1726](https://github.com/ratatui/ratatui/pull/1726)

  > see #1721
  >
> Not sure what caused this - it's been there for a while probably and
we
  > didn't realize it since we used `demo2-destroy` mostly.

-
[0fd4753](0fd4753e6b)
_(examples)_ Run the correct example for chart by @orhun in
[#1679](https://github.com/ratatui/ratatui/pull/1679)

  > fixes #1678

-
[39479e2](39479e298c)
_(examples)_ Ensure that example projects are not published by @orhun in
[#1672](https://github.com/ratatui/ratatui/pull/1672)

-
[9314312](93143126b3)
_(layout)_ Feature flag cache related types by @joshka in
[#1842](https://github.com/ratatui/ratatui/pull/1842)

-
[2dd1977](2dd1977c59)
_(layout-cache)_ Import `NonZeroUsize` only when `layout-cache` is
enabled by @j-g00da in
[#1839](https://github.com/ratatui/ratatui/pull/1839)

> This silences unused import warning, when `layout-cache` is disabled.

-
[564a9d7](564a9d76fc)
_(line-gauge)_ Pad default label to display 3 numbers by @martinetd in
[#2053](https://github.com/ratatui/ratatui/pull/2053)

> Display the default label of the LineGauge widget padded to fill 3
cells.
> This makes it so that the label doesn't shift around when going from a
  > single digit to double / triple digits.
  >
> To maintain the existing behavior, use a custom label by calling
`.label()`
  > on the LineGauge.

-
[a692a6e](a692a6e371)
_(lint)_ Apply rust 1.84 clippy suggestions by @joshka in
[#1612](https://github.com/ratatui/ratatui/pull/1612)

  > The canvas map constants are now statics instead.
  > Fixes
>
https://rust-lang.github.io/rust-clippy/master/index.html\#large_const_arrays

-
[2e54d5e](2e54d5e22c)
_(macros)_ Use $crate re-export in text macro by @airblast-dev in
[#1832](https://github.com/ratatui/ratatui/pull/1832)

-
[79d5165](79d5165cae)
_(no_std)_ Propagate `std` feature flag to dependencies by @j-g00da in
[#1838](https://github.com/ratatui/ratatui/pull/1838)

> Disables `std` feature flags in dependencies and only enables them
with
> `ratatui` and `ratatui-core`'s `std` feature flag. This partially
fixes the
> issue of still depending on `std`, when `std` feature flag is
disabled.

-
[00da8c6](00da8c6203)
_(no_std)_ Provide `f64` polyfills for `no_std` compatibility by
@j-g00da in [#1840](https://github.com/ratatui/ratatui/pull/1840)

  > Related:https://github.com/rust-lang/rust/issues/137578

-
[3b13240](3b13240728)
_(scrollbar)_ Check for area.is_empty() before rendering by @farmeroy in
[#1529](https://github.com/ratatui/ratatui/pull/1529)

> This adds the `area.is_empty()` back into the scrollbar render method.
  > Without it, the widget panics if the height is 0.

-
[f57b696](f57b696fdc)
_(span)_ Dont render control characters by @EdJoPaTo in
[#1312](https://github.com/ratatui/ratatui/pull/1312)

-
[2ce958e](2ce958e38c)
_(table)_ Allow display of additional table row, if row height > 1 by
@Lunderberg in [#1452](https://github.com/ratatui/ratatui/pull/1452)

-
[0a25bc1](0a25bc166d)
_(tests)_ Update the stderr snapshot for ratatui-macros by @orhun in
[#2161](https://github.com/ratatui/ratatui/pull/2161)

  > New 🦀 broke the CI

-
[5fa342c](5fa342cc52)
_(widgets)_ Fix centered block title truncation by @ognis1205 in
[#1973](https://github.com/ratatui/ratatui/pull/1973)

  > Previously block titles that were aligned center were
  > truncated poorly (aligned to the left, and the last
  > non-fitting title would be truncated on the left and right.
  > This now truncates the titles more obviously centered.

-
[1fe64de](1fe64de09a)
_(uncategorized)_ Include underline color in anstyle conversion by
@aschey in [#2004](https://github.com/ratatui/ratatui/pull/2004)

  > Underline color wasn't included in the style conversion logic.

-
[c1b8528](c1b8528b69)
_(uncategorized)_ Panic when rendering widgets on too small buffer by
@j-g00da in [#1996](https://github.com/ratatui/ratatui/pull/1996)

> Fixes panic on overflow on horizontal `Barchart` and `RatatuiMascot`
and adds proper tests to all widgets.
  >
  > ***

-
[08b21fa](08b21fa55c)
_(uncategorized)_ Fix panic when rendering a `Paragraph` out of bounds
by @jwodder in [#1670](https://github.com/ratatui/ratatui/pull/1670)

  > Fixes #1667.

-
[80bc818](80bc818723)
_(uncategorized)_ Fix truncation of left aligned block titles by @joshka
in [#1931](https://github.com/ratatui/ratatui/pull/1931)

> truncate the right side of left aligned titles rather than the left
side
> of right aligned titles. This is more obvious as the left side of text
  > often contains more important information. And we generally read
  > left to right.
  >
  > This change makes centered titles overwrite left aligned titles and
  > right aligned titles overwrite centered or left aligned titles.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/358

-
[21e3b59](21e3b598ce)
_(uncategorized)_ Fix handling of multi-byte chars in bar chart by
@joshka in [#1934](https://github.com/ratatui/ratatui/pull/1934)

  > The split_at method requires that the split point is at a valid utf8
  > character boundary.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1928

-
[e1e4004](e1e400406c)
_(uncategorized)_ Derive copy for list state by @janTatesa in
[#1921](https://github.com/ratatui/ratatui/pull/1921)

-
[12cb5a2](12cb5a28fe)
_(uncategorized)_ Allow canvas area to exceed u16::MAX by @Daksh14 in
[#1891](https://github.com/ratatui/ratatui/pull/1891)

> This allows Canvas grids where the width \* height exceeds u16::MAX by
  > converting values to usize earlier in several methods.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1449

-
[09cc9ef](09cc9ef57d)
_(uncategorized)_ Typo in changelog by @joshka in
[#1857](https://github.com/ratatui/ratatui/pull/1857)

-
[c238aca](c238aca83a)
_(uncategorized)_ `padding_right()` should set right padding instead of
left by @sxyazi in [#1837](https://github.com/ratatui/ratatui/pull/1837)

  > Fixes https://github.com/ratatui/ratatui/issues/1836

-
[c90ba97](c90ba9781e)
_(uncategorized)_ Avoid unnecessary imports in minimal build by @cgzones
in [#1787](https://github.com/ratatui/ratatui/pull/1787)

  > core::ops::Range is only used with the feature `scrolling-regions`.
  > Ensure a minimal `cargo check` reports no warnings.

-
[416ebdf](416ebdf8c8)
_(uncategorized)_ Correct clippy errors introduced by rust 1.86.0 update
by @j-g00da in [#1755](https://github.com/ratatui/ratatui/pull/1755)

  > New version of rust (1.86.0) caused CI to fail.

-
[4eac5b2](4eac5b2849)
_(uncategorized)_ Make deprecation notes more helpful by @joshka in
[#1702](https://github.com/ratatui/ratatui/pull/1702)

> AI coding assistants use the deprecation notes to automatically
suggest
> fixes. This commit updates the deprecation notes to push those tools
to
  > suggest the correct replacement methods and types.
  >
> Specifically, AI tools often suggest using `Buffer::get(x, y)`,
because
  > of their training data where this was prevalent. When fixing these
> deprecations, they often incorrectly suggest using `Buffer::get(x, y)`
  > instead of `Buffer[(x, y)]`.

-
[35a8642](35a86427ab)
_(uncategorized)_ `Rect::positions()` should be empty when width is 0
and height is nonzero by @jwodder in
[#1669](https://github.com/ratatui/ratatui/pull/1669)

  > Fixes #1666.

-
[f5fc819](f5fc8197ff)
_(uncategorized)_ Avoid extra line break on whitespace only lines when
wrapping paragraphs by @dotdash in
[#1636](https://github.com/ratatui/ratatui/pull/1636)

  > Currently whitespace only lines produces an extra line break when
  > trimming is disabled, because both the trimmed as well as the
  > non-trimmed line get inserted. Fix this by only inserting the
  > non-trimmed one.

-
[2892bdd](2892bddce6)
_(uncategorized)_ Rust 1.83 clippy lints by @joshka in
[#1527](https://github.com/ratatui/ratatui/pull/1527)

>
https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes

-
[36e2d1b](36e2d1bda1)
_(uncategorized)_ Add feature(doc_cfg) when generating docs by @joshka
in [#1506](https://github.com/ratatui/ratatui/pull/1506)

-
[4d7704f](4d7704fba5)
_(uncategorized)_ Make StatefulWidget and Ref work with unsized State by
@thscharler in [#1505](https://github.com/ratatui/ratatui/pull/1505)

  > StatefulWidget::State and StatefulWidgetRef::State are now ?Sized.
  >
> This allows implementations of the traits to use unsized types for the
  > State associated type. This is turn is useful when doing things like
  > boxing different stateful widget types with State which implements
  > `Any`, are slices or any other dynamically sized type.

-
[7b87509](7b875091e1)
_(uncategorized)_ Typo by @marcoieni in
[#1480](https://github.com/ratatui/ratatui/pull/1480)

### Refactor

-
[8d60e96](8d60e96b2b)
_(examples)_ Use crossterm event methods by @joshka in
[#1792](https://github.com/ratatui/ratatui/pull/1792)

> Crossterm 0.29 introduced methods to easily check / extract the event
  > type. E.g. as_key_press_event() and is_key_press(). This commit
  > updates the examples to use these methods instead of matching on
  > the event type. This makes the code cleaner and easier to read.
  >
> Also does a general cleanup of the event handling code in the
examples.

-
[07bec55](07bec55b7d)
_(no_std)_ Make usages of std explicit in ratatui-core. by @ed-2100 in
[#1782](https://github.com/ratatui/ratatui/pull/1782)

  > ### This commit does the following:
  >
  > - Adds `#[no_std]` to `lib.rs`.
  > - Adds `extern crate std;` to `lib.rs`.
> - Updates `ratatui-core` to explicitly `use` items from std and alloc.
  > - Prefers `use`-ing alloc over std when possible.
  >
  > ### Explanation:
  >
> This allows usages of `std` in `ratatui-core` to be clearly pointed
out
  > and dealt with individually.
  >
  > Eventually, when `std` is to be feature gated, the associated commit
  > will be much cleaner.

-
[f132fa1](f132fa1715)
_(table)_ Small readability improvements by @joshka in
[#1510](https://github.com/ratatui/ratatui/pull/1510)

-
[02e53de](02e53de0f8)
_(uncategorized)_ Make use of iter::repeat_n() by @cgzones in
[#1788](https://github.com/ratatui/ratatui/pull/1788)

  > Applied via clippy --fix.
  > Available since 1.82.0.

-
[a195d59](a195d59a47)
_(uncategorized)_ Move xtask commands to small modules by @joshka in
[#1620](https://github.com/ratatui/ratatui/pull/1620)

-
[904b0aa](904b0aa723)
_(uncategorized)_ Move symbols to modules by @joshka in
[#1594](https://github.com/ratatui/ratatui/pull/1594)

-
[7c8573f](7c8573f575)
_(uncategorized)_ Rearrange selection_spacing code by @raylu in
[#1540](https://github.com/ratatui/ratatui/pull/1540)

-
[217c57c](217c57cd60)
_(uncategorized)_ Modularize backends by @orhun in
[#1508](https://github.com/ratatui/ratatui/pull/1508)

> Backend code is now moved to `ratatui-crossterm`, `ratatui-termion`
and
> `ratatui-termwiz`. This should be backwards compatible with existing
code.

-
[e461b72](e461b724a6)
_(uncategorized)_ Move {Stateful,}Widget{,Ref} types into individual
files by @joshka in
[#1479](https://github.com/ratatui/ratatui/pull/1479)

> This is a preparatory refactoring for modularization. No user visible
  > changes.

### Documentation

-
[40e96a2](40e96a2a04)
_(block)_ Add collapsed border example by @joshka in
[#1899](https://github.com/ratatui/ratatui/pull/1899)

-
[d291042](d291042e69)
_(block)_ Revise the block example by @orhun in
[#1520](https://github.com/ratatui/ratatui/pull/1520)

  > - Moves the block example from `ratatui` to `ratatui-widgets`
  > - Simplifies the example (bordered, styled, custom borders)
  >
  > see #1512

-
[0951da5](0951da52f9)
_(breaking-changes)_ Improve migration guide for `Backend::Error` by
@j-g00da in [#1908](https://github.com/ratatui/ratatui/pull/1908)

  > Related:https://github.com/fujiapple852/trippy/pull/1588

-
[bbe1cf9](bbe1cf9497)
_(breaking-changes)_ Change MSRV to 1.85 by @j-g00da in
[#1896](https://github.com/ratatui/ratatui/pull/1896)

> The minimum supported Rust version is now for `ratatui` v0.30 is 1.85

-
[c7912f3](c7912f3990)
_(breaking-changes)_ Fix header level by @j-g00da in
[#1825](https://github.com/ratatui/ratatui/pull/1825)

-
[eb24938](eb249382c9)
_(changelog)_ Add note to ratatui-macros' changelog

-
[fcde9cb](fcde9cb9c3)
_(changelog)_ Fix typo by @orhun in
[#1463](https://github.com/ratatui/ratatui/pull/1463)

-
[73488ab](73488abb45)
_(contributing)_ Fix link to `widgets_block_renders` test by @ognis1205
in [#2101](https://github.com/ratatui/ratatui/pull/2101)

  > The `CONTRIBUTING.md` referenced `tests/widgets_block.rs`, but the
> correct path is `ratatui/tests/widgets_block.rs`. Updated the link so
  > that readers can navigate to the test example without 404 error.
  >
  > ***

-
[0b025db](0b025db72b)
_(contributing)_ Fix grammar by @j-g00da in
[#1958](https://github.com/ratatui/ratatui/pull/1958)

-
[1197b2a](1197b2a02c)
_(contributing)_ Add note about using nightly for formatting by @joshka
in [#1816](https://github.com/ratatui/ratatui/pull/1816)

-
[3ae6bf1](3ae6bf1d6f)
_(contributing)_ Use cargo-xtask for instructions by @orhun in
[#1509](https://github.com/ratatui/ratatui/pull/1509)

  > - Updates `CONTRIBUTING.md` about the usage of `xtask`
  > - Removes `Makefile.toml`

-
[22e3e84](22e3e84de8)
_(core)_ Remove link to Paragraph widget by @orhun in
[#1683](https://github.com/ratatui/ratatui/pull/1683)

-
[200b217](200b217722)
_(examples)_ Add VHS tapes and docs for widget examples by @orhun in
[#2114](https://github.com/ratatui/ratatui/pull/2114)

  > fixes #1982
  >
> Later on I'll figure out an easy way to regenerate this in the CI and
  > possibly do the same for the app examples' VHS tapes. That's why I
  > haven't added a script or mentioned anything in the docs yet (hint:
  > #1721)
  >
  > ***

-
[861fbdf](861fbdf5cf)
_(examples)_ Fix a typo by @j-g00da in
[#1890](https://github.com/ratatui/ratatui/pull/1890)

  > Makes CI typos check pass again

-
[882cc3c](882cc3c6c6)
_(examples)_ Update app examples with tapes by @orhun in
[#1673](https://github.com/ratatui/ratatui/pull/1673)

-
[4393fae](4393fae54c)
_(examples)_ Move scrollbar example to examples folder by @orhun in
[#1665](https://github.com/ratatui/ratatui/pull/1665)

-
[9ea70e2](9ea70e28c6)
_(examples)_ Move widget-impl example to examples folder by @orhun in
[#1663](https://github.com/ratatui/ratatui/pull/1663)

-
[774ab78](774ab788d4)
_(examples)_ Move widget-ref-container example to examples folder by
@orhun in [#1664](https://github.com/ratatui/ratatui/pull/1664)

  > see #1512

-
[910d16e](910d16e63a)
_(examples)_ Move user-input example to examples folder by @orhun in
[#1659](https://github.com/ratatui/ratatui/pull/1659)

-
[dbfb7da](dbfb7da9e3)
_(examples)_ Move table example to examples folder by @orhun in
[#1657](https://github.com/ratatui/ratatui/pull/1657)

-
[cb2a58a](cb2a58aaa0)
_(examples)_ Move tracing example to examples folder by @orhun in
[#1658](https://github.com/ratatui/ratatui/pull/1658)

-
[7e00b64](7e00b646fc)
_(examples)_ Move panic example to examples folder by @orhun in
[#1655](https://github.com/ratatui/ratatui/pull/1655)

-
[8127590](8127590812)
_(examples)_ Move modifiers example to examples folder by @orhun in
[#1654](https://github.com/ratatui/ratatui/pull/1654)

-
[7c40c0b](7c40c0bbdd)
_(examples)_ Move popup example to examples folder by @orhun in
[#1656](https://github.com/ratatui/ratatui/pull/1656)

  > see #1512

-
[d87354f](d87354f400)
_(examples)_ Move list example to examples folder by @orhun in
[#1653](https://github.com/ratatui/ratatui/pull/1653)

  > see #1512
  >
  > also renames it to todo-list

-
[621226f](621226f2e2)
_(examples)_ Move inline example to examples folder by @orhun in
[#1651](https://github.com/ratatui/ratatui/pull/1651)

-
[9ba7d25](9ba7d25b71)
_(examples)_ Move hyperlink example to examples folder by @orhun in
[#1650](https://github.com/ratatui/ratatui/pull/1650)

-
[bb94d1c](bb94d1c0fa)
_(examples)_ Move minimal example to examples folder by @orhun in
[#1649](https://github.com/ratatui/ratatui/pull/1649)

-
[9f399ac](9f399ac7a6)
_(examples)_ Move gauge example to examples folder by @orhun in
[#1646](https://github.com/ratatui/ratatui/pull/1646)

-
[104d6a6](104d6a6c2b)
_(examples)_ Move custom-widget example to examples folder by @orhun in
[#1644](https://github.com/ratatui/ratatui/pull/1644)

-
[fa8ca01](fa8ca0121a)
_(examples)_ Move flex example to examples folder by @orhun in
[#1642](https://github.com/ratatui/ratatui/pull/1642)

-
[f5fde0e](f5fde0ef53)
_(examples)_ Move constraints example to examples folder by @orhun in
[#1641](https://github.com/ratatui/ratatui/pull/1641)

-
[fc70288](fc70288954)
_(examples)_ Move constraint-explorer example to examples folder by
@orhun in [#1640](https://github.com/ratatui/ratatui/pull/1640)

-
[325f961](325f96102a)
_(examples)_ Move hello-world example to examples folder by @orhun in
[#1647](https://github.com/ratatui/ratatui/pull/1647)

-
[867c4bc](867c4bc4e9)
_(examples)_ Move colors-rgb example to examples folder by @joshka in
[#1582](https://github.com/ratatui/ratatui/pull/1582)

  > - **docs: move colors-rgb example to examples folder**
  > - **docs: update main examples README**
  >
  > ***

-
[72334ed](72334ed61c)
_(layout)_ Update documentation to point to `kasuari` solver by @a-kenji
in [#2003](https://github.com/ratatui/ratatui/pull/2003)

-
[2be9ccb](2be9ccb120)
_(layout)_ Remove unnecessary path prefix by @j-g00da in
[#1766](https://github.com/ratatui/ratatui/pull/1766)

-
[b669ceb](b669cebcaf)
_(layout)_ Change `cassowary` to `kasuari` crate reference by @j-g00da
in [#1765](https://github.com/ratatui/ratatui/pull/1765)

-
[f907c74](f907c74bb3)
_(license)_ Update copyright years by @LVivona in
[#1639](https://github.com/ratatui/ratatui/pull/1639)

  > Update MIT Licence to copyright year 2025

-
[68b9f67](68b9f67f59)
_(readme)_ Add `Built with Ratatui` badge for downstream projects by
@harilvfs in [#1905](https://github.com/ratatui/ratatui/pull/1905)

-
[088aac1](088aac136d)
_(readme)_ Tweak links and badges by @joshka in
[#1598](https://github.com/ratatui/ratatui/pull/1598)

-
[6e43672](6e436725e4)
_(readme)_ Reimagine README.md by @orhun in
[#1569](https://github.com/ratatui/ratatui/pull/1569)

> This is the result of the re-imagination of a more suitable README.md.
It
  > is simpler and shorter: not giving more information to the user than
  > they actually need.
  >
> Also updates the quickstart code with the up-to-date version and adds
  > link to templates which was missing.
  >
  > ***

-
[8f28247](8f282473b2)
_(readme)_ Correct examples links by @HoKim98 in
[#1484](https://github.com/ratatui/ratatui/pull/1484)

-
[9f90f74](9f90f7495f)
_(readme)_ Fix broken link by @nilsmartel in
[#1485](https://github.com/ratatui/ratatui/pull/1485)

-
[260af68](260af68a34)
_(readme)_ Include iocraft as an alternative by @kdheepak in
[#1483](https://github.com/ratatui/ratatui/pull/1483)

-
[8e5151f](8e5151f83d)
_(rect)_ Fix typo in the Rect::outer function comments by @orhun in
[#2123](https://github.com/ratatui/ratatui/pull/2123)

-
[40f13c6](40f13c6a6c)
_(rect)_ Update the outdated comment for Rect::area() by @eqsdxr in
[#2100](https://github.com/ratatui/ratatui/pull/2100)

> The return value of Rect.area() is no longer of u16 type, and the
value
  > is not being clumped anymore.

-
[ce16692](ce16692b9a)
_(release)_ Fix typo by @j-g00da in
[#1754](https://github.com/ratatui/ratatui/pull/1754)

-
[9a930a6](9a930a6e99)
_(terminal)_ Made usage of Terminal::get_frame() clearer by @Blaeriz in
[#2071](https://github.com/ratatui/ratatui/pull/2071)

  > Closes : https://github.com/ratatui/ratatui/issues/1200
  >
  > ***

-
[b08b4cb](b08b4cbd5e)
_(terminal)_ Add disclaimer about panics to Terminal::new by
@lolbinarycat in [#2088](https://github.com/ratatui/ratatui/pull/2088)

  > part of #2087
  >
  > cc @orhun
  >
  > ***

-
[dafb716](dafb716f9d)
_(widgets)_ Add example for grouped barchart by @orhun in
[#1566](https://github.com/ratatui/ratatui/pull/1566)

  > related #1512
  >
  > ***

-
[ed5dd73](ed5dd73084)
_(widgets)_ Add example for tabs by @orhun in
[#1559](https://github.com/ratatui/ratatui/pull/1559)

  > related #1512
  >
> Also removes the tabs example from ratatui crate since it overlaps
with
> this new example in terms of functionality and it was not following
the
  > general theme of other examples.

-
[fab5321](fab532171d)
_(widgets)_ Add example for scrollbar by @orhun in
[#1545](https://github.com/ratatui/ratatui/pull/1545)

  > Related to: #1512

-
[898aef6](898aef6e2f)
_(widgets)_ Add example for list by @orhun in
[#1542](https://github.com/ratatui/ratatui/pull/1542)

  > Related to: #1512

-
[452366a](452366aa9e)
_(widgets)_ Add example for sparkline by @orhun in
[#1556](https://github.com/ratatui/ratatui/pull/1556)

  > related #1512
  >
> Also removes the sparkline example from ratatui crate since this
example
  > is a simplified and easier to understand version of that

-
[6ddde0e](6ddde0e8a8)
_(widgets)_ Add example for table by @orhun in
[#1557](https://github.com/ratatui/ratatui/pull/1557)

  > related #1512

-
[93ad6b8](93ad6b828c)
_(widgets)_ Update values in chart example by @orhun in
[#1558](https://github.com/ratatui/ratatui/pull/1558)

  > better stonks

-
[15f442a](15f442a71e)
_(widgets)_ Add example for paragraph by @orhun in
[#1544](https://github.com/ratatui/ratatui/pull/1544)

  > related #1512
  >
> Also removes the paragraph example from `ratatui` since these examples
  > are more or less the same.

-
[17bba14](17bba14540)
_(widgets)_ Move the logo example to widgets by @orhun in
[#1543](https://github.com/ratatui/ratatui/pull/1543)

  > related #1512
  >
  > Also updates the code to make it consistent with the other examples

-
[f2451e7](f2451e7f1e)
_(widgets)_ Add example for gauge by @orhun in
[#1539](https://github.com/ratatui/ratatui/pull/1539)

  > related #1512

-
[4f0a8b2](4f0a8b21af)
_(widgets)_ Add example for canvas by @orhun in
[#1533](https://github.com/ratatui/ratatui/pull/1533)

  > related #1512

-
[91147c4](91147c4d75)
_(widgets)_ Add example for chart by @orhun in
[#1536](https://github.com/ratatui/ratatui/pull/1536)

  > stonks

-
[6dd25a3](6dd25a3111)
_(widgets)_ Add example for calendar by @orhun in
[#1532](https://github.com/ratatui/ratatui/pull/1532)

  > related #1512

-
[99ac005](99ac005b06)
_(widgets)_ Add simple barchart example by @joshka in
[#1511](https://github.com/ratatui/ratatui/pull/1511)

-
[f8b0594](f8b0594363)
_(uncategorized)_ Fix: fix typos by @j-g00da in
[#2129](https://github.com/ratatui/ratatui/pull/2129)

  > This fixes the pipeline after bumping typos.

-
[9998000](9998000e36)
_(uncategorized)_ Use shields.io badge by @LitoMore in
[#2040](https://github.com/ratatui/ratatui/pull/2040)

  > Related to:
  >
  > - https://github.com/simple-icons/simple-icons/pull/13593
  > - https://github.com/ratatui/ratatui/pull/1967
  >
  > The Ratatui icon is available on shields.io now ✌️
  >
  > And it's customizable. There are more configurations at
  > https://shields.io/badges.
  >
  > Here are some examples:
  >
  > ```markdown
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  > ```
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
  >
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  >
> I also created a PR to the ratatui-website project to update the
badge.
  > Here is the PR:
  >
  > - https://github.com/ratatui/ratatui-website/pull/924

-
[71ef65b](71ef65b624)
_(uncategorized)_ Add section on collaborative development to
contributing doc by @joshka in
[#2029](https://github.com/ratatui/ratatui/pull/2029)

-
[cba5cca](cba5cca2bd)
_(uncategorized)_ Update heading image for Ratatui 0.30.0 release 🎉 by
@j-g00da in [#2000](https://github.com/ratatui/ratatui/pull/2000)

-
[9836f07](9836f0760d)
_(uncategorized)_ Add AI contribution guidelines by @joshka in
[#2013](https://github.com/ratatui/ratatui/pull/2013)

-
[98f85b8](98f85b8650)
_(uncategorized)_ Update link to scrollable widgets RFC by @MatrixFrog
in [#1994](https://github.com/ratatui/ratatui/pull/1994)

-
[055522e](055522ef7b)
_(uncategorized)_ Add docs for authoring widget crates by @j-g00da in
[#1955](https://github.com/ratatui/ratatui/pull/1955)

  > - added Authoring Widget Libraries sub-section
  > - moved built-in and third-party widgets sections higher

-
[617d318](617d31851a)
_(uncategorized)_ Improve Block docs by @joshka in
[#1953](https://github.com/ratatui/ratatui/pull/1953)

-
[8e2d568](8e2d568428)
_(uncategorized)_ Improve layout related docs by @joshka in
[#1948](https://github.com/ratatui/ratatui/pull/1948)

> Adds module level docs and more comprehensive docs on all the types in
  > the layout module
  >
  > Fixes #1937

-
[4c708dd](4c708ddf8a)
_(uncategorized)_ Improve docs for run/init/restore etc. by @joshka in
[#1947](https://github.com/ratatui/ratatui/pull/1947)

  > - **docs: document the init module**
  > - **docs: use the ratatui::run() methods in the main doc**
> - **docs: add more intradoc / website links and historical perspective
  >   on Terminal / backend**
  > - **docs: add notes about new run/init/restore methods and the
  >   defaultterminal type to terminal docs**

-
[5620e06](5620e06b1a)
_(uncategorized)_ Add crate organization sections to workspace by
@joshka in [#1946](https://github.com/ratatui/ratatui/pull/1946)

  > Adds summary-level crate organization documentation to all crates
> explaining the modular workspace structure and when to use each crate.
  > Links to ARCHITECTURE.md for detailed information.

-
[cfb65e6](cfb65e64ba)
_(uncategorized)_ Add examples for handling state by @joshka in
[#1849](https://github.com/ratatui/ratatui/pull/1849)

> Added comprehensive state management examples covering both immutable
  > and mutable patterns and documentation to help developers choose the
  > right approach for their applications.

-
[3de41a8](3de41a8249)
_(uncategorized)_ Document widgets module by @joshka in
[#1932](https://github.com/ratatui/ratatui/pull/1932)

  > Adds a good overview of the use and implementation of widget traits.
  >
  > Goals with the doc rewrite:
  >
> - document the rationale for the ratatui-widgets crate with info for
app
  >   builders and widget makers.
  > - Show how to use the widgets for rendering as well as implement the
  >   traits- document the differences and reasons for each trait
  > - document the historical perspective (to make it easy to understand
  >   older Ratatui apps as well as migrate to newer approaches
  > - give recommended approaches to implementing traits
  > - explain the differences between Consuming and Shared / Mutable
  >   Reference implementations of Widget
  > - explain the differences between using StatefulWidget and Mutable
  >   References
  > - Explain the use case for WidgetRef and StatefulWidgetRef
  > - Link out to third part widget lists
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/366
  >
  > ***

-
[ca2ad4a](ca2ad4a1f9)
_(uncategorized)_ Simplify ratatui-macro docs by @joshka in
[#1923](https://github.com/ratatui/ratatui/pull/1923)

-
[92b6a16](92b6a16bde)
_(uncategorized)_ Fix grammar in ratatui-widgets README by @sevki in
[#1885](https://github.com/ratatui/ratatui/pull/1885)

-
[da05957](da05957fa0)
_(uncategorized)_ Add widget-ref-container example by @joshka in
[#1603](https://github.com/ratatui/ratatui/pull/1603)

  > Implements ideas alluded to

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2025-12-23 21:45:05 +03:00
dependabot[bot]
1f7efe9d86 build(deps): bump dtolnay/rust-toolchain from 0b1efabc08b657293548b77fb76cc02d26091c7e to f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 (#2281)
Bumps
[dtolnay/rust-toolchain](https://github.com/dtolnay/rust-toolchain) from
0b1efabc08b657293548b77fb76cc02d26091c7e to
f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f7ccc83f9e"><code>f7ccc83</code></a>
Merge pull request <a
href="https://redirect.github.com/dtolnay/rust-toolchain/issues/177">#177</a>
from dtolnay/permitcopyrename</li>
<li><a
href="1c0547fbe5"><code>1c0547f</code></a>
Permit cross-device copy</li>
<li>See full diff in <a
href="0b1efabc08...f7ccc83f9e">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 18:49:46 +03:00
dependabot[bot]
fbd560a0c8 build(deps): bump taiki-e/install-action from 2.63.3 to 2.65.1 (#2282)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.63.3 to 2.65.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.65.1</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.9.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.21.6.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.23.</p>
</li>
</ul>
<h2>2.65.0</h2>
<ul>
<li>
<p>Support <code>cargo-insta</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1372">#1372</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.21.2.</p>
</li>
</ul>
<h2>2.64.2</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.19.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.12.</p>
</li>
</ul>
<h2>2.64.1</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.8.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.11.</p>
</li>
</ul>
<h2>2.64.0</h2>
<ul>
<li>
<p><code>tool</code> input option now supports whitespace (space, tab,
and line) or comma separated list. Previously, only comma-separated list
was supported. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1366">#1366</a>)</p>
</li>
<li>
<p>Support <code>prek</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1357">#1357</a>,
thanks <a href="https://github.com/j178"><code>@​j178</code></a>)</p>
</li>
<li>
<p>Support <code>mdbook-mermaid</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1359">#1359</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Support <code>martin</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1364">#1364</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.68.2.</p>
</li>
<li>
<p>Update <code>xh@latest</code> to 0.25.3.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.10.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.18.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.9.1.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.65.1] - 2025-12-21</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.9.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.21.6.</p>
</li>
<li>
<p>Update <code>prek@latest</code> to 0.2.23.</p>
</li>
</ul>
<h2>[2.65.0] - 2025-12-20</h2>
<ul>
<li>
<p>Support <code>cargo-insta</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1372">#1372</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.21.2.</p>
</li>
</ul>
<h2>[2.64.2] - 2025-12-19</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.19.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.12.</p>
</li>
</ul>
<h2>[2.64.1] - 2025-12-18</h2>
<ul>
<li>
<p>Update <code>tombi@latest</code> to 0.7.8.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.11.</p>
</li>
</ul>
<h2>[2.64.0] - 2025-12-17</h2>
<ul>
<li>
<p><code>tool</code> input option now supports whitespace (space, tab,
and line) or comma separated list. Previously, only comma-separated list
was supported. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1366">#1366</a>)</p>
</li>
<li>
<p>Support <code>prek</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1357">#1357</a>,
thanks <a href="https://github.com/j178"><code>@​j178</code></a>)</p>
</li>
<li>
<p>Support <code>mdbook-mermaid</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1359">#1359</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Support <code>martin</code>. (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1364">#1364</a>,
thanks <a
href="https://github.com/CommanderStorm"><code>@​CommanderStorm</code></a>)</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.68.2.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b9c5db3aef"><code>b9c5db3</code></a>
Release 2.65.1</li>
<li><a
href="7796c0f3bb"><code>7796c0f</code></a>
Update changelog</li>
<li><a
href="f071f24b17"><code>f071f24</code></a>
Update <code>tombi@latest</code> to 0.7.9</li>
<li><a
href="874ad32436"><code>874ad32</code></a>
Update <code>vacuum@latest</code> to 0.21.6</li>
<li><a
href="51bd7eff06"><code>51bd7ef</code></a>
Update <code>vacuum@latest</code> to 0.21.5</li>
<li><a
href="e3a472337e"><code>e3a4723</code></a>
Update <code>prek@latest</code> to 0.2.23</li>
<li><a
href="bfc291e1e3"><code>bfc291e</code></a>
Release 2.65.0</li>
<li><a
href="4620a85cf9"><code>4620a85</code></a>
Update changelog</li>
<li><a
href="09980ef8ed"><code>09980ef</code></a>
Support <code>cargo-insta</code> (<a
href="https://redirect.github.com/taiki-e/install-action/issues/1372">#1372</a>)</li>
<li><a
href="e6fc9bc5a6"><code>e6fc9bc</code></a>
Update <code>vacuum@latest</code> to 0.21.2</li>
<li>Additional commits viewable in <a
href="d850aa8169...b9c5db3aef">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.63.3&new-version=2.65.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 18:49:21 +03:00
dependabot[bot]
44957543c5 build(deps): bump serde_json from 1.0.145 to 1.0.146 (#2284)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.145 to
1.0.146.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/serde-rs/json/releases">serde_json's
releases</a>.</em></p>
<blockquote>
<h2>v1.0.146</h2>
<ul>
<li>Set fast_arithmetic=64 for riscv64 (<a
href="https://redirect.github.com/serde-rs/json/issues/1305">#1305</a>,
thanks <a
href="https://github.com/Xeonacid"><code>@​Xeonacid</code></a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="75ad7e6b4e"><code>75ad7e6</code></a>
Release 1.0.146</li>
<li><a
href="bc6c8276d9"><code>bc6c827</code></a>
Merge pull request <a
href="https://redirect.github.com/serde-rs/json/issues/1305">#1305</a>
from Xeonacid/patch-1</li>
<li><a
href="a09210adf5"><code>a09210a</code></a>
Set fast_arithmetic=64 for riscv64</li>
<li><a
href="01182e54b5"><code>01182e5</code></a>
Update actions/upload-artifact@v5 -&gt; v6</li>
<li><a
href="383b13a45f"><code>383b13a</code></a>
Update actions/upload-artifact@v4 -&gt; v5</li>
<li><a
href="04dd357b99"><code>04dd357</code></a>
Raise required compiler to Rust 1.68</li>
<li><a
href="e047dfbe00"><code>e047dfb</code></a>
Resolve manual_let_else pedantic clippy lint</li>
<li><a
href="a525d9c0c0"><code>a525d9c</code></a>
Raise required compiler to Rust 1.65</li>
<li><a
href="f815793bfd"><code>f815793</code></a>
Remove rustc version badge from readme</li>
<li><a
href="3f17d2c6ea"><code>3f17d2c</code></a>
Update actions/checkout@v5 -&gt; v6</li>
<li>Additional commits viewable in <a
href="https://github.com/serde-rs/json/compare/v1.0.145...v1.0.146">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde_json&package-manager=cargo&previous-version=1.0.145&new-version=1.0.146)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-12-22 18:43:38 +03:00
dependabot[bot]
a8d8afe101 build(deps): bump tracing from 0.1.43 to 0.1.44 (#2283)
Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.43 to
0.1.44.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tracing/releases">tracing's
releases</a>.</em></p>
<blockquote>
<h2>tracing 0.1.44</h2>
<h3>Fixed</h3>
<ul>
<li>Fix <code>record_all</code> panic (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3432">#3432</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li><code>tracing-core</code>: updated to 0.1.36 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3440">#3440</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/3432">#3432</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3432">tokio-rs/tracing#3432</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3440">#3440</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3440">tokio-rs/tracing#3440</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2d55f6faf9"><code>2d55f6f</code></a>
chore: prepare tracing 0.1.44 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3439">#3439</a>)</li>
<li><a
href="10a9e838a3"><code>10a9e83</code></a>
chore: prepare tracing-core 0.1.36 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3440">#3440</a>)</li>
<li><a
href="ee82cf92a8"><code>ee82cf9</code></a>
tracing: fix record_all panic (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3432">#3432</a>)</li>
<li><a
href="9978c3663b"><code>9978c36</code></a>
chore: prepare tracing-mock 0.1.0-beta.3 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3429">#3429</a>)</li>
<li><a
href="cc44064b3a"><code>cc44064</code></a>
chore: prepare tracing-subscriber 0.3.22 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3428">#3428</a>)</li>
<li>See full diff in <a
href="https://github.com/tokio-rs/tracing/compare/tracing-0.1.43...tracing-0.1.44">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing&package-manager=cargo&previous-version=0.1.43&new-version=0.1.44)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 18:43:04 +03:00
dependabot[bot]
664b79404b build(deps): bump octocrab from 0.48.1 to 0.49.2 (#2285)
Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.48.1 to
0.49.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.49.2</h2>
<h3>Added</h3>
<ul>
<li>Add body_text and body_html to Comment model (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/832">#832</a>)</li>
</ul>
<h2>v0.49.1</h2>
<h3>Added</h3>
<ul>
<li>provide expiration-aware installation token APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/837">#837</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Send body for retried requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/842">#842</a>)</li>
</ul>
<h2>v0.49.0</h2>
<h3>Fixed</h3>
<ul>
<li>[<strong>breaking</strong>] add a cfg to make the crypto backend for
jwt configurable (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/834">#834</a>)</li>
<li>incorrect path for followers and followees (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/829">#829</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>fix various warnings in CI and deny warnings being reintroduced (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/839">#839</a>)</li>
<li>[<strong>breaking</strong>] mark more structs as
<code>#[non_exhaustive]</code> (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/840">#840</a>)</li>
<li>Partial implementation of Organization CoPilot APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/747">#747</a>)</li>
<li>[codes-of-conduct] <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/527">#527</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/833">#833</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.1...v0.49.2">0.49.2</a>
- 2025-12-20</h2>
<h3>Added</h3>
<ul>
<li>Add body_text and body_html to Comment model (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/832">#832</a>)</li>
</ul>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.49.0...v0.49.1">0.49.1</a>
- 2025-12-20</h2>
<h3>Added</h3>
<ul>
<li>provide expiration-aware installation token APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/837">#837</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Send body for retried requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/842">#842</a>)</li>
</ul>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.48.1...v0.49.0">0.49.0</a>
- 2025-12-19</h2>
<h3>Fixed</h3>
<ul>
<li>[<strong>breaking</strong>] add a cfg to make the crypto backend for
jwt configurable (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/834">#834</a>)</li>
<li>incorrect path for followers and followees (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/829">#829</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>fix various warnings in CI and deny warnings being reintroduced (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/839">#839</a>)</li>
<li>[<strong>breaking</strong>] mark more structs as
<code>#[non_exhaustive]</code> (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/840">#840</a>)</li>
<li>Partial implementation of Organization CoPilot APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/747">#747</a>)</li>
<li>[codes-of-conduct] <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/527">#527</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/833">#833</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="927105dffe"><code>927105d</code></a>
chore: release v0.49.2 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/843">#843</a>)</li>
<li><a
href="90f9139b85"><code>90f9139</code></a>
feat: Add body_text and body_html to Comment model (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/832">#832</a>)</li>
<li><a
href="4fce8e0221"><code>4fce8e0</code></a>
chore: release v0.49.1 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/841">#841</a>)</li>
<li><a
href="5ce8559748"><code>5ce8559</code></a>
fix: Send body for retried requests (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/842">#842</a>)</li>
<li><a
href="c8b8228529"><code>c8b8228</code></a>
feat: provide expiration-aware installation token APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/837">#837</a>)</li>
<li><a
href="c554baad27"><code>c554baa</code></a>
chore: release v0.49.0 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/838">#838</a>)</li>
<li><a
href="3d8d846dfa"><code>3d8d846</code></a>
fix!: add a cfg to make the crypto backend for jwt configurable (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/834">#834</a>)</li>
<li><a
href="8e4624a30c"><code>8e4624a</code></a>
chore: fix various warnings in CI and deny warnings being reintroduced
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/839">#839</a>)</li>
<li><a
href="60878beec7"><code>60878be</code></a>
chore!: mark more structs as <code>#[non_exhaustive]</code> (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/840">#840</a>)</li>
<li><a
href="2c49ae4050"><code>2c49ae4</code></a>
Partial implementation of Organization CoPilot APIs (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/747">#747</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.48.1...v0.49.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.48.1&new-version=0.49.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 18:42:41 +03:00
dependabot[bot]
f9c6093b66 build(deps): bump fakeit from 1.4.0 to 1.4.1 (#2286)
Bumps [fakeit](https://github.com/PumpkinSeed/fakeit) from 1.4.0 to
1.4.1.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="352e9939c0"><code>352e993</code></a>
Bump version</li>
<li><a
href="7c4b0be098"><code>7c4b0be</code></a>
Merge pull request <a
href="https://redirect.github.com/PumpkinSeed/fakeit/issues/38">#38</a>
from scriptnetsthlm/master</li>
<li><a
href="551b15999b"><code>551b159</code></a>
Update gender function to include female</li>
<li>See full diff in <a
href="https://github.com/PumpkinSeed/fakeit/compare/v1.4.0...v1.4.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=fakeit&package-manager=cargo&previous-version=1.4.0&new-version=1.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-22 18:42:11 +03:00
Orhun Parmaksız
b7ecef086d chore: expose crossterm 0.28/0.29 feature flags in Ratatui (#2270)
In docs we currently say that individual versions of crossterm could be
enabled like this:

```toml
ratatui = { version = "0.30.0-beta", features = ["crossterm_0_28"] }
```

However this wasn't actually possible:

```
package `x` depends on `ratatui` with feature `crossterm_0_28` but `ratatui` does not have that feature.

failed to select a version for `ratatui` which could resolve this conflict
```

This PR fixes that by exposing respective feature flags.
(Tested locally)

---------

Co-authored-by: Jagoda Estera Ślązak <128227338+j-g00da@users.noreply.github.com>
2025-12-16 11:23:50 +03:00
dependabot[bot]
38f7ee2049 build(deps): bump DavidAnson/markdownlint-cli2-action from 21.0.0 to 22.0.0 (#2273)
Bumps
[DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action)
from 21.0.0 to 22.0.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="07035fd053"><code>07035fd</code></a>
Update to version 22.0.0.</li>
<li><a
href="d74d6a504e"><code>d74d6a5</code></a>
Freshen generated index.js file.</li>
<li><a
href="ecaf45cd0e"><code>ecaf45c</code></a>
Bump markdownlint-cli2 from 0.19.1 to 0.20.0</li>
<li><a
href="e4bf40dee6"><code>e4bf40d</code></a>
Freshen generated index.js file.</li>
<li><a
href="ae047c4d45"><code>ae047c4</code></a>
Bump markdownlint-cli2 from 0.19.0 to 0.19.1</li>
<li><a
href="db7ea3f7fb"><code>db7ea3f</code></a>
Bump actions/checkout from 5 to 6</li>
<li><a
href="bfd3fdc8e2"><code>bfd3fdc</code></a>
Bump <code>@​stylistic/eslint-plugin</code> from 5.6.0 to 5.6.1</li>
<li><a
href="43dc18c80b"><code>43dc18c</code></a>
Bump <code>@​stylistic/eslint-plugin</code> from 5.5.0 to 5.6.0</li>
<li>See full diff in <a
href="30a0e04f18...07035fd053">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=DavidAnson/markdownlint-cli2-action&package-manager=github_actions&previous-version=21.0.0&new-version=22.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:45:48 +03:00
dependabot[bot]
87a382f0e7 build(deps): bump codecov/codecov-action from 5.5.1 to 5.5.2 (#2272)
Bumps
[codecov/codecov-action](https://github.com/codecov/codecov-action) from
5.5.1 to 5.5.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/releases">codecov/codecov-action's
releases</a>.</em></p>
<blockquote>
<h2>v5.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>check gpg only when skip-validation = false by <a
href="https://github.com/maxweng-sentry"><code>@​maxweng-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1894">codecov/codecov-action#1894</a></li>
<li>chore: <code>disable_search</code> alignment by <a
href="https://github.com/freemanzMrojo"><code>@​freemanzMrojo</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1881">codecov/codecov-action#1881</a></li>
<li>chore(release): 5.5.2 by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1902">codecov/codecov-action#1902</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/maxweng-sentry"><code>@​maxweng-sentry</code></a>
made their first contribution in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1894">codecov/codecov-action#1894</a></li>
<li><a
href="https://github.com/freemanzMrojo"><code>@​freemanzMrojo</code></a>
made their first contribution in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1881">codecov/codecov-action#1881</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1...v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1...v5.5.2</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md">codecov/codecov-action's
changelog</a>.</em></p>
<blockquote>
<h2>v5.5.2</h2>
<h3>What's Changed</h3>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2">https://github.com/codecov/codecov-action/compare/v5.5.1..v5.5.2</a></p>
<h2>v5.5.1</h2>
<h3>What's Changed</h3>
<ul>
<li>fix: overwrite pr number on fork by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1871">codecov/codecov-action#1871</a></li>
<li>build(deps): bump actions/checkout from 4.2.2 to 5.0.0 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1868">codecov/codecov-action#1868</a></li>
<li>build(deps): bump github/codeql-action from 3.29.9 to 3.29.11 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1867">codecov/codecov-action#1867</a></li>
<li>fix: update to use local app/ dir by <a
href="https://github.com/thomasrockhu-codecov"><code>@​thomasrockhu-codecov</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1872">codecov/codecov-action#1872</a></li>
<li>docs: fix typo in README by <a
href="https://github.com/datalater"><code>@​datalater</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1866">codecov/codecov-action#1866</a></li>
<li>Document a <code>codecov-cli</code> version reference example by <a
href="https://github.com/webknjaz"><code>@​webknjaz</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1774">codecov/codecov-action#1774</a></li>
<li>build(deps): bump github/codeql-action from 3.28.18 to 3.29.9 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1861">codecov/codecov-action#1861</a></li>
<li>build(deps): bump ossf/scorecard-action from 2.4.1 to 2.4.2 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1833">codecov/codecov-action#1833</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1">https://github.com/codecov/codecov-action/compare/v5.5.0..v5.5.1</a></p>
<h2>v5.5.0</h2>
<h3>What's Changed</h3>
<ul>
<li>feat: upgrade wrapper to 0.2.4 by <a
href="https://github.com/jviall"><code>@​jviall</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1864">codecov/codecov-action#1864</a></li>
<li>Pin actions/github-script by Git SHA by <a
href="https://github.com/martincostello"><code>@​martincostello</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1859">codecov/codecov-action#1859</a></li>
<li>fix: check reqs exist by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1835">codecov/codecov-action#1835</a></li>
<li>fix: Typo in README by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1838">codecov/codecov-action#1838</a></li>
<li>docs: Refine OIDC docs by <a
href="https://github.com/spalmurray"><code>@​spalmurray</code></a> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1837">codecov/codecov-action#1837</a></li>
<li>build(deps): bump github/codeql-action from 3.28.17 to 3.28.18 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1829">codecov/codecov-action#1829</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0">https://github.com/codecov/codecov-action/compare/v5.4.3..v5.5.0</a></p>
<h2>v5.4.3</h2>
<h3>What's Changed</h3>
<ul>
<li>build(deps): bump github/codeql-action from 3.28.13 to 3.28.17 by
<code>@​app/dependabot</code> in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1822">codecov/codecov-action#1822</a></li>
<li>fix: OIDC on forks by <a
href="https://github.com/joseph-sentry"><code>@​joseph-sentry</code></a>
in <a
href="https://redirect.github.com/codecov/codecov-action/pull/1823">codecov/codecov-action#1823</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3">https://github.com/codecov/codecov-action/compare/v5.4.2..v5.4.3</a></p>
<h2>v5.4.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="671740ac38"><code>671740a</code></a>
chore(release): 5.5.2 (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1902">#1902</a>)</li>
<li><a
href="96b38e9e60"><code>96b38e9</code></a>
chore: <code>disable_search</code> alignment (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1881">#1881</a>)</li>
<li><a
href="9b6d1f84bd"><code>9b6d1f8</code></a>
check gpg only when skip-validation = false (<a
href="https://redirect.github.com/codecov/codecov-action/issues/1894">#1894</a>)</li>
<li>See full diff in <a
href="5a1091511a...671740ac38">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov/codecov-action&package-manager=github_actions&previous-version=5.5.1&new-version=5.5.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:45:12 +03:00
dependabot[bot]
4367bb45a1 build(deps): bump taiki-e/install-action from 2.62.63 to 2.63.3 (#2271)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.63 to 2.63.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.63.3</h2>
<ul>
<li>Update <code>cargo-nextest@latest</code> to 0.9.115.</li>
</ul>
<h2>2.63.2</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.7.</p>
</li>
<li>
<p>Update <code>git-cliff@latest</code> to 2.11.0.</p>
</li>
<li>
<p>Update <code>coreutils@latest</code> to 0.5.0.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.4.</p>
</li>
</ul>
<h2>2.63.1</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.5.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.9.0.</p>
</li>
</ul>
<h2>2.63.0</h2>
<ul>
<li>
<p>Support <code>tombi</code> (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1340">#1340</a>,
thanks <a
href="https://github.com/crepererum"><code>@​crepererum</code></a>)</p>
</li>
<li>
<p>Update <code>cargo-dinghy@latest</code> to 0.8.4.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.2.</p>
</li>
<li>
<p>Update <code>mdbook@latest</code> to 0.5.2.</p>
</li>
</ul>
<h2>2.62.67</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.5.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.72.1.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.3.1.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.45.0.</p>
</li>
</ul>
<h2>2.62.66</h2>
<ul>
<li>
<p>Update <code>uv@latest</code> to 0.9.17.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.38.2.</p>
</li>
</ul>
<h2>2.62.65</h2>
<ul>
<li>
<p>Update <code>cyclonedx@latest</code> to 0.29.2.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.44.1.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.7.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.1.</p>
</li>
</ul>
<h2>2.62.64</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.63.3] - 2025-12-15</h2>
<ul>
<li>Update <code>cargo-nextest@latest</code> to 0.9.115.</li>
</ul>
<h2>[2.63.2] - 2025-12-15</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.7.</p>
</li>
<li>
<p>Update <code>git-cliff@latest</code> to 2.11.0.</p>
</li>
<li>
<p>Update <code>coreutils@latest</code> to 0.5.0.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.4.</p>
</li>
</ul>
<h2>[2.63.1] - 2025-12-14</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.12.5.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.9.0.</p>
</li>
</ul>
<h2>[2.63.0] - 2025-12-12</h2>
<ul>
<li>
<p>Support <code>tombi</code> (<a
href="https://redirect.github.com/taiki-e/install-action/pull/1340">#1340</a>,
thanks <a
href="https://github.com/crepererum"><code>@​crepererum</code></a>)</p>
</li>
<li>
<p>Update <code>cargo-dinghy@latest</code> to 0.8.4.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.2.</p>
</li>
<li>
<p>Update <code>mdbook@latest</code> to 0.5.2.</p>
</li>
</ul>
<h2>[2.62.67] - 2025-12-11</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.5.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.72.1.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.3.1.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d850aa8169"><code>d850aa8</code></a>
Release 2.63.3</li>
<li><a
href="4e27f4eba3"><code>4e27f4e</code></a>
Update <code>cargo-nextest@latest</code> to 0.9.115</li>
<li><a
href="5818d9684d"><code>5818d96</code></a>
Release 2.63.2</li>
<li><a
href="9935da0ea5"><code>9935da0</code></a>
Update changelog</li>
<li><a
href="3396925d74"><code>3396925</code></a>
Update <code>mise@latest</code> to 2025.12.7</li>
<li><a
href="4563b68018"><code>4563b68</code></a>
Update <code>mise@latest</code> to 2025.12.6</li>
<li><a
href="bb9926ecd3"><code>bb9926e</code></a>
Update <code>git-cliff@latest</code> to 2.11.0</li>
<li><a
href="68c369b718"><code>68c369b</code></a>
Update <code>coreutils@latest</code> to 0.5.0</li>
<li><a
href="2afaa0138a"><code>2afaa01</code></a>
Update <code>cargo-binstall@latest</code> to 1.16.4</li>
<li><a
href="61e5998d10"><code>61e5998</code></a>
Release 2.63.1</li>
<li>Additional commits viewable in <a
href="50708e9ba8...d850aa8169">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.63&new-version=2.63.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 18:44:46 +03:00
三咲雅 misaki masa
bf84c6229b feat(core): Add a has_modifier() method to Style (#2267)
Resolves https://github.com/ratatui/ratatui/issues/2264
2025-12-13 14:07:45 -08:00
dependabot[bot]
3bdb9fe982 build(deps): bump release-plz/action from 0.5.119 to 0.5.120 (#2254)
Bumps [release-plz/action](https://github.com/release-plz/action) from
0.5.119 to 0.5.120.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/release-plz/action/releases">release-plz/action's
releases</a>.</em></p>
<blockquote>
<h2>v0.5.120</h2>
<h2>What's Changed</h2>
<ul>
<li>Update to 0.3.150 by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/232">release-plz/action#232</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/release-plz/action/compare/v0.5...v0.5.120">https://github.com/release-plz/action/compare/v0.5...v0.5.120</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="487eb7b5c0"><code>487eb7b</code></a>
Update to 0.3.150 (<a
href="https://redirect.github.com/release-plz/action/issues/232">#232</a>)</li>
<li>See full diff in <a
href="1efcf74dfc...487eb7b5c0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=release-plz/action&package-manager=github_actions&previous-version=0.5.119&new-version=0.5.120)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:58:07 +03:00
dependabot[bot]
2163fd5a2c build(deps): bump actions/checkout from 6.0.0 to 6.0.1 (#2255)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.0
to 6.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.1">https://github.com/actions/checkout/compare/v6...v6.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8e8c483db8"><code>8e8c483</code></a>
Clarify v6 README (<a
href="https://redirect.github.com/actions/checkout/issues/2328">#2328</a>)</li>
<li><a
href="033fa0dc0b"><code>033fa0d</code></a>
Add worktree support for persist-credentials includeIf (<a
href="https://redirect.github.com/actions/checkout/issues/2327">#2327</a>)</li>
<li><a
href="c2d88d3ecc"><code>c2d88d3</code></a>
Update all references from v5 and v4 to v6 (<a
href="https://redirect.github.com/actions/checkout/issues/2314">#2314</a>)</li>
<li>See full diff in <a
href="1af3b93b68...8e8c483db8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=6.0.0&new-version=6.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:57:50 +03:00
dependabot[bot]
645cd55ed2 build(deps): bump taiki-e/install-action from 2.62.61 to 2.62.63 (#2256)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.61 to 2.62.63.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.63</h2>
<ul>
<li>
<p>Update <code>protoc@latest</code> to 3.33.2.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.150.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.3.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.21.7.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.0.</p>
</li>
</ul>
<h2>2.62.62</h2>
<ul>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.18.8.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.7.1.</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.68.1.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.15.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.21.6.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<ul>
<li>
<p>Update <code>just@latest</code> to 1.44.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.16.</p>
</li>
</ul>
<h2>[2.62.63] - 2025-12-06</h2>
<ul>
<li>
<p>Update <code>protoc@latest</code> to 3.33.2.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.150.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.3.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.21.7.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.12.0.</p>
</li>
</ul>
<h2>[2.62.62] - 2025-12-03</h2>
<ul>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.18.8.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.7.1.</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.68.1.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.15.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.21.6.</p>
</li>
</ul>
<h2>[2.62.61] - 2025-12-02</h2>
<ul>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.18.7.</p>
</li>
<li>
<p>Update <code>cargo-careful@latest</code> to 0.4.9.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.14.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.4.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="50708e9ba8"><code>50708e9</code></a>
Release 2.62.63</li>
<li><a
href="608cb5db93"><code>608cb5d</code></a>
Update <code>protoc@latest</code> to 3.33.2</li>
<li><a
href="813a6b3dc6"><code>813a6b3</code></a>
Update <code>release-plz@latest</code> to 0.3.150</li>
<li><a
href="643883d80b"><code>643883d</code></a>
Update <code>cargo-binstall@latest</code> to 1.16.3</li>
<li><a
href="3a82a98e89"><code>3a82a98</code></a>
Update <code>knope@latest</code> to 0.21.7</li>
<li><a
href="b24d319e09"><code>b24d319</code></a>
Update <code>mise@latest</code> to 2025.12.0</li>
<li><a
href="493d7f216e"><code>493d7f2</code></a>
Release 2.62.62</li>
<li><a
href="0c6fcb01be"><code>0c6fcb0</code></a>
Update <code>cargo-deny@latest</code> to 0.18.8</li>
<li><a
href="e8101c18b1"><code>e8101c1</code></a>
Tweak docs</li>
<li><a
href="c8c9b5bb95"><code>c8c9b5b</code></a>
tools: Update scripts</li>
<li>Additional commits viewable in <a
href="92e6dd1c20...50708e9ba8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.61&new-version=2.62.63)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:57:19 +03:00
dependabot[bot]
28d80365d6 build(deps): bump octocrab from 0.48.0 to 0.48.1 (#2258)
Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.48.0 to
0.48.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.48.1</h2>
<h3>Fixed</h3>
<ul>
<li><em>(build)</em> don't fetch dependencies (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/828">#828</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.48.0...v0.48.1">0.48.1</a>
- 2025-12-02</h2>
<h3>Fixed</h3>
<ul>
<li><em>(build)</em> don't fetch dependencies (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/828">#828</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d381cc09db"><code>d381cc0</code></a>
chore: release v0.48.1 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/830">#830</a>)</li>
<li><a
href="41162f3dc1"><code>41162f3</code></a>
fix(build): don't fetch dependencies (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/828">#828</a>)</li>
<li>See full diff in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.48.0...v0.48.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.48.0&new-version=0.48.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:56:27 +03:00
dependabot[bot]
c52de1a926 build(deps): bump tracing-appender from 0.2.3 to 0.2.4 (#2259)
Bumps [tracing-appender](https://github.com/tokio-rs/tracing) from 0.2.3
to 0.2.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tracing/releases">tracing-appender's
releases</a>.</em></p>
<blockquote>
<h2>tracing-appender 0.2.4</h2>
<h3>Added</h3>
<ul>
<li>Prune old files at startup (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/2966">#2966</a>)</li>
<li>Add fallback to file creation date (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3000">#3000</a>)</li>
<li>Introduce weekly rotation (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3218">#3218</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix <code>max_files</code> integer underflow when set to zero (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3348">#3348</a>)</li>
</ul>
<h3>Documented</h3>
<ul>
<li>Update tracing-appender docs link to correct docs.rs URL (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3325">#3325</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/2966">#2966</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#2966%5D(https://redirect.github.com/tokio-rs/tracing/issues/2966)">tokio-rs/tracing#2966</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3000">#3000</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3000%5D(https://redirect.github.com/tokio-rs/tracing/issues/3000)">tokio-rs/tracing#3000</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3218">#3218</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3218%5D(https://redirect.github.com/tokio-rs/tracing/issues/3218)">tokio-rs/tracing#3218</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3325">#3325</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3325%5D(https://redirect.github.com/tokio-rs/tracing/issues/3325)">tokio-rs/tracing#3325</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3348">#3348</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3348%5D(https://redirect.github.com/tokio-rs/tracing/issues/3348)">tokio-rs/tracing#3348</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="405397b8cc"><code>405397b</code></a>
chore: prepare tracing-appender 0.2.4 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3420">#3420</a>)</li>
<li><a
href="a9eeed7394"><code>a9eeed7</code></a>
chore: prepare tracing-subscriber 0.3.21 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3419">#3419</a>)</li>
<li><a
href="5bd5505478"><code>5bd5505</code></a>
chore: prepare tracing 0.1.42 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3418">#3418</a>)</li>
<li><a
href="55086231ec"><code>5508623</code></a>
chore: prepare tracing-attributes 0.1.31 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3417">#3417</a>)</li>
<li><a
href="d92b4c0feb"><code>d92b4c0</code></a>
chore: prepare tracing-core 0.1.35 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3414">#3414</a>)</li>
<li><a
href="9751b6e776"><code>9751b6e</code></a>
chore: run <code>tracing-subscriber</code> tests with all features (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3412">#3412</a>)</li>
<li><a
href="efa0169b43"><code>efa0169</code></a>
mock: add doctests for <code>on_register_dispatch</code> negative cases
(<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3416">#3416</a>)</li>
<li><a
href="a093858f38"><code>a093858</code></a>
docs: fix link in <code>FmtSpan</code> docs (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3411">#3411</a>)</li>
<li><a
href="976fa55e2a"><code>976fa55</code></a>
mock: add test case for layer not calling on_register_dispatch (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3415">#3415</a>)</li>
<li><a
href="8bc008c5f0"><code>8bc008c</code></a>
fix(subscriber): make Layered propagate on_register_dispatch (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3379">#3379</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tracing/compare/tracing-appender-0.2.3...tracing-appender-0.2.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing-appender&package-manager=cargo&previous-version=0.2.3&new-version=0.2.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:56:03 +03:00
dependabot[bot]
e338795396 build(deps): bump line-clipping from 0.3.4 to 0.3.5 (#2260)
Bumps [line-clipping](https://github.com/joshka/line-clipping) from
0.3.4 to 0.3.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/joshka/line-clipping/releases">line-clipping's
releases</a>.</em></p>
<blockquote>
<h2>v0.3.5</h2>
<h3>Other</h3>
<ul>
<li>use trusted-publising (<a
href="https://redirect.github.com/joshka/line-clipping/pull/24">#24</a>)</li>
<li>set edition 2024 and msrv 1.85 (<a
href="https://redirect.github.com/joshka/line-clipping/pull/23">#23</a>)</li>
<li><em>(deps)</em> bump actions/checkout in the github-actions group
(<a
href="https://redirect.github.com/joshka/line-clipping/pull/22">#22</a>)</li>
<li><em>(deps)</em> bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/pull/21">#21</a>)</li>
<li><em>(deps)</em> bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/pull/18">#18</a>)</li>
<li>fix clippy install (<a
href="https://redirect.github.com/joshka/line-clipping/pull/19">#19</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/joshka/line-clipping/blob/main/CHANGELOG.md">line-clipping's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/joshka/line-clipping/compare/v0.3.4...v0.3.5">0.3.5</a>
- 2025-11-29</h2>
<h3>Other</h3>
<ul>
<li>use trusted-publising (<a
href="https://redirect.github.com/joshka/line-clipping/pull/24">#24</a>)</li>
<li>set edition 2024 and msrv 1.85 (<a
href="https://redirect.github.com/joshka/line-clipping/pull/23">#23</a>)</li>
<li><em>(deps)</em> bump actions/checkout in the github-actions group
(<a
href="https://redirect.github.com/joshka/line-clipping/pull/22">#22</a>)</li>
<li><em>(deps)</em> bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/pull/21">#21</a>)</li>
<li><em>(deps)</em> bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/pull/18">#18</a>)</li>
<li>fix clippy install (<a
href="https://redirect.github.com/joshka/line-clipping/pull/19">#19</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="edf70705ae"><code>edf7070</code></a>
chore: release v0.3.5 (<a
href="https://redirect.github.com/joshka/line-clipping/issues/20">#20</a>)</li>
<li><a
href="64af0944e9"><code>64af094</code></a>
chore: use trusted-publising (<a
href="https://redirect.github.com/joshka/line-clipping/issues/24">#24</a>)</li>
<li><a
href="3a88318f99"><code>3a88318</code></a>
chore: set edition 2024 and msrv 1.85 (<a
href="https://redirect.github.com/joshka/line-clipping/issues/23">#23</a>)</li>
<li><a
href="180f3a1952"><code>180f3a1</code></a>
build(deps): bump actions/checkout in the github-actions group (<a
href="https://redirect.github.com/joshka/line-clipping/issues/22">#22</a>)</li>
<li><a
href="4e5cf3b954"><code>4e5cf3b</code></a>
build(deps): bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/issues/21">#21</a>)</li>
<li><a
href="b7808bc2e0"><code>b7808bc</code></a>
build(deps): bump bitflags in the rust-dependencies group (<a
href="https://redirect.github.com/joshka/line-clipping/issues/18">#18</a>)</li>
<li><a
href="ffead4fad2"><code>ffead4f</code></a>
ci: fix clippy install (<a
href="https://redirect.github.com/joshka/line-clipping/issues/19">#19</a>)</li>
<li>See full diff in <a
href="https://github.com/joshka/line-clipping/compare/v0.3.4...v0.3.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=line-clipping&package-manager=cargo&previous-version=0.3.4&new-version=0.3.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:54:35 +03:00
dependabot[bot]
f944f2fff9 build(deps): bump instability from 0.3.9 to 0.3.10 (#2261)
Bumps [instability](https://github.com/ratatui/instability) from 0.3.9
to 0.3.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/instability/releases">instability's
releases</a>.</em></p>
<blockquote>
<h2>instability-example-v0.3.10</h2>
<h3>Other</h3>
<ul>
<li>Add #[allow(unused_imports)] lint to unstable reexports (<a
href="https://redirect.github.com/ratatui/instability/pull/21">#21</a>)</li>
</ul>
<h2>instability-v0.3.10</h2>
<h3>Other</h3>
<ul>
<li>enable trusted publishing with release-plz (<a
href="https://redirect.github.com/ratatui/instability/pull/31">#31</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/instability/blob/main/CHANGELOG.md">instability's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/ratatui/instability/compare/instability-v0.3.9...instability-v0.3.10">0.3.10</a>
- 2025-11-29</h2>
<h3>Other</h3>
<ul>
<li>enable trusted publishing with release-plz (<a
href="https://redirect.github.com/ratatui/instability/pull/31">#31</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8b311cd7d5"><code>8b311cd</code></a>
chore: release v0.3.10 (<a
href="https://redirect.github.com/ratatui/instability/issues/32">#32</a>)</li>
<li><a
href="220c65cbc5"><code>220c65c</code></a>
chore: enable trusted publishing with release-plz (<a
href="https://redirect.github.com/ratatui/instability/issues/31">#31</a>)</li>
<li>See full diff in <a
href="https://github.com/ratatui/instability/compare/instability-v0.3.9...instability-v0.3.10">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=instability&package-manager=cargo&previous-version=0.3.9&new-version=0.3.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:54:06 +03:00
dependabot[bot]
58c85295ae build(deps): bump criterion from 0.8.0 to 0.8.1 (#2257)
Bumps [criterion](https://github.com/criterion-rs/criterion.rs) from
0.8.0 to 0.8.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/criterion-rs/criterion.rs/releases">criterion's
releases</a>.</em></p>
<blockquote>
<h2>criterion-plot-v0.8.1</h2>
<h3>Fixed</h3>
<ul>
<li>Typo</li>
</ul>
<h2>criterion-v0.8.1</h2>
<h3>Fixed</h3>
<ul>
<li>Homepage link</li>
</ul>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump crate-ci/typos from 1.23.5 to 1.40.0</li>
<li><em>(deps)</em> bump jontze/action-mdbook from 3 to 4</li>
<li><em>(deps)</em> bump actions/checkout from 4 to 6</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.8.0...criterion-v0.8.1">0.8.1</a>
- 2025-12-07</h2>
<h3>Fixed</h3>
<ul>
<li>Homepage link</li>
</ul>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump crate-ci/typos from 1.23.5 to 1.40.0</li>
<li><em>(deps)</em> bump jontze/action-mdbook from 3 to 4</li>
<li><em>(deps)</em> bump actions/checkout from 4 to 6</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e4e06dfdc3"><code>e4e06df</code></a>
chore: release v0.8.1</li>
<li><a
href="aa548b9f58"><code>aa548b9</code></a>
fix: Homepage link</li>
<li><a
href="950c3b727a"><code>950c3b7</code></a>
fix: Typo</li>
<li><a
href="7e3e50c369"><code>7e3e50c</code></a>
chore(deps): bump crate-ci/typos from 1.23.5 to 1.40.0</li>
<li><a
href="391a99ad54"><code>391a99a</code></a>
chore(deps): bump jontze/action-mdbook from 3 to 4</li>
<li><a
href="8fb9a8797a"><code>8fb9a87</code></a>
chore(deps): bump actions/checkout from 4 to 6</li>
<li>See full diff in <a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.8.0...criterion-v0.8.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=criterion&package-manager=cargo&previous-version=0.8.0&new-version=0.8.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-08 18:53:24 +03:00
dependabot[bot]
dc4ca94e95 build(deps): bump taiki-e/install-action from 2.62.57 to 2.62.60 (#2242)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.57 to 2.62.60.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.60</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.18.0.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.7.0.</p>
</li>
<li>
<p>Update <code>wasm-bindgen@latest</code> to 0.2.106.</p>
</li>
</ul>
<h2>2.62.59</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.10.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.13.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.40.0.</p>
</li>
</ul>
<h2>2.62.58</h2>
<ul>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.6.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.8.</p>
</li>
<li>
<p>Update <code>zizmor@latest</code> to 1.17.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.12.</p>
</li>
<li>
<p>Update <code>editorconfig-checker@latest</code> to 3.6.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 39.0.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.149.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.4.</p>
</li>
<li>
<p>Update <code>cargo-valgrind@latest</code> to 2.4.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.11.</p>
</li>
</ul>
<h2>[2.62.60] - 2025-11-30</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.18.0.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.7.0.</p>
</li>
<li>
<p>Update <code>wasm-bindgen@latest</code> to 0.2.106.</p>
</li>
</ul>
<h2>[2.62.59] - 2025-11-28</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.10.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.13.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.40.0.</p>
</li>
</ul>
<h2>[2.62.58] - 2025-11-26</h2>
<ul>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.6.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.8.</p>
</li>
<li>
<p>Update <code>zizmor@latest</code> to 1.17.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.12.</p>
</li>
<li>
<p>Update <code>editorconfig-checker@latest</code> to 3.6.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 39.0.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.149.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3575e53270"><code>3575e53</code></a>
Release 2.62.60</li>
<li><a
href="82ed20a6c4"><code>82ed20a</code></a>
Update cspell dictionary</li>
<li><a
href="f6aadf50d8"><code>f6aadf5</code></a>
Update <code>zizmor@latest</code> to 1.18.0</li>
<li><a
href="6faf516c7d"><code>6faf516</code></a>
Update <code>cargo-shear@latest</code> to 1.7.0</li>
<li><a
href="54589f5111"><code>54589f5</code></a>
Update <code>wasm-bindgen@latest</code> to 0.2.106</li>
<li><a
href="b4b8094585"><code>b4b8094</code></a>
Release 2.62.59</li>
<li><a
href="812d1ba673"><code>812d1ba</code></a>
Update changelog</li>
<li><a
href="3d348f5824"><code>3d348f5</code></a>
Update <code>mise@latest</code> to 2025.11.10</li>
<li><a
href="85debb04fc"><code>85debb0</code></a>
Update <code>mise@latest</code> to 2025.11.9</li>
<li><a
href="b21ab5b468"><code>b21ab5b</code></a>
Update <code>uv@latest</code> to 0.9.13</li>
<li>Additional commits viewable in <a
href="763e3324d4...3575e53270">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.57&new-version=2.62.60)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 14:43:06 -08:00
Josh McKinney
22610b019b feat: Support adding an Offset to Position (#2239)
Adds Position::offset() and arithmentic ops (Position + Offset and
Position - Offset)

Fixes: https://github.com/ratatui/ratatui/issues/2018
2025-12-06 14:42:39 -08:00
dependabot[bot]
c0e1b1560e build(deps): bump criterion from 0.7.0 to 0.8.0 (#2246)
Bumps [criterion](https://github.com/criterion-rs/criterion.rs) from
0.7.0 to 0.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/criterion-rs/criterion.rs/releases">criterion's
releases</a>.</em></p>
<blockquote>
<h2>criterion-plot-v0.8.0</h2>
<p>No release notes provided.</p>
<h2>criterion-v0.8.0</h2>
<h3>BREAKING</h3>
<ul>
<li>Drop async-std support</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Bump MSRV to 1.86, stable to 1.91.1</li>
</ul>
<h3>Added</h3>
<ul>
<li>Add ability to plot throughput on summary page.</li>
<li>Add support for reporting throughput in elements and bytes -
<code>Throughput::ElementsAndBytes</code> allows the text summary to
report throughput in both units simultaneously.</li>
<li>Add alloca-based memory layout randomisation to mitigate memory
effects on measurements.</li>
<li>Add doc comment to benchmark runner in criterion_group macro
(removes linter warnings)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix plotting NaN bug</li>
</ul>
<h3>Other</h3>
<ul>
<li>Remove Master API Docs links temporarily while we restore the docs
publishing.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/criterion-rs/criterion.rs/blob/master/CHANGELOG.md">criterion's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.7.0...criterion-v0.8.0">0.8.0</a>
- 2025-11-29</h2>
<h3>BREAKING</h3>
<ul>
<li>Drop async-std support</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Bump MSRV to 1.86, stable to 1.91.1</li>
</ul>
<h3>Added</h3>
<ul>
<li>Add ability to plot throughput on summary page.</li>
<li>Add support for reporting throughput in elements and bytes -
<code>Throughput::ElementsAndBytes</code> allows the text summary to
report throughput in both units simultaneously.</li>
<li>Add alloca-based memory layout randomisation to mitigate memory
effects on measurements.</li>
<li>Add doc comment to benchmark runner in criterion_group macro
(removes linter warnings)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix plotting NaN bug</li>
</ul>
<h3>Other</h3>
<ul>
<li>Remove Master API Docs links temporarily while we restore the docs
publishing.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b49ade728c"><code>b49ade7</code></a>
chore: release v0.8.0</li>
<li>See full diff in <a
href="https://github.com/criterion-rs/criterion.rs/compare/criterion-plot-v0.7.0...criterion-v0.8.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=criterion&package-manager=cargo&previous-version=0.7.0&new-version=0.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 14:42:16 -08:00
Paul Harrison
55a95e67bc test(rect): mutual intersection agreement (#2252) 2025-12-03 22:46:00 -08:00
Paul Harrison
345f47e044 style(rect): use plus operator for offset (#2251)
## Summary
Use `+` operator to move `Rect` by an `Offset` as added
[here](https://github.com/ratatui/ratatui/pull/1596).

Includes change to use `Offset::new()` in place of `Offset { ... }`
2025-12-02 17:47:03 +03:00
dependabot[bot]
cb85c8eb4e build(deps): bump release-plz/action from 0.5.118 to 0.5.119 (#2245)
Bumps [release-plz/action](https://github.com/release-plz/action) from
0.5.118 to 0.5.119.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/release-plz/action/releases">release-plz/action's
releases</a>.</em></p>
<blockquote>
<h2>v0.5.119</h2>
<h2>What's Changed</h2>
<ul>
<li>Add <code>dry_run</code> input option by <a
href="https://github.com/MidasLamb"><code>@​MidasLamb</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/204">release-plz/action#204</a></li>
<li>fix test by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/226">release-plz/action#226</a></li>
<li>build(deps): bump actions/checkout from 5 to 6 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/release-plz/action/pull/227">release-plz/action#227</a></li>
<li>updater: fix number of assets by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/228">release-plz/action#228</a></li>
<li>Update to 0.3.149 by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/229">release-plz/action#229</a></li>
<li>update cargo-semver-checks to v0.45 by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/release-plz/action/pull/230">release-plz/action#230</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/MidasLamb"><code>@​MidasLamb</code></a>
made their first contribution in <a
href="https://redirect.github.com/release-plz/action/pull/204">release-plz/action#204</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/release-plz/action/compare/v0.5...v0.5.119">https://github.com/release-plz/action/compare/v0.5...v0.5.119</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1efcf74dfc"><code>1efcf74</code></a>
update cargo-semver-checks to v0.45 (<a
href="https://redirect.github.com/release-plz/action/issues/230">#230</a>)</li>
<li><a
href="063bcc50f8"><code>063bcc5</code></a>
Update to 0.3.149 (<a
href="https://redirect.github.com/release-plz/action/issues/229">#229</a>)</li>
<li><a
href="8fbb571544"><code>8fbb571</code></a>
updater: fix number of assets (<a
href="https://redirect.github.com/release-plz/action/issues/228">#228</a>)</li>
<li><a
href="8139e59591"><code>8139e59</code></a>
build(deps): bump actions/checkout from 5 to 6 (<a
href="https://redirect.github.com/release-plz/action/issues/227">#227</a>)</li>
<li><a
href="01df7609d1"><code>01df760</code></a>
fix test (<a
href="https://redirect.github.com/release-plz/action/issues/226">#226</a>)</li>
<li><a
href="af52851a74"><code>af52851</code></a>
Add <code>dry_run</code> input option (<a
href="https://redirect.github.com/release-plz/action/issues/204">#204</a>)</li>
<li>See full diff in <a
href="d529f731ae...1efcf74dfc">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=release-plz/action&package-manager=github_actions&previous-version=0.5.118&new-version=0.5.119)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:46:08 +03:00
dependabot[bot]
b405a398e9 build(deps): bump tracing from 0.1.41 to 0.1.43 (#2247)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.41 to
0.1.43.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tracing/releases">tracing's
releases</a>.</em></p>
<blockquote>
<h2>tracing 0.1.43</h2>
<h4>Important</h4>
<p>The previous release [0.1.42] was yanked because <a
href="https://redirect.github.com/tokio-rs/tracing/issues/3382">#3382</a>
was a breaking change.
See further details in <a
href="https://redirect.github.com/tokio-rs/tracing/issues/3424">#3424</a>.
This release contains all the changes from that
version, plus a revert for the problematic part of the breaking PR.</p>
<h3>Fixed</h3>
<ul>
<li>Revert &quot;make <code>valueset</code> macro sanitary&quot; (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3425">#3425</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/3382">#3382</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3382">tokio-rs/tracing#3382</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3424">#3424</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3424">tokio-rs/tracing#3424</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3425">#3425</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3425">tokio-rs/tracing#3425</a>
[0.1.42]: <a
href="https://github.com/tokio-rs/tracing/releases/tag/tracing-0.1.42">https://github.com/tokio-rs/tracing/releases/tag/tracing-0.1.42</a></p>
<h2>tracing 0.1.42</h2>
<h3>Important</h3>
<p>The [<code>Span::record_all</code>] method has been removed from the
documented API. It
was always unsuable via the documented API as it requried a
<code>ValueSet</code> which
has no publically documented constructors. The method remains, but
should not
be used outside of <code>tracing</code> macros.</p>
<h3>Added</h3>
<ul>
<li><strong>attributes</strong>: Support constant expressions as
instrument field names (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3158">#3158</a>)</li>
<li>Add <code>record_all!</code> macro for recording multiple values in
one call (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3227">#3227</a>)</li>
<li><strong>core</strong>: Improve code generation at trace points
significantly (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3398">#3398</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li><code>tracing-core</code>: updated to 0.1.35 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3414">#3414</a>)</li>
<li><code>tracing-attributes</code>: updated to 0.1.31 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3417">#3417</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix &quot;name / parent&quot; variant of <code>event!</code> (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/2983">#2983</a>)</li>
<li>Remove 'r#' prefix from raw identifiers in field names (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3130">#3130</a>)</li>
<li>Fix perf regression when <code>release_max_level_*</code> not set
(<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3373">#3373</a>)</li>
<li>Use imported instead of fully qualified path (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3374">#3374</a>)</li>
<li>Make <code>valueset</code> macro sanitary (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3382">#3382</a>)</li>
</ul>
<h3>Documented</h3>
<ul>
<li><strong>core</strong>: Add missing <code>dyn</code> keyword in
<code>Visit</code> documentation code sample (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3387">#3387</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/2983">#2983</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#2983%5D(https://redirect.github.com/tokio-rs/tracing/issues/2983)">tokio-rs/tracing#2983</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3130">#3130</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3130%5D(https://redirect.github.com/tokio-rs/tracing/issues/3130)">tokio-rs/tracing#3130</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3158">#3158</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3158%5D(https://redirect.github.com/tokio-rs/tracing/issues/3158)">tokio-rs/tracing#3158</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="64e1c8d3ae"><code>64e1c8d</code></a>
chore: prepare tracing 0.1.43 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3427">#3427</a>)</li>
<li><a
href="7c44f7bb21"><code>7c44f7b</code></a>
tracing: revert &quot;make <code>valueset</code> macro sanitary&quot;
(<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3425">#3425</a>)</li>
<li><a
href="cdaf661c13"><code>cdaf661</code></a>
chore: prepare tracing-mock 0.1.0-beta.2 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3422">#3422</a>)</li>
<li><a
href="a164fd3021"><code>a164fd3</code></a>
chore: prepare tracing-journald 0.3.2 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3421">#3421</a>)</li>
<li><a
href="405397b8cc"><code>405397b</code></a>
chore: prepare tracing-appender 0.2.4 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3420">#3420</a>)</li>
<li><a
href="a9eeed7394"><code>a9eeed7</code></a>
chore: prepare tracing-subscriber 0.3.21 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3419">#3419</a>)</li>
<li><a
href="5bd5505478"><code>5bd5505</code></a>
chore: prepare tracing 0.1.42 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3418">#3418</a>)</li>
<li><a
href="55086231ec"><code>5508623</code></a>
chore: prepare tracing-attributes 0.1.31 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3417">#3417</a>)</li>
<li><a
href="d92b4c0feb"><code>d92b4c0</code></a>
chore: prepare tracing-core 0.1.35 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3414">#3414</a>)</li>
<li><a
href="9751b6e776"><code>9751b6e</code></a>
chore: run <code>tracing-subscriber</code> tests with all features (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3412">#3412</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tracing/compare/tracing-0.1.41...tracing-0.1.43">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing&package-manager=cargo&previous-version=0.1.41&new-version=0.1.43)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:45:16 +03:00
dependabot[bot]
cd5c7afbac build(deps): bump crate-ci/typos from 1.39.2 to 1.40.0 (#2244)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.39.2 to
1.40.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.40.0</h2>
<h2>[1.40.0] - 2025-11-26</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1405">November
2025</a> changes</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.40.0] - 2025-11-26</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1405">November
2025</a> changes</li>
</ul>
<h2>[1.39.2] - 2025-11-13</h2>
<h3>Fixes</h3>
<ul>
<li>Don't offer <code>entry</code> as a correction for
<code>entrys</code></li>
</ul>
<h2>[1.39.1] - 2025-11-12</h2>
<h3>Features</h3>
<ul>
<li>Make <code>--help</code> more vibrant</li>
</ul>
<h2>[1.39.0] - 2025-10-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1383">October
2025</a> changes</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>When a typo is pluralized, prefer pluralized corrections</li>
</ul>
<h2>[1.38.1] - 2025-10-07</h2>
<h3>Fixes</h3>
<ul>
<li>Ignore common golang identifiers</li>
</ul>
<h2>[1.38.0] - 2025-10-06</h2>
<h3>Features</h3>
<ul>
<li>Update type list</li>
</ul>
<h3>Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2d0ce569fe"><code>2d0ce56</code></a>
chore: Release</li>
<li><a
href="efbd900f8d"><code>efbd900</code></a>
chore: Release</li>
<li><a
href="863fd15db8"><code>863fd15</code></a>
docs: Update changelog</li>
<li><a
href="9a27b16791"><code>9a27b16</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1432">#1432</a>
from epage/nov</li>
<li><a
href="3dbd9d4eac"><code>3dbd9d4</code></a>
feat(dict): November additions</li>
<li><a
href="a1a16c7b7c"><code>a1a16c7</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1427">#1427</a>
from deining/bump-github-action</li>
<li><a
href="cb8d2e78ff"><code>cb8d2e7</code></a>
docs: Bump GitHub checkout action in 'github-action.md'</li>
<li><a
href="9f99fb8dfe"><code>9f99fb8</code></a>
docs(ref): Clarify extend-words / extend-identifiers</li>
<li>See full diff in <a
href="626c4bedb7...2d0ce569fe">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.39.2&new-version=1.40.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:44:57 +03:00
dependabot[bot]
604f89a167 build(deps): bump Swatinem/rust-cache from 2.8.1 to 2.8.2 (#2243)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from
2.8.1 to 2.8.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/swatinem/rust-cache/releases">Swatinem/rust-cache's
releases</a>.</em></p>
<blockquote>
<h2>v2.8.2</h2>
<h2>What's Changed</h2>
<ul>
<li>ci: address lint findings, add zizmor workflow by <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/262">Swatinem/rust-cache#262</a></li>
<li>feat: Implement ability to disable adding job ID + rust environment
hashes to cache names by <a
href="https://github.com/Ryan-Brice"><code>@​Ryan-Brice</code></a> in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/279">Swatinem/rust-cache#279</a></li>
<li>Don't overwrite env for cargo-metadata call by <a
href="https://github.com/MaeIsBad"><code>@​MaeIsBad</code></a> in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/285">Swatinem/rust-cache#285</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/woodruffw"><code>@​woodruffw</code></a>
made their first contribution in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/262">Swatinem/rust-cache#262</a></li>
<li><a
href="https://github.com/Ryan-Brice"><code>@​Ryan-Brice</code></a> made
their first contribution in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/279">Swatinem/rust-cache#279</a></li>
<li><a href="https://github.com/MaeIsBad"><code>@​MaeIsBad</code></a>
made their first contribution in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/285">Swatinem/rust-cache#285</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Swatinem/rust-cache/compare/v2.8.1...v2.8.2">https://github.com/Swatinem/rust-cache/compare/v2.8.1...v2.8.2</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md">Swatinem/rust-cache's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>2.8.2</h2>
<ul>
<li>Don't overwrite env for cargo-metadata call</li>
</ul>
<h2>2.8.1</h2>
<ul>
<li>Set empty <code>CARGO_ENCODED_RUSTFLAGS</code> when retrieving
metadata</li>
<li>Various dependency updates</li>
</ul>
<h2>2.8.0</h2>
<ul>
<li>Add support for <code>warpbuild</code> cache provider</li>
<li>Add new <code>cache-workspace-crates</code> feature</li>
</ul>
<h2>2.7.8</h2>
<ul>
<li>Include CPU arch in the cache key</li>
</ul>
<h2>2.7.7</h2>
<ul>
<li>Also cache <code>cargo install</code> metadata</li>
</ul>
<h2>2.7.6</h2>
<ul>
<li>Allow opting out of caching $CARGO_HOME/bin</li>
<li>Add runner OS in cache key</li>
<li>Adds an option to do lookup-only of the cache</li>
</ul>
<h2>2.7.5</h2>
<ul>
<li>Support Cargo.lock format cargo-lock v4</li>
<li>Only run macOsWorkaround() on macOS</li>
</ul>
<h2>2.7.3</h2>
<ul>
<li>Work around upstream problem that causes cache saving to hang for
minutes.</li>
</ul>
<h2>2.7.2</h2>
<ul>
<li>Only key by <code>Cargo.toml</code> and <code>Cargo.lock</code>
files of workspace members.</li>
</ul>
<h2>2.7.1</h2>
<ul>
<li>Update toml parser to fix parsing errors.</li>
</ul>
<h2>2.7.0</h2>
<ul>
<li>Properly cache <code>trybuild</code> tests.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="779680da71"><code>779680d</code></a>
2.8.2</li>
<li><a
href="2ea64efb25"><code>2ea64ef</code></a>
Bump smol-toml from 1.4.2 to 1.5.2 in the prd-minor group (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/287">#287</a>)</li>
<li><a
href="8930d9c33e"><code>8930d9c</code></a>
Bump the actions group with 3 updates (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/288">#288</a>)</li>
<li><a
href="c071727fc9"><code>c071727</code></a>
Bump <code>@​actions/io</code> from 1.1.3 to 2.0.0 in the prd-major
group (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/281">#281</a>)</li>
<li><a
href="f2a41b7c11"><code>f2a41b7</code></a>
Bump <code>@​types/node</code> from 24.9.0 to 24.10.0 in the dev-minor
group (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/282">#282</a>)</li>
<li><a
href="e306f83d21"><code>e306f83</code></a>
Don't overwrite env for cargo-metadata call (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/285">#285</a>)</li>
<li><a
href="c9119007a1"><code>c911900</code></a>
Merge pull request <a
href="https://redirect.github.com/swatinem/rust-cache/issues/284">#284</a>
from Swatinem/dependabot/github_actions/actions-baeb0...</li>
<li><a
href="3aaed5547e"><code>3aaed55</code></a>
Bump the actions group with 2 updates</li>
<li><a
href="972b315a82"><code>972b315</code></a>
Merge pull request <a
href="https://redirect.github.com/swatinem/rust-cache/issues/283">#283</a>
from Swatinem/dependabot/github_actions/actions-b360d...</li>
<li><a
href="07caf06f7a"><code>07caf06</code></a>
Bump taiki-e/install-action from 2.62.45 to 2.62.49 in the actions
group</li>
<li>Additional commits viewable in <a
href="f13886b937...779680da71">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Swatinem/rust-cache&package-manager=github_actions&previous-version=2.8.1&new-version=2.8.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:44:42 +03:00
dependabot[bot]
db40df4ed9 build(deps): bump tracing-subscriber from 0.3.20 to 0.3.22 (#2248)
Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from
0.3.20 to 0.3.22.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tracing/releases">tracing-subscriber's
releases</a>.</em></p>
<blockquote>
<h2>tracing-subscriber 0.3.22</h2>
<h4>Important</h4>
<p>The previous release [0.3.21] was yanked as it depended explicitly on
[tracing-0.1.42], which was yanked due to a breaking change (see <a
href="https://redirect.github.com/tokio-rs/tracing/issues/3424">#3424</a>
for
details). This release contains all the changes from the previous
release, plus
an update to the newer version of <code>tracing</code>.</p>
<h3>Changed</h3>
<ul>
<li><code>tracing</code>: updated to 0.1.43 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3427">#3427</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/3424">#3424</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3424">tokio-rs/tracing#3424</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3427">#3427</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/3427">tokio-rs/tracing#3427</a>
[0.3.21]: <a
href="https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.21">https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.21</a>
[tracing-0.1.42]: <a
href="https://github.com/tokio-rs/tracing/releases/tag/tracing-0.1.42">https://github.com/tokio-rs/tracing/releases/tag/tracing-0.1.42</a></p>
<h2>tracing-subscriber 0.3.21</h2>
<h3>Fixed</h3>
<ul>
<li>Change registry exit to decrement local span ref only (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3331">#3331</a>)</li>
<li>Make Layered propagate <code>on_register_dispatch</code> (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3379">#3379</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li><code>tracing</code>: updated to 0.1.42 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3418">#3418</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Remove <code>clone_span</code> on enter (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3289">#3289</a>)</li>
</ul>
<h3>Documented</h3>
<ul>
<li>Fix a few small things in the format module (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3339">#3339</a>)</li>
<li>Fix extra closing brace in layer docs (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3350">#3350</a>)</li>
<li>Fix link in <code>FmtSpan</code> docs (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3411">#3411</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tracing/issues/3289">#3289</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3289%5D(https://redirect.github.com/tokio-rs/tracing/issues/3289)">tokio-rs/tracing#3289</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3331">#3331</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3331%5D(https://redirect.github.com/tokio-rs/tracing/issues/3331)">tokio-rs/tracing#3331</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3339">#3339</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3339%5D(https://redirect.github.com/tokio-rs/tracing/issues/3339)">tokio-rs/tracing#3339</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3350">#3350</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3350%5D(https://redirect.github.com/tokio-rs/tracing/issues/3350)">tokio-rs/tracing#3350</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3379">#3379</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3379%5D(https://redirect.github.com/tokio-rs/tracing/issues/3379)">tokio-rs/tracing#3379</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3411">#3411</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3411%5D(https://redirect.github.com/tokio-rs/tracing/issues/3411)">tokio-rs/tracing#3411</a>
<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3418">#3418</a>:
<a
href="https://redirect.github.com/tokio-rs/tracing/pull/%5B#3418%5D(https://redirect.github.com/tokio-rs/tracing/issues/3418)">tokio-rs/tracing#3418</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="cc44064b3a"><code>cc44064</code></a>
chore: prepare tracing-subscriber 0.3.22 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3428">#3428</a>)</li>
<li><a
href="64e1c8d3ae"><code>64e1c8d</code></a>
chore: prepare tracing 0.1.43 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3427">#3427</a>)</li>
<li><a
href="7c44f7bb21"><code>7c44f7b</code></a>
tracing: revert &quot;make <code>valueset</code> macro sanitary&quot;
(<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3425">#3425</a>)</li>
<li><a
href="cdaf661c13"><code>cdaf661</code></a>
chore: prepare tracing-mock 0.1.0-beta.2 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3422">#3422</a>)</li>
<li><a
href="a164fd3021"><code>a164fd3</code></a>
chore: prepare tracing-journald 0.3.2 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3421">#3421</a>)</li>
<li><a
href="405397b8cc"><code>405397b</code></a>
chore: prepare tracing-appender 0.2.4 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3420">#3420</a>)</li>
<li><a
href="a9eeed7394"><code>a9eeed7</code></a>
chore: prepare tracing-subscriber 0.3.21 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3419">#3419</a>)</li>
<li><a
href="5bd5505478"><code>5bd5505</code></a>
chore: prepare tracing 0.1.42 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3418">#3418</a>)</li>
<li><a
href="55086231ec"><code>5508623</code></a>
chore: prepare tracing-attributes 0.1.31 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3417">#3417</a>)</li>
<li><a
href="d92b4c0feb"><code>d92b4c0</code></a>
chore: prepare tracing-core 0.1.35 (<a
href="https://redirect.github.com/tokio-rs/tracing/issues/3414">#3414</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.20...tracing-subscriber-0.3.22">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tracing-subscriber&package-manager=cargo&previous-version=0.3.20&new-version=0.3.22)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:44:00 +03:00
dependabot[bot]
fae7688ed8 build(deps): bump kasuari from 0.4.10 to 0.4.11 (#2249)
Bumps [kasuari](https://github.com/ratatui/kasuari) from 0.4.10 to
0.4.11.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/kasuari/releases">kasuari's
releases</a>.</em></p>
<blockquote>
<h2>v0.4.11</h2>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump actions/checkout from 5 to 6 in the
github-actions group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/42">#42</a>)</li>
<li><em>(deps)</em> bump hashbrown from 0.16.0 to 0.16.1 in the
rust-dependencies group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/43">#43</a>)</li>
<li>enable trusted publishing and normalize release-plz workflow (<a
href="https://redirect.github.com/ratatui/kasuari/pull/44">#44</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/kasuari/blob/main/CHANGELOG.md">kasuari's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/ratatui/kasuari/compare/v0.4.10...v0.4.11">0.4.11</a>
- 2025-11-29</h2>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump actions/checkout from 5 to 6 in the
github-actions group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/42">#42</a>)</li>
<li><em>(deps)</em> bump hashbrown from 0.16.0 to 0.16.1 in the
rust-dependencies group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/43">#43</a>)</li>
<li>enable trusted publishing and normalize release-plz workflow (<a
href="https://redirect.github.com/ratatui/kasuari/pull/44">#44</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="dfde5428e6"><code>dfde542</code></a>
chore: release v0.4.11 (<a
href="https://redirect.github.com/ratatui/kasuari/issues/45">#45</a>)</li>
<li><a
href="e0143cfc9a"><code>e0143cf</code></a>
build(deps): bump actions/checkout from 5 to 6 in the github-actions
group (<a
href="https://redirect.github.com/ratatui/kasuari/issues/42">#42</a>)</li>
<li><a
href="87b93a0dde"><code>87b93a0</code></a>
build(deps): bump hashbrown from 0.16.0 to 0.16.1 in the
rust-dependencies gr...</li>
<li><a
href="f8fd0abdcb"><code>f8fd0ab</code></a>
chore: enable trusted publishing and normalize release-plz workflow (<a
href="https://redirect.github.com/ratatui/kasuari/issues/44">#44</a>)</li>
<li><a
href="376ec2bb56"><code>376ec2b</code></a>
build(deps): bump document-features from 0.2.11 to 0.2.12 in the
rust-depende...</li>
<li>See full diff in <a
href="https://github.com/ratatui/kasuari/compare/v0.4.10...v0.4.11">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=kasuari&package-manager=cargo&previous-version=0.4.10&new-version=0.4.11)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:43:29 +03:00
dependabot[bot]
2c17beaee4 build(deps): bump fakeit from 1.3.1 to 1.4.0 (#2250)
Bumps [fakeit](https://github.com/PumpkinSeed/fakeit) from 1.3.1 to
1.4.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f33e977442"><code>f33e977</code></a>
Bump version in cargo lock</li>
<li><a
href="d3ccee7287"><code>d3ccee7</code></a>
Bump the version</li>
<li><a
href="3844cbc04c"><code>3844cbc</code></a>
Merge pull request <a
href="https://redirect.github.com/PumpkinSeed/fakeit/issues/37">#37</a>
from joshka/joshka/push-xvwtqpvvsnvx</li>
<li><a
href="c33ef2828e"><code>c33ef28</code></a>
remove libmath and its stale rand deps</li>
<li><a
href="0821f8c368"><code>0821f8c</code></a>
Cargo.lock bump</li>
<li><a
href="785ef4d27a"><code>785ef4d</code></a>
Bump version</li>
<li><a
href="c56643d4a0"><code>c56643d</code></a>
Merge pull request <a
href="https://redirect.github.com/PumpkinSeed/fakeit/issues/36">#36</a>
from PumpkinSeed/rustfmt</li>
<li><a
href="8f272d7a6d"><code>8f272d7</code></a>
Change the MSRV</li>
<li><a
href="114d603f1c"><code>114d603</code></a>
Rustfmt</li>
<li><a
href="144b618085"><code>144b618</code></a>
Bump the version</li>
<li>Additional commits viewable in <a
href="https://github.com/PumpkinSeed/fakeit/compare/v1.3.1...v1.4.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=fakeit&package-manager=cargo&previous-version=1.3.1&new-version=1.4.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 17:43:05 +03:00
Josh McKinney
24e3133456 feat: add Rect::resize() method (#2240)
Fixes: https://github.com/ratatui/ratatui/issues/1440
2025-11-30 12:00:03 -08:00
Josh McKinney
96d097ef76 feat: implement Rect ops for moving (#1596)
feat: implement Rect ops for moving

Implemented `Add`, `AddAssign`, `Sub`, and `SubAssign` on `Rect` for
`Offset`. This makes it possible to move rects

```rust
let rect = Rect::new(1, 2, 3, 4);
let moved = rect + Offset(1, 2);
let moved = rect - Offset(1, 2);
let moved = rect + Offset(-1, -2);
```

Additionally Rect, Size, Offset, and Position now all have MIN and MAX
consts.
2025-11-30 11:57:08 -08:00
dependabot[bot]
a6356c157c build(deps): bump octocrab from 0.47.1 to 0.48.0 (#2230)
Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.47.1 to
0.48.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.48.0</h2>
<h3>Added</h3>
<ul>
<li>fetch contributor repository permission (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/825">#825</a>)</li>
<li>[<strong>breaking</strong>] Use
<code>Option&lt;AuthorAssociation&gt;</code> over <code>String</code> in
<code>Issue</code> struct (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/822">#822</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>add missing issue event types (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/821">#821</a>)</li>
<li>Remove fields deleted in October 2025 API changes (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/826">#826</a>)</li>
<li>Bump jsonwebtoken to v10 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/814">#814</a>)</li>
<li>Feature/set http headers <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/808">#808</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/819">#819</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.47.1...v0.48.0">0.48.0</a>
- 2025-11-18</h2>
<h3>Added</h3>
<ul>
<li>fetch contributor repository permission (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/825">#825</a>)</li>
<li>[<strong>breaking</strong>] Use
<code>Option&lt;AuthorAssociation&gt;</code> over <code>String</code> in
<code>Issue</code> struct (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/822">#822</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>add missing issue event types (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/821">#821</a>)</li>
<li>Remove fields deleted in October 2025 API changes (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/826">#826</a>)</li>
<li>Bump jsonwebtoken to v10 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/814">#814</a>)</li>
<li>Feature/set http headers <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/808">#808</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/819">#819</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9fc79f7bef"><code>9fc79f7</code></a>
chore: release v0.48.0 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/823">#823</a>)</li>
<li><a
href="819a1f1a44"><code>819a1f1</code></a>
models: add missing issue event types (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/821">#821</a>)</li>
<li><a
href="730b70f1a9"><code>730b70f</code></a>
Remove fields deleted in October 2025 API changes (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/826">#826</a>)</li>
<li><a
href="8cecdae759"><code>8cecdae</code></a>
Bump jsonwebtoken to v10 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/814">#814</a>)</li>
<li><a
href="8be15f41ef"><code>8be15f4</code></a>
feat: fetch contributor repository permission (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/825">#825</a>)</li>
<li><a
href="610775a98d"><code>610775a</code></a>
Feature/set http headers <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/808">#808</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/819">#819</a>)</li>
<li><a
href="edc6cdefc4"><code>edc6cde</code></a>
feat!: Use <code>Option\&lt;AuthorAssociation&gt;</code> over
<code>String</code> in <code>Issue</code> struct (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/822">#822</a>)</li>
<li>See full diff in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.47.1...v0.48.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.47.1&new-version=0.48.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh McKinney <joshka@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-11-30 01:36:19 -08:00
Josh McKinney
0fbefe9389 chore(ci): don't fail on cargo-deny advisories (#2237)
Instead of failing on advisories, run the cargo-deny check, and report
the failure.

Uses the cargo-deny-action instead of installing this manually.


https://github.com/EmbarkStudios/cargo-deny-action/tree/v2?tab=readme-ov-file#recommended-pipeline-if-using-advisories-to-avoid-sudden-breakages
(bumped to use rust stable, and log level info)
2025-11-30 12:26:16 +03:00
dependabot[bot]
12c49c0eac build(deps): bump DavidAnson/markdownlint-cli2-action from 20.0.0 to 21.0.0 (#2207)
Bumps
[DavidAnson/markdownlint-cli2-action](https://github.com/davidanson/markdownlint-cli2-action)
from 20.0.0 to 21.0.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="30a0e04f18"><code>30a0e04</code></a>
Update to version 21.0.0.</li>
<li><a
href="6d4a055237"><code>6d4a055</code></a>
Freshen generated index.js file.</li>
<li><a
href="d9bf3fbe88"><code>d9bf3fb</code></a>
Bump markdownlint-cli2 from 0.18.1 to 0.19.0</li>
<li><a
href="29b4789128"><code>29b4789</code></a>
Bump <code>@​eslint/js</code> from 9.39.0 to 9.39.1</li>
<li><a
href="6d600f113b"><code>6d600f1</code></a>
Bump eslint from 9.39.0 to 9.39.1</li>
<li><a
href="15b21a00af"><code>15b21a0</code></a>
Bump <code>@​eslint/js</code> from 9.38.0 to 9.39.0</li>
<li><a
href="b259d54d28"><code>b259d54</code></a>
Bump eslint from 9.38.0 to 9.39.0</li>
<li><a
href="451cad2cde"><code>451cad2</code></a>
Bump eslint-plugin-unicorn from 61.0.2 to 62.0.0</li>
<li><a
href="c076bbe50e"><code>c076bbe</code></a>
Bump <code>@​stylistic/eslint-plugin</code> from 5.4.0 to 5.5.0</li>
<li><a
href="ef464f44a2"><code>ef464f4</code></a>
Bump <code>@​eslint/js</code> from 9.37.0 to 9.38.0</li>
<li>Additional commits viewable in <a
href="992badcdf2...30a0e04f18">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=DavidAnson/markdownlint-cli2-action&package-manager=github_actions&previous-version=20.0.0&new-version=21.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh McKinney <joshka@users.noreply.github.com>
2025-11-29 15:55:16 -08:00
Serge Barral
f18bcbf06b feat(canvas)!: Add quadrant, sextant and octant markers (#2235)
The octant marker is an alternative to the Braille marker with the same
resolution, but offering densely packed, regular pseudo-pixels, without
visible bands between rows and columns. 

Quadrant and Sextants are also added to support 2x2 and 2x3.

Sextant and Octant unicode characters that are less widely supported at
the moment, which is why `Braille` was left as the default.

BREAKING CHANGE: addition of new variants to `Marker` and removal of
no longer used constants in `ratatui::symbols::braille`.
2025-11-29 15:37:53 -08:00
Jagoda Estera Ślązak
ee673476d3 feat(symbols)!: Make Marker non-exhaustive (#2236)
This will allow us to add new markers without causing further breaking
changes.

BREAKING CHANGE: `Marker` is now non-exhaustive
2025-11-29 10:35:30 +01:00
dependabot[bot]
3ba3735650 build(deps): bump termion from 4.0.5 to 4.0.6 (#2227)
Bumps termion from 4.0.5 to 4.0.6.


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=termion&package-manager=cargo&previous-version=4.0.5&new-version=4.0.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-28 18:07:57 +01:00
dependabot[bot]
bf268937d4 build(deps): bump dtolnay/rust-toolchain (#2233)
Bumps
[dtolnay/rust-toolchain](https://github.com/dtolnay/rust-toolchain) from
0f44b27771c32bda9f458f75a1e241b09791b331 to
0b1efabc08b657293548b77fb76cc02d26091c7e.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0b1efabc08"><code>0b1efab</code></a>
Update actions/checkout@v5 -&gt; v6</li>
<li>See full diff in <a
href="0f44b27771...0b1efabc08">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-11-25 09:27:20 +01:00
Jagoda Estera Ślązak
26b05dee59 feat(chart): Render Braille over Blocks in Charts and Canvas (#2165)
This makes it possible to stack charts, and write text over block symbols in
Charts and Canvas while still showing the block symbols behind the text.

Co-authored-by: Lunderberg <eldritch.cheese@gmail.com>
2025-11-25 09:23:54 +01:00
dependabot[bot]
3a945dfe06 build(deps): bump actions/checkout from 5.0.0 to 6.0.0 (#2232)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0
to 6.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
<li>update readme/changelog for v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2311">actions/checkout#2311</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5.0.0...v6.0.0">https://github.com/actions/checkout/compare/v5.0.0...v6.0.0</a></p>
<h2>v6-beta</h2>
<h2>What's Changed</h2>
<p>Updated persist-credentials to store the credentials under
<code>$RUNNER_TEMP</code> instead of directly in the local git
config.</p>
<p>This requires a minimum Actions Runner version of <a
href="https://github.com/actions/runner/releases/tag/v2.329.0">v2.329.0</a>
to access the persisted credentials for <a
href="https://docs.github.com/en/actions/tutorials/use-containerized-services/create-a-docker-container-action">Docker
container action</a> scenarios.</p>
<h2>v5.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5...v5.0.1">https://github.com/actions/checkout/compare/v5...v5.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>V5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1af3b93b68"><code>1af3b93</code></a>
update readme/changelog for v6 (<a
href="https://redirect.github.com/actions/checkout/issues/2311">#2311</a>)</li>
<li><a
href="71cf2267d8"><code>71cf226</code></a>
v6-beta (<a
href="https://redirect.github.com/actions/checkout/issues/2298">#2298</a>)</li>
<li><a
href="069c695914"><code>069c695</code></a>
Persist creds to a separate file (<a
href="https://redirect.github.com/actions/checkout/issues/2286">#2286</a>)</li>
<li><a
href="ff7abcd0c3"><code>ff7abcd</code></a>
Update README to include Node.js 24 support details and requirements (<a
href="https://redirect.github.com/actions/checkout/issues/2248">#2248</a>)</li>
<li>See full diff in <a
href="08c6903cd8...1af3b93b68">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=5.0.0&new-version=6.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-11-24 19:28:25 +03:00
dependabot[bot]
8f6782acd5 build(deps): bump hashbrown from 0.16.0 to 0.16.1 (#2228)
Bumps [hashbrown](https://github.com/rust-lang/hashbrown) from 0.16.0 to
0.16.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rust-lang/hashbrown/releases">hashbrown's
releases</a>.</em></p>
<blockquote>
<h2>v0.16.1</h2>
<h3>Added</h3>
<ul>
<li>Added <code>HashTable</code> methods related to the raw bucket index
(<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/657">#657</a>)</li>
<li>Added <code>VacantEntryRef::insert_with_key</code> (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/579">#579</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Removed specialization for <code>Copy</code> types (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/662">#662</a>)</li>
<li>The <code>get_many_mut</code> family of methods have been renamed to
<code>get_disjoint_mut</code>
to match the standard library. The old names are still present for now,
but
deprecated. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/648">#648</a>)</li>
<li>Recognize and use over-sized allocations when using custom
allocators. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/523">#523</a>)</li>
<li>Depend on <code>serde_core</code> instead of <code>serde</code>. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/649">#649</a>)</li>
<li>Optimized <code>collect</code> on rayon parallel iterators. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/652">#652</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md">hashbrown's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/rust-lang/hashbrown/compare/v0.16.0...v0.16.1">0.16.1</a>
- 2025-11-20</h2>
<h3>Added</h3>
<ul>
<li>Added <code>HashTable</code> methods related to the raw bucket index
(<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/657">#657</a>)</li>
<li>Added <code>VacantEntryRef::insert_with_key</code> (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/579">#579</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>Removed specialization for <code>Copy</code> types (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/662">#662</a>)</li>
<li>The <code>get_many_mut</code> family of methods have been renamed to
<code>get_disjoint_mut</code>
to match the standard library. The old names are still present for now,
but
deprecated. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/648">#648</a>)</li>
<li>Recognize and use over-sized allocations when using custom
allocators. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/523">#523</a>)</li>
<li>Depend on <code>serde_core</code> instead of <code>serde</code>. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/649">#649</a>)</li>
<li>Optimized <code>collect</code> on rayon parallel iterators. (<a
href="https://redirect.github.com/rust-lang/hashbrown/issues/652">#652</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1876e4f027"><code>1876e4f</code></a>
Add PR link for <code>get_disjoint_mut</code> rename</li>
<li><a
href="2e363b6f12"><code>2e363b6</code></a>
Update CHANGELOG for version 0.16.1</li>
<li><a
href="88d54a540f"><code>88d54a5</code></a>
chore: release v0.16.1</li>
<li><a
href="21be06c3ac"><code>21be06c</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/hashbrown/issues/657">#657</a>
from cuviper/table-bucket</li>
<li><a
href="af971f3735"><code>af971f3</code></a>
Add <code>T</code> to bucket iterators and inline their methods</li>
<li><a
href="7ccb6d6ffc"><code>7ccb6d6</code></a>
Add <code>HashTable::iter_buckets</code> and
<code>iter_hash_buckets</code></li>
<li><a
href="aeb7996601"><code>aeb7996</code></a>
Add <code>HashTable::get_bucket_entry_unchecked</code></li>
<li><a
href="e885a4ea47"><code>e885a4e</code></a>
<code>get_bucket_entry -&gt; Result\&lt;OccupiedEntry,
AbsentEntry&gt;</code></li>
<li><a
href="dabfbef806"><code>dabfbef</code></a>
Add <code>get_bucket_unchecked</code> and
<code>get_bucket_unchecked_mut</code></li>
<li><a
href="42d9377a3f"><code>42d9377</code></a>
Make <code>HashTable</code> entries use <code>Tag</code> instead of a
full hash</li>
<li>Additional commits viewable in <a
href="https://github.com/rust-lang/hashbrown/compare/v0.16.0...v0.16.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hashbrown&package-manager=cargo&previous-version=0.16.0&new-version=0.16.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-11-24 19:27:54 +03:00
dependabot[bot]
dd6d315c7b build(deps): bump zizmorcore/zizmor-action from 0.2.0 to 0.3.0 (#2231)
Bumps
[zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action)
from 0.2.0 to 0.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/zizmorcore/zizmor-action/releases">zizmorcore/zizmor-action's
releases</a>.</em></p>
<blockquote>
<h2>v0.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>README: fix troubleshooting link by <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> in <a
href="https://redirect.github.com/zizmorcore/zizmor-action/pull/50">zizmorcore/zizmor-action#50</a></li>
<li>README: add a troubleshooting section about Advanced Security by <a
href="https://github.com/woodruffw"><code>@​woodruffw</code></a> in <a
href="https://redirect.github.com/zizmorcore/zizmor-action/pull/51">zizmorcore/zizmor-action#51</a></li>
<li>feat: Support a config option by <a
href="https://github.com/naokihaba"><code>@​naokihaba</code></a> in <a
href="https://redirect.github.com/zizmorcore/zizmor-action/pull/56">zizmorcore/zizmor-action#56</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/naokihaba"><code>@​naokihaba</code></a>
made their first contribution in <a
href="https://redirect.github.com/zizmorcore/zizmor-action/pull/56">zizmorcore/zizmor-action#56</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/zizmorcore/zizmor-action/compare/v0.2.0...v0.3.0">https://github.com/zizmorcore/zizmor-action/compare/v0.2.0...v0.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e639db9933"><code>e639db9</code></a>
remove mise.toml (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/57">#57</a>)</li>
<li><a
href="f4409e3039"><code>f4409e3</code></a>
feat: Support a config option (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/56">#56</a>)</li>
<li><a
href="1aba86d8e1"><code>1aba86d</code></a>
chore(deps): bump github/codeql-action in the github-actions group (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/54">#54</a>)</li>
<li><a
href="da5ac40c54"><code>da5ac40</code></a>
README: add a troubleshooting section about Advanced Security (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/51">#51</a>)</li>
<li><a
href="cc28a584f0"><code>cc28a58</code></a>
README: fix troubleshooting link (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/50">#50</a>)</li>
<li><a
href="c323c83e3a"><code>c323c83</code></a>
chore(deps): bump zizmorcore/zizmor-action from 0.1.2 to 0.2.0 in the
github-...</li>
<li><a
href="0696496a48"><code>0696496</code></a>
chore(deps): bump github/codeql-action in the github-actions group (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/48">#48</a>)</li>
<li><a
href="873539476a"><code>8735394</code></a>
docs: bump action pins (<a
href="https://redirect.github.com/zizmorcore/zizmor-action/issues/46">#46</a>)</li>
<li>See full diff in <a
href="e673c3917a...e639db9933">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=zizmorcore/zizmor-action&package-manager=github_actions&previous-version=0.2.0&new-version=0.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 19:02:14 +03:00
dependabot[bot]
fe410c6645 build(deps): bump clap from 4.5.51 to 4.5.53 (#2229)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.51 to 4.5.53.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/releases">clap's
releases</a>.</em></p>
<blockquote>
<h2>v4.5.53</h2>
<h2>[4.5.53] - 2025-11-19</h2>
<h3>Features</h3>
<ul>
<li>Add <code>default_values_if</code>,
<code>default_values_ifs</code></li>
</ul>
<h2>v4.5.52</h2>
<h2>[4.5.52] - 2025-11-17</h2>
<h3>Fixes</h3>
<ul>
<li>Don't panic when <code>args_conflicts_with_subcommands</code>
conflicts with an <code>ArgGroup</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/blob/master/CHANGELOG.md">clap's
changelog</a>.</em></p>
<blockquote>
<h2>[4.5.53] - 2025-11-19</h2>
<h3>Features</h3>
<ul>
<li>Add <code>default_values_if</code>,
<code>default_values_ifs</code></li>
</ul>
<h2>[4.5.52] - 2025-11-17</h2>
<h3>Fixes</h3>
<ul>
<li>Don't panic when <code>args_conflicts_with_subcommands</code>
conflicts with an <code>ArgGroup</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3716f9f428"><code>3716f9f</code></a>
chore: Release</li>
<li><a
href="613b69a6b7"><code>613b69a</code></a>
docs: Update changelog</li>
<li><a
href="d117f7acde"><code>d117f7a</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6028">#6028</a>
from epage/arg</li>
<li><a
href="cb8255d2f3"><code>cb8255d</code></a>
feat(builder): Allow quoted id's for arg macro</li>
<li><a
href="1036060f13"><code>1036060</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6025">#6025</a>
from AldaronLau/typos-in-faq</li>
<li><a
href="2fcafc0aee"><code>2fcafc0</code></a>
docs: Fix minor grammar issues in FAQ</li>
<li><a
href="a380b65fe9"><code>a380b65</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6023">#6023</a>
from epage/template</li>
<li><a
href="4d7ab1483c"><code>4d7ab14</code></a>
chore: Update from _rust/main template</li>
<li><a
href="b8a7ea49d9"><code>b8a7ea4</code></a>
chore(deps): Update Rust Stable to v1.87 (<a
href="https://redirect.github.com/clap-rs/clap/issues/18">#18</a>)</li>
<li><a
href="f9842b3b3f"><code>f9842b3</code></a>
chore: Avoid MSRV problems out of the box</li>
<li>Additional commits viewable in <a
href="https://github.com/clap-rs/clap/compare/clap_complete-v4.5.51...clap_complete-v4.5.53">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=clap&package-manager=cargo&previous-version=4.5.51&new-version=4.5.53)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 19:00:45 +03:00
dependabot[bot]
5895340cb3 build(deps): bump taiki-e/install-action from 2.62.52 to 2.62.57 (#2234)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.52 to 2.62.57.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.57</h2>
<ul>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.18.6.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.5.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.2.</p>
</li>
</ul>
<h2>2.62.56</h2>
<ul>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.4.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.72.0.</p>
</li>
</ul>
<h2>2.62.55</h2>
<ul>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.1.</p>
</li>
<li>
<p>Update <code>editorconfig-checker@latest</code> to 3.5.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.11.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 39.0.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.7.</p>
</li>
<li>
<p>Update <code>mdbook@latest</code> to 0.5.1.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.3.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.114.</p>
</li>
</ul>
<h2>2.62.54</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.6.</p>
</li>
<li>
<p>Update <code>hyperfine@latest</code> to 1.20.0.</p>
</li>
</ul>
<h2>2.62.53</h2>
<ul>
<li>
<p>Update <code>mdbook@latest</code> to 0.5.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.10.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.38.0.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.62.57] - 2025-11-24</h2>
<ul>
<li>
<p>Update <code>cargo-deny@latest</code> to 0.18.6.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.5.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.2.</p>
</li>
</ul>
<h2>[2.62.56] - 2025-11-23</h2>
<ul>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.4.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.72.0.</p>
</li>
</ul>
<h2>[2.62.55] - 2025-11-21</h2>
<ul>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.1.</p>
</li>
<li>
<p>Update <code>editorconfig-checker@latest</code> to 3.5.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.11.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 39.0.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.7.</p>
</li>
<li>
<p>Update <code>mdbook@latest</code> to 0.5.1.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.3.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.114.</p>
</li>
</ul>
<h2>[2.62.54] - 2025-11-19</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.6.</p>
</li>
<li>
<p>Update <code>hyperfine@latest</code> to 1.20.0.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="763e3324d4"><code>763e332</code></a>
Release 2.62.57</li>
<li><a
href="4af8b97fbd"><code>4af8b97</code></a>
Update <code>cargo-deny@latest</code> to 0.18.6</li>
<li><a
href="a35850f875"><code>a35850f</code></a>
Update <code>cargo-shear@latest</code> to 1.6.5</li>
<li><a
href="810fa5b442"><code>810fa5b</code></a>
Update <code>cargo-binstall@latest</code> to 1.16.2</li>
<li><a
href="f79fe7514d"><code>f79fe75</code></a>
Release 2.62.56</li>
<li><a
href="35828c1ac9"><code>35828c1</code></a>
Update <code>cargo-shear@latest</code> to 1.6.4</li>
<li><a
href="6de94973ee"><code>6de9497</code></a>
Update <code>rclone@latest</code> to 1.72.0</li>
<li><a
href="132c875eef"><code>132c875</code></a>
Release 2.62.55</li>
<li><a
href="560f08d34e"><code>560f08d</code></a>
Update <code>cargo-binstall@latest</code> to 1.16.1</li>
<li><a
href="fcce1e7255"><code>fcce1e7</code></a>
Update <code>editorconfig-checker@latest</code> to 3.5.0</li>
<li>Additional commits viewable in <a
href="537c30d2b4...763e3324d4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.52&new-version=2.62.57)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 18:55:17 +03:00
Josh McKinney
e869cb9750 feat: add Size::area() (#2226)
Add Size::area() returning u32 to avoid u16 overflow
Fixes https://github.com/ratatui/ratatui/issues/2204
2025-11-24 10:09:31 +03:00
Paul Harrison
b1d47e7718 docs: Discourage use of Buffer's pos_of, index_of (#2225)
These methods assume that the backing store of any buffer / area is linearly indexable. There are other ways that we might want to experiment in the future with how to store the values (trees, 2D allocated areas that are non-contiguous etc.). The index <-> pos conversion there isn't particularly useful. This should be an internal implementation detail of the buffer, rather than something that we expose, but we're not deprecating this for now at least.
2025-11-23 20:22:13 -08:00
WaterWhisperer
94ba82e9ca test(gauge): add benchmarks for gauge (#2221) 2025-11-23 11:37:55 -08:00
Orhun Parmaksız
500f6c5a52 chore(deps): bump fakeit to 1.3.1 (#2218)
fixes #2215
2025-11-22 14:03:16 -08:00
0xb002f0
b6588fd1fa feat: implement From<Size> for (u16, u16) (#2223) 2025-11-22 13:52:10 -08:00
Paul Harrison
c7c3498025 refactor: use saturating_add in Rect::new (#2216) 2025-11-19 21:06:27 -08:00
Matthias Beyer
b65788ce14 docs(examples): remove duplicated link (#2212) 2025-11-18 19:33:37 +03:00
dependabot[bot]
5d0a362f3e build(deps): bump crate-ci/typos from 1.39.0 to 1.39.2 (#2208)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.39.0 to
1.39.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.39.2</h2>
<h2>[1.39.2] - 2025-11-13</h2>
<h3>Fixes</h3>
<ul>
<li>Don't offer <code>entry</code> as a correction for
<code>entrys</code></li>
</ul>
<h2>v1.39.1</h2>
<h2>[1.39.1] - 2025-11-12</h2>
<h3>Features</h3>
<ul>
<li>Make <code>--help</code> more vibrant</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.39.2] - 2025-11-13</h2>
<h3>Fixes</h3>
<ul>
<li>Don't offer <code>entry</code> as a correction for
<code>entrys</code></li>
</ul>
<h2>[1.39.1] - 2025-11-12</h2>
<h3>Features</h3>
<ul>
<li>Make <code>--help</code> more vibrant</li>
</ul>
<h2>[1.39.0] - 2025-10-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1383">October
2025</a> changes</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>When a typo is pluralized, prefer pluralized corrections</li>
</ul>
<h2>[1.38.1] - 2025-10-07</h2>
<h3>Fixes</h3>
<ul>
<li>Ignore common golang identifiers</li>
</ul>
<h2>[1.38.0] - 2025-10-06</h2>
<h3>Features</h3>
<ul>
<li>Update type list</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>typ</code></li>
<li>Consistently error on unused config fields</li>
</ul>
<h2>[1.37.3] - 2025-10-06</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="626c4bedb7"><code>626c4be</code></a>
chore: Release</li>
<li><a
href="c6b458db05"><code>c6b458d</code></a>
docs: Update changelog</li>
<li><a
href="eed04198a6"><code>eed0419</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1423">#1423</a>
from epage/entrys</li>
<li><a
href="40383f41a2"><code>40383f4</code></a>
fix(dict): Don't offer 'entry' as a correction for 'entrys'</li>
<li><a
href="1af53e3774"><code>1af53e3</code></a>
chore: Release</li>
<li><a
href="e5d291b81a"><code>e5d291b</code></a>
docs: Update changelog</li>
<li><a
href="55474f5ff9"><code>55474f5</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1417">#1417</a>
from starsep/colorful_help</li>
<li><a
href="78b9375950"><code>78b9375</code></a>
feat: Enable colors for typos --help</li>
<li><a
href="308f8f5788"><code>308f8f5</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1409">#1409</a>
from crate-ci/renovate/actions-download-artifact-6.x</li>
<li><a
href="cf03418f50"><code>cf03418</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1410">#1410</a>
from crate-ci/renovate/actions-setup-python-6.x</li>
<li>Additional commits viewable in <a
href="07d900b8fa...626c4bedb7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.39.0&new-version=1.39.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 18:32:32 +03:00
dependabot[bot]
7762effd93 build(deps): bump taiki-e/install-action from 2.62.49 to 2.62.52 (#2206)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.49 to 2.62.52.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.52</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.113.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.5.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.3.</p>
</li>
</ul>
<h2>2.62.51</h2>
<ul>
<li>
<p>Update <code>typos@latest</code> to 1.39.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.4.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.9.</p>
</li>
<li>
<p>Update <code>protoc@latest</code> to 3.33.1.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.43.1.</p>
</li>
</ul>
<h2>2.62.50</h2>
<ul>
<li>
<p>Update <code>wasmtime@latest</code> to 38.0.4.</p>
</li>
<li>
<p>Update <code>coreutils@latest</code> to 0.4.0.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.62.52] - 2025-11-17</h2>
<ul>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.113.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.16.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.5.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.3.</p>
</li>
</ul>
<h2>[2.62.51] - 2025-11-14</h2>
<ul>
<li>
<p>Update <code>typos@latest</code> to 1.39.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.4.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.9.</p>
</li>
<li>
<p>Update <code>protoc@latest</code> to 3.33.1.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.43.1.</p>
</li>
</ul>
<h2>[2.62.50] - 2025-11-12</h2>
<ul>
<li>
<p>Update <code>wasmtime@latest</code> to 38.0.4.</p>
</li>
<li>
<p>Update <code>coreutils@latest</code> to 0.4.0.</p>
</li>
</ul>
<h2>[2.62.49] - 2025-11-09</h2>
<ul>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.11.</p>
</li>
<li>
<p>Update <code>cargo-auditable@latest</code> to 0.7.2.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.2.</p>
</li>
</ul>
<h2>[2.62.48] - 2025-11-08</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="537c30d2b4"><code>537c30d</code></a>
Release 2.62.52</li>
<li><a
href="6881535782"><code>6881535</code></a>
Update <code>cargo-nextest@latest</code> to 0.9.113</li>
<li><a
href="4b1e2228ab"><code>4b1e222</code></a>
Update <code>cargo-binstall@latest</code> to 1.16.0</li>
<li><a
href="28efaede1c"><code>28efaed</code></a>
Update <code>mise@latest</code> to 2025.11.5</li>
<li><a
href="b9f2331284"><code>b9f2331</code></a>
Update <code>cargo-shear@latest</code> to 1.6.3</li>
<li><a
href="0be4756f42"><code>0be4756</code></a>
Release 2.62.51</li>
<li><a
href="e1c1ebb6a3"><code>e1c1ebb</code></a>
Update changelog</li>
<li><a
href="d78637d17c"><code>d78637d</code></a>
Update <code>typos@latest</code> to 1.39.2</li>
<li><a
href="107556f337"><code>107556f</code></a>
Update <code>mise@latest</code> to 2025.11.4</li>
<li><a
href="2913759b20"><code>2913759</code></a>
Update <code>uv@latest</code> to 0.9.9</li>
<li>Additional commits viewable in <a
href="44c6d64aa6...537c30d2b4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.49&new-version=2.62.52)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 18:32:01 +03:00
dependabot[bot]
718dcd6ccb build(deps): bump dtolnay/rust-toolchain from 6d653acede28d24f02e3cd41383119e8b1b35921 to 0f44b27771c32bda9f458f75a1e241b09791b331 (#2205)
Bumps
[dtolnay/rust-toolchain](https://github.com/dtolnay/rust-toolchain) from
6d653acede28d24f02e3cd41383119e8b1b35921 to
0f44b27771c32bda9f458f75a1e241b09791b331.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="0f44b27771"><code>0f44b27</code></a>
Add 1.91.1 patch release</li>
<li>See full diff in <a
href="6d653acede...0f44b27771">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 18:31:12 +03:00
Josh McKinney
1dc18bf3cf feat(calendar): add width and height functions (#2198)
Fixes https://github.com/ratatui/ratatui/issues/2016

---------

Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
2025-11-15 16:04:46 -08:00
b-guild
90a77aaf8b feat(Direction): add Direction::perpendicular(self) (#2197) 2025-11-11 21:15:58 -08:00
dependabot[bot]
d709b0380f build(deps): bump duct from 1.1.0 to 1.1.1 (#2192)
Bumps [duct](https://github.com/oconnor663/duct.rs) from 1.1.0 to 1.1.1.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9414b8ff71"><code>9414b8f</code></a>
version 1.1.1</li>
<li><a
href="5436d0838b"><code>5436d08</code></a>
fix test_pipe_inheritance on macOS</li>
<li><a
href="0348c93566"><code>0348c93</code></a>
test_pipe_inheritance (failing on macOS)</li>
<li>See full diff in <a
href="https://github.com/oconnor663/duct.rs/compare/1.1.0...1.1.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=duct&package-manager=cargo&previous-version=1.1.0&new-version=1.1.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-11 11:24:09 +03:00
dependabot[bot]
f8c1006058 build(deps): bump octocrab from 0.47.0 to 0.47.1 (#2193)
[//]: # (dependabot-start)
⚠️  **Dependabot is rebasing this PR** ⚠️ 

Rebasing might not happen immediately, so don't worry if this takes some
time.

Note: if you make any changes to this PR yourself, they will take
precedence over the rebase.

---

[//]: # (dependabot-end)

Bumps [octocrab](https://github.com/XAMPPRocky/octocrab) from 0.47.0 to
0.47.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/releases">octocrab's
releases</a>.</em></p>
<blockquote>
<h2>v0.47.1</h2>
<h3>Added</h3>
<ul>
<li>add missing list workflows filters (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/820">#820</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>Modify <code>_put</code> method documentation (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/818">#818</a>)</li>
<li>Feature/interactions 537 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/817">#817</a>)</li>
<li>Added Feature/classrooms <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/524">#524</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/815">#815</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/XAMPPRocky/octocrab/blob/main/CHANGELOG.md">octocrab's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.47.0...v0.47.1">0.47.1</a>
- 2025-11-03</h2>
<h3>Added</h3>
<ul>
<li>add missing list workflows filters (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/820">#820</a>)</li>
</ul>
<h3>Other</h3>
<ul>
<li>Modify <code>_put</code> method documentation (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/818">#818</a>)</li>
<li>Feature/interactions 537 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/817">#817</a>)</li>
<li>Added Feature/classrooms <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/524">#524</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/pull/815">#815</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="6e4ae2659e"><code>6e4ae26</code></a>
chore: release v0.47.1 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/816">#816</a>)</li>
<li><a
href="8114a6bc42"><code>8114a6b</code></a>
feat: add missing list workflows filters (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/820">#820</a>)</li>
<li><a
href="8918c90564"><code>8918c90</code></a>
docs: Modify <code>_put</code> method documentation (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/818">#818</a>)</li>
<li><a
href="14a95d00f4"><code>14a95d0</code></a>
Feature/interactions 537 (<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/817">#817</a>)</li>
<li><a
href="e95fc40ddd"><code>e95fc40</code></a>
Added Feature/classrooms <a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/524">#524</a>
(<a
href="https://redirect.github.com/XAMPPRocky/octocrab/issues/815">#815</a>)</li>
<li>See full diff in <a
href="https://github.com/XAMPPRocky/octocrab/compare/v0.47.0...v0.47.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=octocrab&package-manager=cargo&previous-version=0.47.0&new-version=0.47.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 21:18:06 +03:00
dependabot[bot]
c60fc65915 build(deps): bump taiki-e/install-action from 2.62.45 to 2.62.49 (#2194)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.45 to 2.62.49.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.49</h2>
<ul>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.11.</p>
</li>
<li>
<p>Update <code>cargo-auditable@latest</code> to 0.7.2.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.2.</p>
</li>
</ul>
<h2>2.62.48</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.3.</p>
</li>
<li>
<p>Update <code>cargo-audit@latest</code> to 0.22.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.1.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.8.</p>
</li>
<li>
<p>Update <code>cargo-udeps@latest</code> to 0.1.60.</p>
</li>
<li>
<p>Update <code>zizmor@latest</code> to 1.16.3.</p>
</li>
</ul>
<h2>2.62.47</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.111.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.2.</p>
</li>
</ul>
<h2>2.62.46</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.5.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.37.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.2.</p>
</li>
<li>
<p>Update <code>knope@latest</code> to 0.21.5.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<ul>
<li>Update <code>coreutils@latest</code> to 0.4.0.</li>
</ul>
<h2>[2.62.49] - 2025-11-09</h2>
<ul>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.11.</p>
</li>
<li>
<p>Update <code>cargo-auditable@latest</code> to 0.7.2.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.2.</p>
</li>
</ul>
<h2>[2.62.48] - 2025-11-08</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.3.</p>
</li>
<li>
<p>Update <code>cargo-audit@latest</code> to 0.22.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.1.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.8.</p>
</li>
<li>
<p>Update <code>cargo-udeps@latest</code> to 0.1.60.</p>
</li>
<li>
<p>Update <code>zizmor@latest</code> to 1.16.3.</p>
</li>
</ul>
<h2>[2.62.47] - 2025-11-05</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.20.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.111.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.2.</p>
</li>
</ul>
<h2>[2.62.46] - 2025-11-04</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.5.</p>
</li>
<li>
<p>Update <code>syft@latest</code> to 1.37.0.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="44c6d64aa6"><code>44c6d64</code></a>
Release 2.62.49</li>
<li><a
href="3a701df4c2"><code>3a701df</code></a>
Update <code>cargo-binstall@latest</code> to 1.15.11</li>
<li><a
href="4242e04eb8"><code>4242e04</code></a>
Update <code>cargo-auditable@latest</code> to 0.7.2</li>
<li><a
href="3df5533ef8"><code>3df5533</code></a>
Update <code>vacuum@latest</code> to 0.20.2</li>
<li><a
href="e797ba6a25"><code>e797ba6</code></a>
Release 2.62.48</li>
<li><a
href="bcf91e02ac"><code>bcf91e0</code></a>
Update <code>mise@latest</code> to 2025.11.3</li>
<li><a
href="e78113b60c"><code>e78113b</code></a>
Update <code>cargo-audit@latest</code> to 0.22.0</li>
<li><a
href="0ef486444e"><code>0ef4864</code></a>
Update <code>vacuum@latest</code> to 0.20.1</li>
<li><a
href="5eda7b1985"><code>5eda7b1</code></a>
Update <code>uv@latest</code> to 0.9.8</li>
<li><a
href="3853a413e6"><code>3853a41</code></a>
Update <code>cargo-udeps@latest</code> to 0.1.60</li>
<li>Additional commits viewable in <a
href="81ee1d48d9...44c6d64aa6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.45&new-version=2.62.49)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 20:37:50 +03:00
dependabot[bot]
6c2f276d1c build(deps): bump trybuild from 1.0.113 to 1.0.114 (#2191)
Bumps [trybuild](https://github.com/dtolnay/trybuild) from 1.0.113 to
1.0.114.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dtolnay/trybuild/releases">trybuild's
releases</a>.</em></p>
<blockquote>
<h2>1.0.114</h2>
<ul>
<li>Normalize indentation of rustc suggestion lines (<a
href="https://redirect.github.com/dtolnay/trybuild/issues/319">#319</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="51f9418017"><code>51f9418</code></a>
Release 1.0.114</li>
<li><a
href="b4f6299028"><code>b4f6299</code></a>
Merge pull request <a
href="https://redirect.github.com/dtolnay/trybuild/issues/319">#319</a>
from dtolnay/suggestion</li>
<li><a
href="781a773986"><code>781a773</code></a>
Normalize indentation of rustc suggestion lines</li>
<li><a
href="c610b402ae"><code>c610b40</code></a>
Add test that reproduces misalignment of help under note</li>
<li>See full diff in <a
href="https://github.com/dtolnay/trybuild/compare/1.0.113...1.0.114">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trybuild&package-manager=cargo&previous-version=1.0.113&new-version=1.0.114)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 20:37:06 +03:00
dependabot[bot]
4cb1b06371 build(deps): bump rust-lang/crates-io-auth-action from 1.0.2 to 1.0.3 (#2195)
Bumps
[rust-lang/crates-io-auth-action](https://github.com/rust-lang/crates-io-auth-action)
from 1.0.2 to 1.0.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/rust-lang/crates-io-auth-action/releases">rust-lang/crates-io-auth-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update dependency eslint to v9.38.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/88">rust-lang/crates-io-auth-action#88</a></li>
<li>chore(deps): update dependency msw to v2.11.6 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/89">rust-lang/crates-io-auth-action#89</a></li>
<li>chore(deps): update dependency typescript-eslint to v8.46.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/90">rust-lang/crates-io-auth-action#90</a></li>
<li>refactor: Migrate from tsup to tsdown by <a
href="https://github.com/kingsword09"><code>@​kingsword09</code></a> in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/92">rust-lang/crates-io-auth-action#92</a></li>
<li>chore(deps): update dependency typescript-eslint to v8.46.3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/97">rust-lang/crates-io-auth-action#97</a></li>
<li>chore(deps): update dependency globals to v16.5.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/96">rust-lang/crates-io-auth-action#96</a></li>
<li>chore(deps): update dependency msw to v2.12.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/98">rust-lang/crates-io-auth-action#98</a></li>
<li>chore(deps): update lycheeverse/lychee-action action to v2.7.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/94">rust-lang/crates-io-auth-action#94</a></li>
<li>chore(deps): update dependency eslint to v9.39.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/93">rust-lang/crates-io-auth-action#93</a></li>
<li>chore(deps): update dependency vitest to v4 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/91">rust-lang/crates-io-auth-action#91</a></li>
<li>update tsdown to version 0.16 by <a
href="https://github.com/marcoieni"><code>@​marcoieni</code></a> in <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/100">rust-lang/crates-io-auth-action#100</a></li>
<li>chore(deps): lock file maintenance by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/pull/95">rust-lang/crates-io-auth-action#95</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/rust-lang/crates-io-auth-action/compare/v1.0.2...v1.0.3">https://github.com/rust-lang/crates-io-auth-action/compare/v1.0.2...v1.0.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b7e9a28ede"><code>b7e9a28</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/95">#95</a>
from rust-lang/renovate/lock-file-maintenance</li>
<li><a
href="7ac4f7f0b8"><code>7ac4f7f</code></a>
chore(deps): lock file maintenance</li>
<li><a
href="eeaaca05a4"><code>eeaaca0</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/100">#100</a>
from rust-lang/update-tsdown-to-version-0-16</li>
<li><a
href="9002361790"><code>9002361</code></a>
update tsdown to version 0.16</li>
<li><a
href="a06c97ab62"><code>a06c97a</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/91">#91</a>
from rust-lang/renovate/major-vitest-monorepo</li>
<li><a
href="2d6d1934da"><code>2d6d193</code></a>
chore(deps): update dependency vitest to v4</li>
<li><a
href="5c091fa7bf"><code>5c091fa</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/93">#93</a>
from rust-lang/renovate/eslint-monorepo</li>
<li><a
href="14c141348e"><code>14c1413</code></a>
chore(deps): update dependency eslint to v9.39.1</li>
<li><a
href="8a0dbdbd2a"><code>8a0dbdb</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/94">#94</a>
from rust-lang/renovate/github-actions</li>
<li><a
href="2c172cf087"><code>2c172cf</code></a>
Merge pull request <a
href="https://redirect.github.com/rust-lang/crates-io-auth-action/issues/96">#96</a>
from rust-lang/renovate/globals-16.x-lockfile</li>
<li>Additional commits viewable in <a
href="041cce5b4b...b7e9a28ede">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rust-lang/crates-io-auth-action&package-manager=github_actions&previous-version=1.0.2&new-version=1.0.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-10 20:24:05 +03:00
dependabot[bot]
09b943d5b9 build(deps): bump crate-ci/typos from 1.38.1 to 1.39.0 (#2181)
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.38.1 to
1.39.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
releases</a>.</em></p>
<blockquote>
<h2>v1.39.0</h2>
<h2>[1.39.0] - 2025-10-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1383">October
2025</a> changes</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>When a typo is pluralized, prefer pluralized corrections</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
changelog</a>.</em></p>
<blockquote>
<h1>Change Log</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a href="https://keepachangelog.com/">Keep a
Changelog</a>
and this project adheres to <a href="https://semver.org/">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased] - ReleaseDate</h2>
<h2>[1.39.0] - 2025-10-31</h2>
<h3>Features</h3>
<ul>
<li>Updated the dictionary with the <a
href="https://redirect.github.com/crate-ci/typos/issues/1383">October
2025</a> changes</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>When a typo is pluralized, prefer pluralized corrections</li>
</ul>
<h2>[1.38.1] - 2025-10-07</h2>
<h3>Fixes</h3>
<ul>
<li>Ignore common golang identifiers</li>
</ul>
<h2>[1.38.0] - 2025-10-06</h2>
<h3>Features</h3>
<ul>
<li>Update type list</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>typ</code></li>
<li>Consistently error on unused config fields</li>
</ul>
<h2>[1.37.3] - 2025-10-06</h2>
<h3>Fixes</h3>
<ul>
<li>Don't correct <code>PN</code> for <code>bitbake</code> file
types</li>
</ul>
<h2>[1.37.2] - 2025-10-03</h2>
<h3>Fixes</h3>
<ul>
<li>Don't suggest <code>diagnostic</code> for <code>diagnotics</code>,
preferring <code>diagnostics</code></li>
</ul>
<h2>[1.37.1] - 2025-10-01</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="07d900b8fa"><code>07d900b</code></a>
chore: Release</li>
<li><a
href="fcce1f892d"><code>fcce1f8</code></a>
chore: Release</li>
<li><a
href="85692fd91b"><code>85692fd</code></a>
docs: Update changelog</li>
<li><a
href="da7527cc35"><code>da7527c</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1406">#1406</a>
from epage/oct</li>
<li><a
href="9046b5b2e9"><code>9046b5b</code></a>
feat(dict): October additions</li>
<li><a
href="9a86c0a0c0"><code>9a86c0a</code></a>
docs: Update screenshot</li>
<li>See full diff in <a
href="80c8a4945e...07d900b8fa">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.38.1&new-version=1.39.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2025-11-03 18:41:31 +03:00
dependabot[bot]
ad56456e23 build(deps): bump taiki-e/install-action from 2.62.38 to 2.62.45 (#2182)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.62.38 to 2.62.45.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.62.45</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.16.2.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.10.</p>
</li>
<li>
<p>Update <code>ubi@latest</code> to 0.8.4.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.1.</p>
</li>
<li>
<p>Update <code>cargo-semver-checks@latest</code> to 0.45.0.</p>
</li>
</ul>
<h2>2.62.44</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.110.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.39.0.</p>
</li>
</ul>
<h2>2.62.43</h2>
<ul>
<li>
<p>Update <code>uv@latest</code> to 0.9.7.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.10.21.</p>
</li>
</ul>
<h2>2.62.42</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.10.20.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.109.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.4.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.6.</p>
</li>
</ul>
<h2>2.62.41</h2>
<ul>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.2.4.</p>
</li>
<li>
<p>Update <code>zizmor@latest</code> to 1.16.1.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.10.19.</p>
</li>
</ul>
<h2>2.62.40</h2>
<ul>
<li>Update <code>wasm-bindgen@latest</code> to 0.2.105.</li>
</ul>
<h2>2.62.39</h2>
<ul>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.1.</p>
</li>
<li>
<p>Update <code>cargo-shear@latest</code> to 1.6.1.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.9.</p>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.62.45] - 2025-11-02</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.16.2.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.15.10.</p>
</li>
<li>
<p>Update <code>ubi@latest</code> to 0.8.4.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.11.1.</p>
</li>
<li>
<p>Update <code>cargo-semver-checks@latest</code> to 0.45.0.</p>
</li>
</ul>
<h2>[2.62.44] - 2025-11-01</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.11.0.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.110.</p>
</li>
<li>
<p>Update <code>typos@latest</code> to 1.39.0.</p>
</li>
</ul>
<h2>[2.62.43] - 2025-10-31</h2>
<ul>
<li>
<p>Update <code>uv@latest</code> to 0.9.7.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2025.10.21.</p>
</li>
</ul>
<h2>[2.62.42] - 2025-10-30</h2>
<ul>
<li>
<p>Update <code>mise@latest</code> to 2025.10.20.</p>
</li>
<li>
<p>Update <code>cargo-nextest@latest</code> to 0.9.109.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.19.4.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.9.6.</p>
</li>
</ul>
<h2>[2.62.41] - 2025-10-29</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="81ee1d48d9"><code>81ee1d4</code></a>
Release 2.62.45</li>
<li><a
href="7e77e5bd52"><code>7e77e5b</code></a>
Update <code>zizmor@latest</code> to 1.16.2</li>
<li><a
href="cbe581c5e1"><code>cbe581c</code></a>
Update <code>cargo-binstall@latest</code> to 1.15.10</li>
<li><a
href="f545311470"><code>f545311</code></a>
Update <code>ubi@latest</code> to 0.8.4</li>
<li><a
href="83d4502be0"><code>83d4502</code></a>
Update <code>mise@latest</code> to 2025.11.1</li>
<li><a
href="2daecf63c1"><code>2daecf6</code></a>
Update <code>cargo-semver-checks@latest</code> to 0.45.0</li>
<li><a
href="47be02f2de"><code>47be02f</code></a>
Release 2.62.44</li>
<li><a
href="5f7c916518"><code>5f7c916</code></a>
Update <code>mise@latest</code> to 2025.11.0</li>
<li><a
href="3e60733ebb"><code>3e60733</code></a>
Update <code>cargo-nextest@latest</code> to 0.9.110</li>
<li><a
href="2ef505df34"><code>2ef505d</code></a>
Update <code>typos@latest</code> to 1.39.0</li>
<li>Additional commits viewable in <a
href="c5b1b6f479...81ee1d48d9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.62.38&new-version=2.62.45)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 18:34:59 +03:00
dependabot[bot]
6957bce264 build(deps): bump clap from 4.5.50 to 4.5.51 (#2185)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.50 to 4.5.51.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/releases">clap's
releases</a>.</em></p>
<blockquote>
<h2>v4.5.51</h2>
<h2>[4.5.51] - 2025-10-29</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Correctly calculate padding for short flags that
take a value</li>
<li><em>(help)</em> Don't panic on short flags using
<code>ArgAction::Count</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/clap-rs/clap/blob/master/CHANGELOG.md">clap's
changelog</a>.</em></p>
<blockquote>
<h2>[4.5.51] - 2025-10-29</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Correctly calculate padding for short flags that
take a value</li>
<li><em>(help)</em> Don't panic on short flags using
<code>ArgAction::Count</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b49dae25ec"><code>b49dae2</code></a>
chore: Release</li>
<li><a
href="d37b0b57ab"><code>d37b0b5</code></a>
docs: Update changelog</li>
<li><a
href="3398b6ab10"><code>3398b6a</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6009">#6009</a>
from gtema/complete_try_generate</li>
<li><a
href="21fc9e46d4"><code>21fc9e4</code></a>
feat(clap-complete): Introduce fallible generator</li>
<li><a
href="bd01bdc0ff"><code>bd01bdc</code></a>
Merge pull request <a
href="https://redirect.github.com/clap-rs/clap/issues/6012">#6012</a>
from epage/sub</li>
<li><a
href="ed0c63deba"><code>ed0c63d</code></a>
docs(derive): Specify arg_required_else_help is set for users</li>
<li><a
href="e2188d9af3"><code>e2188d9</code></a>
chore(deps): Update Rust Stable to v1.87 (<a
href="https://redirect.github.com/clap-rs/clap/issues/6004">#6004</a>)</li>
<li><a
href="e01f2b7640"><code>e01f2b7</code></a>
docs: Cleanup unused links</li>
<li><a
href="6b12a81baf"><code>6b12a81</code></a>
chore: Release</li>
<li><a
href="8dd92a792d"><code>8dd92a7</code></a>
docs: Update changelog</li>
<li>Additional commits viewable in <a
href="https://github.com/clap-rs/clap/compare/clap_complete-v4.5.50...clap_complete-v4.5.51">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=clap&package-manager=cargo&previous-version=4.5.50&new-version=4.5.51)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 18:34:29 +03:00
dependabot[bot]
06f0c67131 build(deps): bump trybuild from 1.0.112 to 1.0.113 (#2184)
Bumps [trybuild](https://github.com/dtolnay/trybuild) from 1.0.112 to
1.0.113.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/dtolnay/trybuild/releases">trybuild's
releases</a>.</em></p>
<blockquote>
<h2>1.0.113</h2>
<ul>
<li>Update <code>target-triple</code> dependency to v1</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f224ff80dc"><code>f224ff8</code></a>
Release 1.0.113</li>
<li><a
href="f19d0bd11d"><code>f19d0bd</code></a>
Update target-triple dependency to v1</li>
<li>See full diff in <a
href="https://github.com/dtolnay/trybuild/compare/1.0.112...1.0.113">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trybuild&package-manager=cargo&previous-version=1.0.112&new-version=1.0.113)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 18:34:08 +03:00
dependabot[bot]
f10a9e8308 build(deps): bump kasuari from 0.4.9 to 0.4.10 (#2183)
Bumps [kasuari](https://github.com/ratatui/kasuari) from 0.4.9 to
0.4.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/kasuari/releases">kasuari's
releases</a>.</em></p>
<blockquote>
<h2>v0.4.10</h2>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump thiserror from 2.0.16 to 2.0.17 in the
rust-dependencies group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/36">#36</a>)</li>
<li><em>(features)</em> improve feature flags docs (<a
href="https://redirect.github.com/ratatui/kasuari/pull/35">#35</a>)</li>
<li>Fixed a bug that lead to the leaking of <code>Symbol</code>s in the
objective function. (<a
href="https://redirect.github.com/ratatui/kasuari/pull/37">#37</a>)</li>
<li>Bump MSRV to 1.85 to use clamp functions in const context (<a
href="https://redirect.github.com/ratatui/kasuari/pull/39">#39</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>bump the MSRV to 1.85 and rely on the standard
<code>f64::clamp</code> in const contexts</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ratatui/kasuari/blob/main/CHANGELOG.md">kasuari's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/ratatui/kasuari/compare/v0.4.9...v0.4.10">0.4.10</a>
- 2025-11-02</h2>
<h3>Other</h3>
<ul>
<li><em>(deps)</em> bump thiserror from 2.0.16 to 2.0.17 in the
rust-dependencies group (<a
href="https://redirect.github.com/ratatui/kasuari/pull/36">#36</a>)</li>
<li><em>(features)</em> improve feature flags docs (<a
href="https://redirect.github.com/ratatui/kasuari/pull/35">#35</a>)</li>
<li>Fixed a bug that lead to the leaking of <code>Symbol</code>s in the
objective function. (<a
href="https://redirect.github.com/ratatui/kasuari/pull/37">#37</a>)</li>
<li>Bump MSRV to 1.85 to use clamp functions in const context (<a
href="https://redirect.github.com/ratatui/kasuari/pull/39">#39</a>)</li>
</ul>
<h3>Changed</h3>
<ul>
<li>bump the MSRV to 1.85 and rely on the standard
<code>f64::clamp</code> in const contexts</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="20e044f28d"><code>20e044f</code></a>
chore: release v0.4.10 (<a
href="https://redirect.github.com/ratatui/kasuari/issues/40">#40</a>)</li>
<li><a
href="3365fcfa78"><code>3365fcf</code></a>
build(deps): bump thiserror from 2.0.16 to 2.0.17 in the
rust-dependencies gr...</li>
<li><a
href="0dabc89b59"><code>0dabc89</code></a>
docs(features): improve feature flags docs (<a
href="https://redirect.github.com/ratatui/kasuari/issues/35">#35</a>)</li>
<li><a
href="c9689a278c"><code>c9689a2</code></a>
Fixed a bug that lead to the leaking of <code>Symbol</code>s in the
objective function. ...</li>
<li><a
href="1c16c27ef5"><code>1c16c27</code></a>
Bump MSRV to 1.85 to use clamp functions in const context (<a
href="https://redirect.github.com/ratatui/kasuari/issues/39">#39</a>)</li>
<li>See full diff in <a
href="https://github.com/ratatui/kasuari/compare/v0.4.9...v0.4.10">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=kasuari&package-manager=cargo&previous-version=0.4.9&new-version=0.4.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 18:33:39 +03:00
Josh McKinney
4c3c0540cd feat(serde): Handle null modifiers in serde Style (#2172)
Allow `Style`'s `add_modifier` and `sub_modifier` fields to
deserialize from `null`
2025-11-01 17:47:56 -07:00
Josh McKinney
f919b25ea6 fix: string_to_string lint is now part of implicit_clone (#2173) 2025-11-02 00:48:44 +01:00
Orhun Parmaksız
714c6584c3 chore(workspace): use ratatui dependency from the workspace (#2169)
Fix #2166
2025-11-01 15:55:40 -07:00
Orhun Parmaksız
3812f69997 chore(cargo): update the documentation metadata for crates (#2170)
also follows the same format for the entries (`name` -> `version` ->
`description` -> etc. in order)
2025-11-01 12:36:37 -07:00
Orhun Parmaksız
16b76e36ee fix(demo): update the width of demo2 tape (#2164)
![](https://github.com/ratatui/ratatui/blob/images/examples/demo2.gif?raw=true)

fixes #1721
2025-11-01 14:00:11 +03:00
github-actions[bot]
fbe6549d05 chore: release beta (#2162)
## 🤖 New release

* `ratatui-core`: 0.1.0-alpha.6 -> 0.1.0-beta.0
* `ratatui-crossterm`: 0.1.0-alpha.5 -> 0.1.0-beta.0
* `ratatui-widgets`: 0.3.0-alpha.5 -> 0.3.0-beta.0
* `ratatui-macros`: 0.7.0-alpha.4 -> 0.7.0-beta.0
* `ratatui-termwiz`: 0.1.0-alpha.5 -> 0.1.0-beta.0
* `ratatui-termion`: 0.1.0-alpha.5 -> 0.1.0-beta.0
* `ratatui`: 0.30.0-alpha.5 -> 0.30.0-beta.0

<details><summary><i><b>Changelog</b></i></summary><p>

##
[v0.30.0-beta.0](https://github.com/ratatui/ratatui/releases/tag/v0.30.0-beta.0)
- 2025-10-28

> _"Rats don't just survive; they discover; they create. ... I mean,
just look at what they do with
the terminal!" – Remy & Orhun_

We are excited to announce the biggest release of `ratatui` so far - a
Rust library that's all about cooking up TUIs 👨‍🍳🐀

 **WIP Release highlights**:
<https://ratatui-0-30.ratatui.pages.dev/highlights/v030/>

⚠️ List of breaking changes can be found
[here](https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md).

### Features

-
[56d5e05](56d5e05762)
_(bar)_ Update label and text_value to accept Into<> by @Emivvvvv in
[#1471](https://github.com/ratatui/ratatui/pull/1471) [**breaking**]

> BREAKING CHANGE:label and text_value now accept `Into<>` types, which
  > breaks type inference.
  >
  > ```diff
  > - Bar::default().label("foo".into());
  > + Bar::default().label("foo");
  > ```
  >
  > ```diff
  > - Bar::default().text_value("bar".into());
  > + Bar::default().text_value("bar");
  > ```

-
[b76ad3b](b76ad3b02e)
_(bar)_ Impl Styled for Bar by @Emivvvvv in
[#1476](https://github.com/ratatui/ratatui/pull/1476)

  > Related:https://github.com/ratatui/ratatui/issues/683

-
[e15fefa](e15fefa922)
_(barchar)_ Add BarChart::grouped constructor by @joshka in
[#1513](https://github.com/ratatui/ratatui/pull/1513)

> Add a new constructor to the `BarChart` widget that allows creating a
  > grouped barchart with multiple groups of bars.
  >
> Also add a new constructor to the `BarGroup` widget that allows
creating
  > a group of bars with a label.

-
[369b18e](369b18eef2)
_(barchart)_ Reduce barchart creation verbosity by @Emivvvvv in
[#1453](https://github.com/ratatui/ratatui/pull/1453)

  > Adds constructor methods for BarChart, BarGroup, and Bar

-
[2d713d7](2d713d723d)
_(crossterm)_ Allow multiple crossterm versions by @joshka in
[#1841](https://github.com/ratatui/ratatui/pull/1841)

  > This commit introduces feature flags to make it possible for widget
  > library authors to depend on a specific version of crossterm without
> causing version conflicts. This should make it easier for libraries
and
  > apps to update crossterm versions more easily.
  >
> The available feature flags are `crossterm_0_28` and `crossterm_0_29`.
> By default, the latest version is enabled. If a multiple features are
  > enabled we choose the latest version. We will in general support at
  > least the last two major (0.x) versions of crossterm, and will only
  > remove versions in a major version bump.

-
[d99984f](d99984f1e9)
_(layout)_ Add `Flex::SpaceEvenly` by @kdheepak in
[#1952](https://github.com/ratatui/ratatui/pull/1952) [**breaking**]

  > Resolves https://github.com/ratatui/ratatui/issues/1951
  >
> BREAKING CHANGE:Old `Flex::SpaceAround` behavior is available by using
  >
  > `Flex::SpaceEvenly` and new
  >
  > `Flex::SpaceAround` now distributes space evenly around each element
  > except the middle spacers
  > are twice the size of first and last elements
  >
  > With this change, the following variants of `Flex` are supported:
  >
> - `Flex::Start`: Aligns items to the start; excess space appears at
the
  >   end.
  > - `Flex::End`: Aligns items to the end; excess space appears at the
  >   start.
  > - `Flex::Center`: Centers items with equal space on both sides.
> - `Flex::SpaceAround` (**new**): Distributes space _around_ items;
space
  >   between items is _twice_ the edge spacing.
> - `Flex::SpaceBetween`: Distributes space _evenly between_ items
except
  >   no space at the edges.
> - `Flex::SpaceEvenly` (**previously `Flex::SpaceAround`**):
Distributes
  >   space _evenly between_ items and edges.
> - `Flex::Legacy`: Preserves legacy behavior, placing all excess space
at
  >   the end.
  >
  > This aligns behavior of `Flex` with CSS flexbox more closely.
  >
  > The following is a screenshot in action:
  >
  > <img width="1090" alt="image"
  >
>
src="https://github.com/user-attachments/assets/2c7cd797-27bd-4242-a824-4565d369227b"
  > />
  >
  > ***

-
[9275d34](9275d3421c)
_(layout)_ Add Offset::new() constructor by @joshka in
[#1547](https://github.com/ratatui/ratatui/pull/1547)

-
[7ad9c29](7ad9c29eac)
_(linegauge)_ Customized symbols by @sectore in
[#1601](https://github.com/ratatui/ratatui/pull/1601)

  > With this PR any symbol (`&str`) can be used to render `filled` and
  > `unfilled` parts of `LineGauge` now. Before that change, only
>
[`symbols::line::Set`](https://docs.rs/ratatui/latest/ratatui/symbols/line/struct.Set.html)
  > was accepted.
  >
  > Note:New methods are introduced to define those symbols:
  > `filled_symbol` and `unfilled_symbol`. The method
>
[`line_set`](https://docs.rs/ratatui/latest/ratatui/widgets/struct.LineGauge.html#method.line_set)
  > is still there, but marked as `deprecated`.
  >
>
![line_gauge](https://github.com/user-attachments/assets/cae308b8-151b-461d-8af6-9a20012adf2f)

-
[92a19cb](92a19cb604)
_(list)_ Highlight symbol styling by @airblast-dev in
[#1595](https://github.com/ratatui/ratatui/pull/1595) [**breaking**]

  > Allow styling for `List`'s highlight symbol
  >
  > This change makes it so anything that implements `Into<Line>` can be
  > used as a highlight symbol.
  >
> BREAKING CHANGE:`List::highlight_symbol` can no longer be used in
const
  > context
  >
  > BREAKING CHANGE:`List::highlight_symbol` accepted `&str`. Conversion
  > methods that rely on type inference will need to be rewritten as the
  > compiler cannot infer the type.
  >
  > closes:https://github.com/ratatui/ratatui/issues/1443
  >
  > ***

-
[e89a526](e89a526aab)
_(no_std)_ Portable-atomic integration for targets with no atomic types
by @j-g00da in [#2076](https://github.com/ratatui/ratatui/pull/2076)

  > Improves compatibility with no-std targets that don't support atomic
  > types.
  >
  > We support three different scenarios depending on the target:
  >
  > 1. Terminal applications and other std targets (e.g. espidf):
  >
  > - `std` enabled, `portable-atomic` disabled
  >
  > 2. Embedded targets with atomic types, bare metal x86, etc.:
  >
  > - `std` disabled `portable-atomic` disabled
  >
  > 3. Embedded targets without atomic types (e.g. single-core MCUs):
  >
  > - `std` disabled, `portable-atomic` enabled
  >
> Turning on `portable-atomic` together with `std` will fall back to
`std`
  > atomic.

-
[1399d95](1399d95ae0)
_(no_std)_ Make palette and serde features depends on std by @j-g00da in
[#1919](https://github.com/ratatui/ratatui/pull/1919)

-
[b32f781](b32f78195b)
_(no_std)_ Make `ratatui-macros` no-std by @j-g00da in
[#1865](https://github.com/ratatui/ratatui/pull/1865)

-
[3e1c72f](3e1c72fb27)
_(no_std)_ Make ratatui compatible with `#![no_std]` by @j-g00da in
[#1794](https://github.com/ratatui/ratatui/pull/1794) [**breaking**]

  > Resolves #1781
  >
  > This PR makes it possible to compile ratatui with `#![no_std]`.
  > Also makes me answer "We Are So Embedded" to "Are We Embedded Yet?"

-
[ab48c06](ab48c06171)
_(no_std)_ Option to disable layout cache for `no_std` compatibility by
@j-g00da in [#1795](https://github.com/ratatui/ratatui/pull/1795)
[**breaking**]

  > Resolves #1780
  >
  > BREAKING CHANGE:Disabling `default-features` will now disable layout
  > cache, which can have a negative impact on performance.
  >
  > `Layout::init_cache` and `Layout::DEFAULT_CACHE_SIZE` are now only
  > available if `layout-cache` feature is enabled.

-
[09173d1](09173d1829)
_(no_std)_ Make `TestBackend::Error` `Infallible` by @j-g00da in
[#1823](https://github.com/ratatui/ratatui/pull/1823) [**breaking**]

> BREAKING CHANGE:`TestBackend` now uses `core::convert::Infallible` for
  > error handling instead of `std::io::Error`

-
[007713e](007713e50a)
_(no_std)_ Replace `Backend`'s `io::Error` usages with associated
`Error` type by @j-g00da in
[#1778](https://github.com/ratatui/ratatui/pull/1778) [**breaking**]

  > Resolves #1775
  >
> BREAKING CHANGE:Custom backends now have to implement `Backend::Error`
> and `Backend::clear_region`. Additionally some generic `Backend` usage
  > will have to explicitly set trait bounds for `Backend::Error`.

-
[a42a17e](a42a17e184)
_(no_std)_ Make `ratatui-widgets` `no_std` by @j-g00da in
[#1779](https://github.com/ratatui/ratatui/pull/1779)

  > Resolves #1776

-
[5a232a3](5a232a3115)
_(no_std)_ Remove redundant `std` usages in `ratatui-widgets` by
@j-g00da in [#1762](https://github.com/ratatui/ratatui/pull/1762)

-
[ebe10cd](ebe10cd81f)
_(no_std)_ Remove redundant `std` usages in `ratatui-core` by @j-g00da
in [#1753](https://github.com/ratatui/ratatui/pull/1753)

  > Resolves https://github.com/ratatui/ratatui/issues/1751

-
[08b08cc](08b08cc45b)
_(rect)_ Centering by @janTatesa in
[#1814](https://github.com/ratatui/ratatui/pull/1814)

  > Resolves #617

-
[ff729b7](ff729b7607)
_(scrollbar)_ Support retrieving the current position of state by @orhun
in [#1552](https://github.com/ratatui/ratatui/pull/1552)

> As of now it is possible to change the position of the Scrollbar but
not
  > possible to retrieve the position for further use. e.g.
  >
  > ```rust
  > let mut state = ScrollbarState::default();
  > state.next();
  > ```
  >
> This commit adds a new method "`current_position`" (since `position`
is
  > already taken by the fluent setter) for that purpose:
  >
  > ```rust
  > let index = state.get_position(); // yay
  > ```
  >
  > See #1545 for the concrete usage of this.

-
[b9da192](b9da1926a0)
_(serde)_ Derive Serialize/Deserialize for alignment enums by @j-g00da
in [#1957](https://github.com/ratatui/ratatui/pull/1957)

  > Resolves #1954

-
[89b7421](89b74214d9)
_(serde)_ Derive Serialize/Deserialize for additional structs/enums by
@aurreland in [#1883](https://github.com/ratatui/ratatui/pull/1883)

  > This PR adds `#[derive(Serialize, Deserialize)]` to the following
  > structs:
  >
  > - `Constraint`
  > - `Direction`
  > - `Spacing`
  > - `Layout`
  > - `AccentedPalette`
  > - `NonAccentedPalette`
  > - `Palette`
  > - `Padding`
  > - `Borders`
  > - `BorderType`
  > - `ListDirection`
  > - `ScrollbarOrientation`
  > - `ScrollDirection`
  > - `RenderDirection`
  > - `HighlightSpacing`
  >
  > Fixes #1877

-
[03f3f6d](03f3f6df35)
_(style)_ Allow add/sub modifiers to be omitted in Style serialization.
by @rcorre in [#2057](https://github.com/ratatui/ratatui/pull/2057)

  > It's really useful that Style supports Deserialize, this allows TUI
  > apps to have configurable theming without much extra code.
  >
  > However, deserializing a style currently fails if `add_modifier` and
  > `sub_modifier` are
  > not specified. That means the following TOML config:
  >
  > ```toml
  > [theme.highlight]
  > fg = "white"
  > bg = "black"
  > ```
  >
> Will fail to deserialize with "missing field `add_modifier`". It
should
  > be possible
  > to omit modifiers and have them default to "none".

-
[985cd05](985cd05573)
_(symbols)_ Add dashed borders by @theotchlx in
[#1573](https://github.com/ratatui/ratatui/pull/1573)

  > Adds several new border sets:
  >
  > - ratatui::symbols::border::LIGHT_DOUBLE_DASHED
  > - ratatui::symbols::border::HEAVY_DOUBLE_DASHED
  > - ratatui::symbols::border::LIGHT_TRIPLE_DASHED
  > - ratatui::symbols::border::HEAVY_TRIPLE_DASHED
  > - ratatui::symbols::border::LIGHT_QUADRUPLE_DASHED
  > - ratatui::symbols::border::HEAVY_QUADRUPLE_DASHED
  >
  > And corresponding variants to the ratatui::widgets::BorderType enum
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1355

-
[4c301e8](4c301e891d)
_(text)_ Implement `AddAssign` for `Text` by @acuteenvy in
[#1956](https://github.com/ratatui/ratatui/pull/1956)

> This makes it possible to add a second `Text` instance to a first one
using the += operator.
  >
  > ```rust
  > let mut text = Text::from("line 1");
  > text += Text::from("line 2");
  > ```
  >
> Style and alignment applied to the second text is ignored (though
styles and alignment of lines and spans are copied).

-
[ce4856a](ce4856a65f)
_(widgets)_ Add the missing constructor to canvas types by @orhun in
[#1538](https://github.com/ratatui/ratatui/pull/1538)

> Allows constructing `Rectangle`, `Points` and `Circle` using the `new`
  > method instead of initializing with the public fields directly.

-
[75b78be](75b78be09f)
_(uncategorized)_ Add width() impl for tabs by @joshka in
[#2049](https://github.com/ratatui/ratatui/pull/2049)

> The purpose of this is to make it easy for apps to easily calculate
the
  > total tab width including all dividers and padding.

-
[8188ed3](8188ed3950)
_(uncategorized)_ Implement UnicodeWidthStr for Text/Line/Span by
@joshka in [#2030](https://github.com/ratatui/ratatui/pull/2030)

  > You can now calculate the width of any Text/Line/Span using the
> UnicodeWidthStr trait instead of the width method on the type. This
also
  > makes it possible to use the width_cjk() method if needed.

-
[c845fec](c845fec765)
_(uncategorized)_ Add conversion from Size to Rect by @joshka in
[#2028](https://github.com/ratatui/ratatui/pull/2028)

  > `Rect::from(size)` returns a new Rect at the origin (0, 0) with the
  > specified `Size`

-
[017af11](017af11b2b)
_(uncategorized)_ Preserve block titles when merging borders by @j-g00da
in [#1977](https://github.com/ratatui/ratatui/pull/1977)

  > Resolves #1939

-
[6dcd53b](6dcd53bc6b)
_(uncategorized)_ Add ergonomic methods for layouting Rects by @joshka
in [#1909](https://github.com/ratatui/ratatui/pull/1909)

> This commit introduces new methods for the `Rect` struct that simplify
> the process of splitting a `Rect` into sub-rects according to a given
> `Layout`. By putting these methods on the `Rect` struct, we make it a
> bit more natural that a layout is applied to the `Rect` itself, rather
  > than passing a `Rect` to the `Layout` struct to be split.
  >
> Adds:- `Rect::layout` and `Rect::try_layout` methods that allow
splitting a
  > `Rect` into an array of sub-rects according to a given `Layout`.
  >
  > - `Rect::layout_vec` method that returns a `Vec` of sub-rects.
> - `Layout::try_areas` method that returns an array of sub-rects, with
  >   compile-time checks for the number of constraints. This is added
  >   mainly for consistency with the new `Rect` methods.
  >
  > ```rust
  > use ratatui_core::layout::{Layout, Constraint, Rect};
  > let area = Rect::new(0, 0, 10, 10);
  > let layout = Layout::vertical([Constraint::Fill(1); 2]);
  >
  > // Rect::layout() infers the number of constraints at compile time:
  > let [top, main] = area.layout(&layout);
  >
> // Rect::try_layout() and Layout::try_areas() do the same, but return
a
  > // Result:
  > let [top, main] = area.try_layout(&layout)?;
  > let [top, main] = layout.try_areas(area)?;
  >
  > // Rect::layout_vec() returns a Vec of sub-rects:
  > let areas_vec = area.layout_vec(&layout);
  >
  > // you can also explicitly specify the number of constraints:
  > let areas = area.layout::<2>(&layout);
  > let areas = area.try_layout::<2>(&layout)?;
  > let areas = layout.try_areas::<2>(area)?;
  > ```

-
[0c3872f](0c3872f1c5)
_(uncategorized)_ Add Rect::outer() by @joshka in
[#1929](https://github.com/ratatui/ratatui/pull/1929)

  > Fixes:https://github.com/ratatui/ratatui/issues/211

-
[7bc78bc](7bc78bca1b)
_(uncategorized)_ Add ratatui::run() method by @joshka in
[#1707](https://github.com/ratatui/ratatui/pull/1707)

> This introduces a new `ratatui::run()` method which runs a closure
with
> a terminal initialized with reasonable defaults for most applications.
  > This calls `ratatui::init()` before running the closure and
> `ratatui::restore()` after the closure completes, and returns the
result
  > of the closure.
  >
  > A minimal hello world example using the new `ratatui::run()` method:
  >
  > ```rust
  > fn main() -> Result<(), Box<dyn std::error::Error>> {
  >     ratatui::run(|terminal| {
  >         loop {
> terminal.draw(|frame| frame.render_widget("Hello World!",
frame.area()))?;
  >             if crossterm::event::read()?.is_key_press() {
  >                 break Ok(());
  >             }
  >         }
  >     })
  > }
  > ```
  >
  > Of course, this also works both with apps that use free methods and
  > structs:
  >
  > ```rust
> fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
  >
  > ratatui::run(run)?;
  > ```
  >
  > ```rust
  > struct App { ... }
  >
  > impl App {
  >     fn new() -> Self { ... }
> fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(),
AppError> { ... }
  > }
  >
  > ratatui::run(|terminal| App::new().run(terminal))?;
  > ```

-
[b6fbfcd](b6fbfcdd1c)
_(uncategorized)_ Add lifetime to symbol sets by @joshka in
[#1935](https://github.com/ratatui/ratatui/pull/1935)

> This makes it possible to create symbol sets at runtime with
non-static
  > lifetimes.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1722

-
[488e5f0](488e5f020f)
_(uncategorized)_ Make `border!` work without importing `Borders` by
@j-g00da in [#1918](https://github.com/ratatui/ratatui/pull/1918)

> Currently using `border!` macro requires explicit import of `Borders`
  > which is unnecessary.

-
[671c2b4](671c2b4fd4)
_(uncategorized)_ Support merging the borders of blocks by @j-g00da

> When two borders overlap, they will automatically merge into a single,
  > clean border instead of overlapping.
  >
> This improves visual clarity and reduces rendering glitches around
corners.
  >
  > For example:
  >
  > ```
> assert_eq!(Cell::new("┘").merge_symbol("┏",
MergeStrategy::Exact).symbol(), "╆");
  > ```

-
[702fff5](702fff501c)
_(uncategorized)_ Implement stylize methods directly on Style by @joshka
in [#1572](https://github.com/ratatui/ratatui/pull/1572) [**breaking**]

> This makes it possible to create constants using the shorthand
methods.
  >
  > ```rust
  > const MY_STYLE: Style = Style::new().blue().on_black();
  > ```
  >
  > Rather than implementing Styled for Style and then adding extension
  > methods that implement the Stylize shorthands, this implements the
  > methods as const functions directly on Style.
  >
  > BREAKING CHANGE:`Style` no longer implements `Styled`. Any calls to
  > methods implemented by the blanket implementation of Stylize are now
> defined directly on Style. Remove the Stylize import if it is no
longer
  > used by your code.
  >
> The `reset()` method does not have a direct replacement, as it clashes
  > with the existing `reset()` method. Use `Style::reset()` rather than
  > `some_style.reset()`
  >
  > Fixes:#1158

-
[4fcd238](4fcd238e1e)
_(uncategorized)_ Support no-std for calendar widget by @joshka in
[#1852](https://github.com/ratatui/ratatui/pull/1852)

> Removes the CalendarEventStore::today() function in no-std
environments

-
[53cdbbc](53cdbbccd5)
_(uncategorized)_ Enable serde propagation to backend crates (crossterm,
termion) by @ArjunKrish7356 in
[#1812](https://github.com/ratatui/ratatui/pull/1812)

> This PR propagates the serde feature from the main ratatui crate to
the
  > ratatui-crossterm and ratatui-termion backend crates. Solves #1805

-
[6836a69](6836a6903e)
_(uncategorized)_ Implement styled for other primitives by @aschey in
[#1684](https://github.com/ratatui/ratatui/pull/1684)

-
[fcb47d6](fcb47d60f3)
_(uncategorized)_ Rename Alignment to HorizontalAlignment and add
VerticalAlignment by @joshka in
[#1735](https://github.com/ratatui/ratatui/pull/1735) [**breaking**]

> We don't anticipate removing or deprecating the type alias in the near
  > future, but it is recommended to update your imports to use the new
  > name.
  >
> Added a VerticalAlignment enum to make the API more consistent. We
don't
> have a specific use case for it yet, but it's better to add it now and
  > be able to use it in the future.
  >
  > BREAKING-CHANGE:The `Alignment` enum has been renamed to
> `HorizontalAlignment` to better reflect its purpose. A type alias has
> been added to maintain backwards compatibility, however there are some
  > cases where type aliases are not enough to maintain backwards
  > compatibility. E.g. when using glob imports to import all the enum
> variants. This should not affect most users, but it is recommended to
  > update your imports to use the new name.
  >
  > ```diff
  > - use ratatui::layout::Alignment;
  > + use ratatui::layout::HorizontalAlignment;
  >
  > - use Alignment::*;
  > + use HorizontalAlignment::*;
  > ```

-
[2714d6b](2714d6b9c3)
_(uncategorized)_ Add array and tuple RGB color conversion methods by
@joshka in [#1703](https://github.com/ratatui/ratatui/pull/1703)

> Other crates (e.g. colorgrad) that deal with colors can convert colors
> to a tuple of 3 or 4 u8 values. This commit adds conversion methods
from
  > these types to a `Color::Rgb` instance. Any alpha value is ignored.
  >
  > ```rust
  > Color::from([255, 0, 0]);
  > Color::from((255, 0, 0));
  > Color::from([255, 0, 0, 255]);
  > Color::from((255, 0, 0, 255));
  > ```

-
[50ba965](50ba96518f)
_(uncategorized)_ Add a new RatatuiMascot widget by @Its-Just-Nans in
[#1584](https://github.com/ratatui/ratatui/pull/1584)

  > Move the Mascot from Demo2 into a new widget.
  > Make the Rat grey and adjust the other colors.
  >
  > ```rust
  > frame.render_widget(RatatuiMascot::default(), frame.area());
  > ```

-
[1d28c89](1d28c89fe5)
_(uncategorized)_ Add conversions for anstyle by @joshka in
[#1581](https://github.com/ratatui/ratatui/pull/1581)
> https://crates.io/crates/anstyle makes it possible to define colors in
> an interoperable way. This makes it possible for applications to
easily
  > load colors from a variety of formats.
  >
> This is gated by the anstyle feature flag which is disabled by
default.
  >
  > ***

### Bug Fixes

-
[a89d3d6](a89d3d62ff)
_(buffer)_ Clear behavior with VS16 wide emojis by @nornagon in
[#2063](https://github.com/ratatui/ratatui/pull/2063)

  > This fixes a bug where certain emojis like ⌨️ would sometimes be
> "overlaid" onto existing content from the buffer, instead of properly
  > clearing.
  >
  > [example demonstrating
>
bug](https://gist.github.com/nornagon/11a79d7a1f2e98aa129fedb4abccc530)
  >
  > This PR was generated by Codex, and validated by me:
  >
> 1. Behavior of the above example code was buggy before this fix
(showed
  >    overlaying "b" on top of the keyboard emoji), and fixed after.
> 2. The U+FE0F check is not strictly required, but I did note that
emoji
> without this char don't exhibit the buggy behavior, even without the
  >    fix.
  >
  > ***

-
[ec30390](ec30390446)
_(canvas)_ Round coordinates to nearest grid cell by @joshka in
[#1507](https://github.com/ratatui/ratatui/pull/1507)

  > Previously the canvas coordinates were rounded towards zero, which
> causes the rendering to be off by one pixel in some cases. It also
meant
> that pixels at the extreme edges of the canvas can only be drawn if
the
  > point was exactly on the edge of the canvas. This commit rounds the
> coordinates to the nearest integer instead. This may change the output
  > for some apps using Canvas / Charts.

-
[afd1ce1](afd1ce179b)
_(canvas)_ Lines that start outside the visible grid are now drawn by
@renesat in [#1501](https://github.com/ratatui/ratatui/pull/1501)

> Previously lines with points that were outside the canvas bounds were
> not drawn at all. Now they are clipped to the bounds of the canvas so
  > that the portion of the line within the canvas is draw.
  >
> To facilitate this, a new `Painter::bounds()` method which returns the
  > bounds of the canvas is added.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1489

-
[2b0a044](2b0a044ced)
_(ci)_ Add contents write permission to release-plz PR by @marcoieni in
[#2119](https://github.com/ratatui/ratatui/pull/2119)

  > https://release-plz.dev/docs/github/quickstart#3-setup-the-workflow
  >
  > Fixes https://github.com/release-plz/release-plz/issues/2439

-
[18e70d3](18e70d3d51)
_(crossterm)_ Terminal should keep Bold when removing Dim by @MarSik in
[#1541](https://github.com/ratatui/ratatui/pull/1541)

  > The Dim removal should behave the same as the logic for Bold removal
> that sends NormalIntensity sequence and then restores Dim when needed.

-
[dca331c](dca331c748)
_(demo)_ Support tab key in demo2 example by @orhun in
[#1726](https://github.com/ratatui/ratatui/pull/1726)

  > see #1721
  >
> Not sure what caused this - it's been there for a while probably and
we
  > didn't realize it since we used `demo2-destroy` mostly.

-
[0fd4753](0fd4753e6b)
_(examples)_ Run the correct example for chart by @orhun in
[#1679](https://github.com/ratatui/ratatui/pull/1679)

  > fixes #1678

-
[39479e2](39479e298c)
_(examples)_ Ensure that example projects are not published by @orhun in
[#1672](https://github.com/ratatui/ratatui/pull/1672)

-
[9314312](93143126b3)
_(layout)_ Feature flag cache related types by @joshka in
[#1842](https://github.com/ratatui/ratatui/pull/1842)

-
[2dd1977](2dd1977c59)
_(layout-cache)_ Import `NonZeroUsize` only when `layout-cache` is
enabled by @j-g00da in
[#1839](https://github.com/ratatui/ratatui/pull/1839)

> This silences unused import warning, when `layout-cache` is disabled.

-
[564a9d7](564a9d76fc)
_(line-gauge)_ Pad default label to display 3 numbers by @martinetd in
[#2053](https://github.com/ratatui/ratatui/pull/2053)

> Display the default label of the LineGauge widget padded to fill 3
cells.
> This makes it so that the label doesn't shift around when going from a
  > single digit to double / triple digits.
  >
> To maintain the existing behavior, use a custom label by calling
`.label()`
  > on the LineGauge.

-
[a692a6e](a692a6e371)
_(lint)_ Apply rust 1.84 clippy suggestions by @joshka in
[#1612](https://github.com/ratatui/ratatui/pull/1612)

  > The canvas map constants are now statics instead.
  > Fixes
>
https://rust-lang.github.io/rust-clippy/master/index.html\#large_const_arrays

-
[2e54d5e](2e54d5e22c)
_(macros)_ Use $crate re-export in text macro by @airblast-dev in
[#1832](https://github.com/ratatui/ratatui/pull/1832)

-
[79d5165](79d5165cae)
_(no_std)_ Propagate `std` feature flag to dependencies by @j-g00da in
[#1838](https://github.com/ratatui/ratatui/pull/1838)

> Disables `std` feature flags in dependencies and only enables them
with
> `ratatui` and `ratatui-core`'s `std` feature flag. This partially
fixes the
> issue of still depending on `std`, when `std` feature flag is
disabled.

-
[00da8c6](00da8c6203)
_(no_std)_ Provide `f64` polyfills for `no_std` compatibility by
@j-g00da in [#1840](https://github.com/ratatui/ratatui/pull/1840)

  > Related:https://github.com/rust-lang/rust/issues/137578

-
[3b13240](3b13240728)
_(scrollbar)_ Check for area.is_empty() before rendering by @farmeroy in
[#1529](https://github.com/ratatui/ratatui/pull/1529)

> This adds the `area.is_empty()` back into the scrollbar render method.
  > Without it, the widget panics if the height is 0.

-
[f57b696](f57b696fdc)
_(span)_ Dont render control characters by @EdJoPaTo in
[#1312](https://github.com/ratatui/ratatui/pull/1312)

-
[2ce958e](2ce958e38c)
_(table)_ Allow display of additional table row, if row height > 1 by
@Lunderberg in [#1452](https://github.com/ratatui/ratatui/pull/1452)

-
[0a25bc1](0a25bc166d)
_(tests)_ Update the stderr snapshot for ratatui-macros by @orhun in
[#2161](https://github.com/ratatui/ratatui/pull/2161)

  > New 🦀 broke the CI

-
[5fa342c](5fa342cc52)
_(widgets)_ Fix centered block title truncation by @ognis1205 in
[#1973](https://github.com/ratatui/ratatui/pull/1973)

  > Previously block titles that were aligned center were
  > truncated poorly (aligned to the left, and the last
  > non-fitting title would be truncated on the left and right.
  > This now truncates the titles more obviously centered.

-
[1fe64de](1fe64de09a)
_(uncategorized)_ Include underline color in anstyle conversion by
@aschey in [#2004](https://github.com/ratatui/ratatui/pull/2004)

  > Underline color wasn't included in the style conversion logic.

-
[c1b8528](c1b8528b69)
_(uncategorized)_ Panic when rendering widgets on too small buffer by
@j-g00da in [#1996](https://github.com/ratatui/ratatui/pull/1996)

> Fixes panic on overflow on horizontal `Barchart` and `RatatuiMascot`
and adds proper tests to all widgets.
  >
  > ***

-
[08b21fa](08b21fa55c)
_(uncategorized)_ Fix panic when rendering a `Paragraph` out of bounds
by @jwodder in [#1670](https://github.com/ratatui/ratatui/pull/1670)

  > Fixes #1667.

-
[80bc818](80bc818723)
_(uncategorized)_ Fix truncation of left aligned block titles by @joshka
in [#1931](https://github.com/ratatui/ratatui/pull/1931)

> truncate the right side of left aligned titles rather than the left
side
> of right aligned titles. This is more obvious as the left side of text
  > often contains more important information. And we generally read
  > left to right.
  >
  > This change makes centered titles overwrite left aligned titles and
  > right aligned titles overwrite centered or left aligned titles.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/358

-
[21e3b59](21e3b598ce)
_(uncategorized)_ Fix handling of multi-byte chars in bar chart by
@joshka in [#1934](https://github.com/ratatui/ratatui/pull/1934)

  > The split_at method requires that the split point is at a valid utf8
  > character boundary.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1928

-
[e1e4004](e1e400406c)
_(uncategorized)_ Derive copy for list state by @janTatesa in
[#1921](https://github.com/ratatui/ratatui/pull/1921)

-
[12cb5a2](12cb5a28fe)
_(uncategorized)_ Allow canvas area to exceed u16::MAX by @Daksh14 in
[#1891](https://github.com/ratatui/ratatui/pull/1891)

> This allows Canvas grids where the width \* height exceeds u16::MAX by
  > converting values to usize earlier in several methods.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1449

-
[09cc9ef](09cc9ef57d)
_(uncategorized)_ Typo in changelog by @joshka in
[#1857](https://github.com/ratatui/ratatui/pull/1857)

-
[c238aca](c238aca83a)
_(uncategorized)_ `padding_right()` should set right padding instead of
left by @sxyazi in [#1837](https://github.com/ratatui/ratatui/pull/1837)

  > Fixes https://github.com/ratatui/ratatui/issues/1836

-
[c90ba97](c90ba9781e)
_(uncategorized)_ Avoid unnecessary imports in minimal build by @cgzones
in [#1787](https://github.com/ratatui/ratatui/pull/1787)

  > core::ops::Range is only used with the feature `scrolling-regions`.
  > Ensure a minimal `cargo check` reports no warnings.

-
[416ebdf](416ebdf8c8)
_(uncategorized)_ Correct clippy errors introduced by rust 1.86.0 update
by @j-g00da in [#1755](https://github.com/ratatui/ratatui/pull/1755)

  > New version of rust (1.86.0) caused CI to fail.

-
[4eac5b2](4eac5b2849)
_(uncategorized)_ Make deprecation notes more helpful by @joshka in
[#1702](https://github.com/ratatui/ratatui/pull/1702)

> AI coding assistants use the deprecation notes to automatically
suggest
> fixes. This commit updates the deprecation notes to push those tools
to
  > suggest the correct replacement methods and types.
  >
> Specifically, AI tools often suggest using `Buffer::get(x, y)`,
because
  > of their training data where this was prevalent. When fixing these
> deprecations, they often incorrectly suggest using `Buffer::get(x, y)`
  > instead of `Buffer[(x, y)]`.

-
[35a8642](35a86427ab)
_(uncategorized)_ `Rect::positions()` should be empty when width is 0
and height is nonzero by @jwodder in
[#1669](https://github.com/ratatui/ratatui/pull/1669)

  > Fixes #1666.

-
[f5fc819](f5fc8197ff)
_(uncategorized)_ Avoid extra line break on whitespace only lines when
wrapping paragraphs by @dotdash in
[#1636](https://github.com/ratatui/ratatui/pull/1636)

  > Currently whitespace only lines produces an extra line break when
  > trimming is disabled, because both the trimmed as well as the
  > non-trimmed line get inserted. Fix this by only inserting the
  > non-trimmed one.

-
[2892bdd](2892bddce6)
_(uncategorized)_ Rust 1.83 clippy lints by @joshka in
[#1527](https://github.com/ratatui/ratatui/pull/1527)

>
https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes

-
[36e2d1b](36e2d1bda1)
_(uncategorized)_ Add feature(doc_cfg) when generating docs by @joshka
in [#1506](https://github.com/ratatui/ratatui/pull/1506)

-
[4d7704f](4d7704fba5)
_(uncategorized)_ Make StatefulWidget and Ref work with unsized State by
@thscharler in [#1505](https://github.com/ratatui/ratatui/pull/1505)

  > StatefulWidget::State and StatefulWidgetRef::State are now ?Sized.
  >
> This allows implementations of the traits to use unsized types for the
  > State associated type. This is turn is useful when doing things like
  > boxing different stateful widget types with State which implements
  > `Any`, are slices or any other dynamically sized type.

-
[7b87509](7b875091e1)
_(uncategorized)_ Typo by @marcoieni in
[#1480](https://github.com/ratatui/ratatui/pull/1480)

### Refactor

-
[8d60e96](8d60e96b2b)
_(examples)_ Use crossterm event methods by @joshka in
[#1792](https://github.com/ratatui/ratatui/pull/1792)

> Crossterm 0.29 introduced methods to easily check / extract the event
  > type. E.g. as_key_press_event() and is_key_press(). This commit
  > updates the examples to use these methods instead of matching on
  > the event type. This makes the code cleaner and easier to read.
  >
> Also does a general cleanup of the event handling code in the
examples.

-
[07bec55](07bec55b7d)
_(no_std)_ Make usages of std explicit in ratatui-core. by @ed-2100 in
[#1782](https://github.com/ratatui/ratatui/pull/1782)

  > ### This commit does the following:
  >
  > - Adds `#[no_std]` to `lib.rs`.
  > - Adds `extern crate std;` to `lib.rs`.
> - Updates `ratatui-core` to explicitly `use` items from std and alloc.
  > - Prefers `use`-ing alloc over std when possible.
  >
  > ### Explanation:
  >
> This allows usages of `std` in `ratatui-core` to be clearly pointed
out
  > and dealt with individually.
  >
  > Eventually, when `std` is to be feature gated, the associated commit
  > will be much cleaner.

-
[f132fa1](f132fa1715)
_(table)_ Small readability improvements by @joshka in
[#1510](https://github.com/ratatui/ratatui/pull/1510)

-
[02e53de](02e53de0f8)
_(uncategorized)_ Make use of iter::repeat_n() by @cgzones in
[#1788](https://github.com/ratatui/ratatui/pull/1788)

  > Applied via clippy --fix.
  > Available since 1.82.0.

-
[a195d59](a195d59a47)
_(uncategorized)_ Move xtask commands to small modules by @joshka in
[#1620](https://github.com/ratatui/ratatui/pull/1620)

-
[904b0aa](904b0aa723)
_(uncategorized)_ Move symbols to modules by @joshka in
[#1594](https://github.com/ratatui/ratatui/pull/1594)

-
[7c8573f](7c8573f575)
_(uncategorized)_ Rearrange selection_spacing code by @raylu in
[#1540](https://github.com/ratatui/ratatui/pull/1540)

-
[217c57c](217c57cd60)
_(uncategorized)_ Modularize backends by @orhun in
[#1508](https://github.com/ratatui/ratatui/pull/1508)

> Backend code is now moved to `ratatui-crossterm`, `ratatui-termion`
and
> `ratatui-termwiz`. This should be backwards compatible with existing
code.

-
[e461b72](e461b724a6)
_(uncategorized)_ Move {Stateful,}Widget{,Ref} types into individual
files by @joshka in
[#1479](https://github.com/ratatui/ratatui/pull/1479)

> This is a preparatory refactoring for modularization. No user visible
  > changes.

### Documentation

-
[40e96a2](40e96a2a04)
_(block)_ Add collapsed border example by @joshka in
[#1899](https://github.com/ratatui/ratatui/pull/1899)

-
[d291042](d291042e69)
_(block)_ Revise the block example by @orhun in
[#1520](https://github.com/ratatui/ratatui/pull/1520)

  > - Moves the block example from `ratatui` to `ratatui-widgets`
  > - Simplifies the example (bordered, styled, custom borders)
  >
  > see #1512

-
[0951da5](0951da52f9)
_(breaking-changes)_ Improve migration guide for `Backend::Error` by
@j-g00da in [#1908](https://github.com/ratatui/ratatui/pull/1908)

  > Related:https://github.com/fujiapple852/trippy/pull/1588

-
[bbe1cf9](bbe1cf9497)
_(breaking-changes)_ Change MSRV to 1.85 by @j-g00da in
[#1896](https://github.com/ratatui/ratatui/pull/1896)

> The minimum supported Rust version is now for `ratatui` v0.30 is 1.85

-
[c7912f3](c7912f3990)
_(breaking-changes)_ Fix header level by @j-g00da in
[#1825](https://github.com/ratatui/ratatui/pull/1825)

-
[eb24938](eb249382c9)
_(changelog)_ Add note to ratatui-macros' changelog

-
[fcde9cb](fcde9cb9c3)
_(changelog)_ Fix typo by @orhun in
[#1463](https://github.com/ratatui/ratatui/pull/1463)

-
[73488ab](73488abb45)
_(contributing)_ Fix link to `widgets_block_renders` test by @ognis1205
in [#2101](https://github.com/ratatui/ratatui/pull/2101)

  > The `CONTRIBUTING.md` referenced `tests/widgets_block.rs`, but the
> correct path is `ratatui/tests/widgets_block.rs`. Updated the link so
  > that readers can navigate to the test example without 404 error.
  >
  > ***

-
[0b025db](0b025db72b)
_(contributing)_ Fix grammar by @j-g00da in
[#1958](https://github.com/ratatui/ratatui/pull/1958)

-
[1197b2a](1197b2a02c)
_(contributing)_ Add note about using nightly for formatting by @joshka
in [#1816](https://github.com/ratatui/ratatui/pull/1816)

-
[3ae6bf1](3ae6bf1d6f)
_(contributing)_ Use cargo-xtask for instructions by @orhun in
[#1509](https://github.com/ratatui/ratatui/pull/1509)

  > - Updates `CONTRIBUTING.md` about the usage of `xtask`
  > - Removes `Makefile.toml`

-
[22e3e84](22e3e84de8)
_(core)_ Remove link to Paragraph widget by @orhun in
[#1683](https://github.com/ratatui/ratatui/pull/1683)

-
[200b217](200b217722)
_(examples)_ Add VHS tapes and docs for widget examples by @orhun in
[#2114](https://github.com/ratatui/ratatui/pull/2114)

  > fixes #1982
  >
> Later on I'll figure out an easy way to regenerate this in the CI and
  > possibly do the same for the app examples' VHS tapes. That's why I
  > haven't added a script or mentioned anything in the docs yet (hint:
  > #1721)
  >
  > ***

-
[861fbdf](861fbdf5cf)
_(examples)_ Fix a typo by @j-g00da in
[#1890](https://github.com/ratatui/ratatui/pull/1890)

  > Makes CI typos check pass again

-
[882cc3c](882cc3c6c6)
_(examples)_ Update app examples with tapes by @orhun in
[#1673](https://github.com/ratatui/ratatui/pull/1673)

-
[4393fae](4393fae54c)
_(examples)_ Move scrollbar example to examples folder by @orhun in
[#1665](https://github.com/ratatui/ratatui/pull/1665)

-
[9ea70e2](9ea70e28c6)
_(examples)_ Move widget-impl example to examples folder by @orhun in
[#1663](https://github.com/ratatui/ratatui/pull/1663)

-
[774ab78](774ab788d4)
_(examples)_ Move widget-ref-container example to examples folder by
@orhun in [#1664](https://github.com/ratatui/ratatui/pull/1664)

  > see #1512

-
[910d16e](910d16e63a)
_(examples)_ Move user-input example to examples folder by @orhun in
[#1659](https://github.com/ratatui/ratatui/pull/1659)

-
[dbfb7da](dbfb7da9e3)
_(examples)_ Move table example to examples folder by @orhun in
[#1657](https://github.com/ratatui/ratatui/pull/1657)

-
[cb2a58a](cb2a58aaa0)
_(examples)_ Move tracing example to examples folder by @orhun in
[#1658](https://github.com/ratatui/ratatui/pull/1658)

-
[7e00b64](7e00b646fc)
_(examples)_ Move panic example to examples folder by @orhun in
[#1655](https://github.com/ratatui/ratatui/pull/1655)

-
[8127590](8127590812)
_(examples)_ Move modifiers example to examples folder by @orhun in
[#1654](https://github.com/ratatui/ratatui/pull/1654)

-
[7c40c0b](7c40c0bbdd)
_(examples)_ Move popup example to examples folder by @orhun in
[#1656](https://github.com/ratatui/ratatui/pull/1656)

  > see #1512

-
[d87354f](d87354f400)
_(examples)_ Move list example to examples folder by @orhun in
[#1653](https://github.com/ratatui/ratatui/pull/1653)

  > see #1512
  >
  > also renames it to todo-list

-
[621226f](621226f2e2)
_(examples)_ Move inline example to examples folder by @orhun in
[#1651](https://github.com/ratatui/ratatui/pull/1651)

-
[9ba7d25](9ba7d25b71)
_(examples)_ Move hyperlink example to examples folder by @orhun in
[#1650](https://github.com/ratatui/ratatui/pull/1650)

-
[bb94d1c](bb94d1c0fa)
_(examples)_ Move minimal example to examples folder by @orhun in
[#1649](https://github.com/ratatui/ratatui/pull/1649)

-
[9f399ac](9f399ac7a6)
_(examples)_ Move gauge example to examples folder by @orhun in
[#1646](https://github.com/ratatui/ratatui/pull/1646)

-
[104d6a6](104d6a6c2b)
_(examples)_ Move custom-widget example to examples folder by @orhun in
[#1644](https://github.com/ratatui/ratatui/pull/1644)

-
[fa8ca01](fa8ca0121a)
_(examples)_ Move flex example to examples folder by @orhun in
[#1642](https://github.com/ratatui/ratatui/pull/1642)

-
[f5fde0e](f5fde0ef53)
_(examples)_ Move constraints example to examples folder by @orhun in
[#1641](https://github.com/ratatui/ratatui/pull/1641)

-
[fc70288](fc70288954)
_(examples)_ Move constraint-explorer example to examples folder by
@orhun in [#1640](https://github.com/ratatui/ratatui/pull/1640)

-
[325f961](325f96102a)
_(examples)_ Move hello-world example to examples folder by @orhun in
[#1647](https://github.com/ratatui/ratatui/pull/1647)

-
[867c4bc](867c4bc4e9)
_(examples)_ Move colors-rgb example to examples folder by @joshka in
[#1582](https://github.com/ratatui/ratatui/pull/1582)

  > - **docs: move colors-rgb example to examples folder**
  > - **docs: update main examples README**
  >
  > ***

-
[72334ed](72334ed61c)
_(layout)_ Update documentation to point to `kasuari` solver by @a-kenji
in [#2003](https://github.com/ratatui/ratatui/pull/2003)

-
[2be9ccb](2be9ccb120)
_(layout)_ Remove unnecessary path prefix by @j-g00da in
[#1766](https://github.com/ratatui/ratatui/pull/1766)

-
[b669ceb](b669cebcaf)
_(layout)_ Change `cassowary` to `kasuari` crate reference by @j-g00da
in [#1765](https://github.com/ratatui/ratatui/pull/1765)

-
[f907c74](f907c74bb3)
_(license)_ Update copyright years by @LVivona in
[#1639](https://github.com/ratatui/ratatui/pull/1639)

  > Update MIT Licence to copyright year 2025

-
[68b9f67](68b9f67f59)
_(readme)_ Add `Built with Ratatui` badge for downstream projects by
@harilvfs in [#1905](https://github.com/ratatui/ratatui/pull/1905)

-
[088aac1](088aac136d)
_(readme)_ Tweak links and badges by @joshka in
[#1598](https://github.com/ratatui/ratatui/pull/1598)

-
[6e43672](6e436725e4)
_(readme)_ Reimagine README.md by @orhun in
[#1569](https://github.com/ratatui/ratatui/pull/1569)

> This is the result of the re-imagination of a more suitable README.md.
It
  > is simpler and shorter: not giving more information to the user than
  > they actually need.
  >
> Also updates the quickstart code with the up-to-date version and adds
  > link to templates which was missing.
  >
  > ***

-
[8f28247](8f282473b2)
_(readme)_ Correct examples links by @HoKim98 in
[#1484](https://github.com/ratatui/ratatui/pull/1484)

-
[9f90f74](9f90f7495f)
_(readme)_ Fix broken link by @nilsmartel in
[#1485](https://github.com/ratatui/ratatui/pull/1485)

-
[260af68](260af68a34)
_(readme)_ Include iocraft as an alternative by @kdheepak in
[#1483](https://github.com/ratatui/ratatui/pull/1483)

-
[8e5151f](8e5151f83d)
_(rect)_ Fix typo in the Rect::outer function comments by @orhun in
[#2123](https://github.com/ratatui/ratatui/pull/2123)

-
[40f13c6](40f13c6a6c)
_(rect)_ Update the outdated comment for Rect::area() by @eqsdxr in
[#2100](https://github.com/ratatui/ratatui/pull/2100)

> The return value of Rect.area() is no longer of u16 type, and the
value
  > is not being clumped anymore.

-
[ce16692](ce16692b9a)
_(release)_ Fix typo by @j-g00da in
[#1754](https://github.com/ratatui/ratatui/pull/1754)

-
[9a930a6](9a930a6e99)
_(terminal)_ Made usage of Terminal::get_frame() clearer by @Blaeriz in
[#2071](https://github.com/ratatui/ratatui/pull/2071)

  > Closes : https://github.com/ratatui/ratatui/issues/1200
  >
  > ***

-
[b08b4cb](b08b4cbd5e)
_(terminal)_ Add disclaimer about panics to Terminal::new by
@lolbinarycat in [#2088](https://github.com/ratatui/ratatui/pull/2088)

  > part of #2087
  >
  > cc @orhun
  >
  > ***

-
[dafb716](dafb716f9d)
_(widgets)_ Add example for grouped barchart by @orhun in
[#1566](https://github.com/ratatui/ratatui/pull/1566)

  > related #1512
  >
  > ***

-
[ed5dd73](ed5dd73084)
_(widgets)_ Add example for tabs by @orhun in
[#1559](https://github.com/ratatui/ratatui/pull/1559)

  > related #1512
  >
> Also removes the tabs example from ratatui crate since it overlaps
with
> this new example in terms of functionality and it was not following
the
  > general theme of other examples.

-
[fab5321](fab532171d)
_(widgets)_ Add example for scrollbar by @orhun in
[#1545](https://github.com/ratatui/ratatui/pull/1545)

  > Related to: #1512

-
[898aef6](898aef6e2f)
_(widgets)_ Add example for list by @orhun in
[#1542](https://github.com/ratatui/ratatui/pull/1542)

  > Related to: #1512

-
[452366a](452366aa9e)
_(widgets)_ Add example for sparkline by @orhun in
[#1556](https://github.com/ratatui/ratatui/pull/1556)

  > related #1512
  >
> Also removes the sparkline example from ratatui crate since this
example
  > is a simplified and easier to understand version of that

-
[6ddde0e](6ddde0e8a8)
_(widgets)_ Add example for table by @orhun in
[#1557](https://github.com/ratatui/ratatui/pull/1557)

  > related #1512

-
[93ad6b8](93ad6b828c)
_(widgets)_ Update values in chart example by @orhun in
[#1558](https://github.com/ratatui/ratatui/pull/1558)

  > better stonks

-
[15f442a](15f442a71e)
_(widgets)_ Add example for paragraph by @orhun in
[#1544](https://github.com/ratatui/ratatui/pull/1544)

  > related #1512
  >
> Also removes the paragraph example from `ratatui` since these examples
  > are more or less the same.

-
[17bba14](17bba14540)
_(widgets)_ Move the logo example to widgets by @orhun in
[#1543](https://github.com/ratatui/ratatui/pull/1543)

  > related #1512
  >
  > Also updates the code to make it consistent with the other examples

-
[f2451e7](f2451e7f1e)
_(widgets)_ Add example for gauge by @orhun in
[#1539](https://github.com/ratatui/ratatui/pull/1539)

  > related #1512

-
[4f0a8b2](4f0a8b21af)
_(widgets)_ Add example for canvas by @orhun in
[#1533](https://github.com/ratatui/ratatui/pull/1533)

  > related #1512

-
[91147c4](91147c4d75)
_(widgets)_ Add example for chart by @orhun in
[#1536](https://github.com/ratatui/ratatui/pull/1536)

  > stonks

-
[6dd25a3](6dd25a3111)
_(widgets)_ Add example for calendar by @orhun in
[#1532](https://github.com/ratatui/ratatui/pull/1532)

  > related #1512

-
[99ac005](99ac005b06)
_(widgets)_ Add simple barchart example by @joshka in
[#1511](https://github.com/ratatui/ratatui/pull/1511)

-
[f8b0594](f8b0594363)
_(uncategorized)_ Fix: fix typos by @j-g00da in
[#2129](https://github.com/ratatui/ratatui/pull/2129)

  > This fixes the pipeline after bumping typos.

-
[9998000](9998000e36)
_(uncategorized)_ Use shields.io badge by @LitoMore in
[#2040](https://github.com/ratatui/ratatui/pull/2040)

  > Related to:
  >
  > - https://github.com/simple-icons/simple-icons/pull/13593
  > - https://github.com/ratatui/ratatui/pull/1967
  >
  > The Ratatui icon is available on shields.io now ✌️
  >
  > And it's customizable. There are more configurations at
  > https://shields.io/badges.
  >
  > Here are some examples:
  >
  > ```markdown
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  > ```
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff)
>
![](https://img.shields.io/badge/Ratatui-fff?logo=ratatui&logoColor=000)
  >
>
![](https://img.shields.io/badge/Built_With-Ratatui-000?logo=ratatui&logoColor=fff&labelColor=000&color=fff)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=flat-square)
  >
>
![](https://img.shields.io/badge/Ratatui-000?logo=ratatui&logoColor=fff&style=for-the-badge)
  >
> I also created a PR to the ratatui-website project to update the
badge.
  > Here is the PR:
  >
  > - https://github.com/ratatui/ratatui-website/pull/924

-
[71ef65b](71ef65b624)
_(uncategorized)_ Add section on collaborative development to
contributing doc by @joshka in
[#2029](https://github.com/ratatui/ratatui/pull/2029)

-
[cba5cca](cba5cca2bd)
_(uncategorized)_ Update heading image for Ratatui 0.30.0 release 🎉 by
@j-g00da in [#2000](https://github.com/ratatui/ratatui/pull/2000)

-
[9836f07](9836f0760d)
_(uncategorized)_ Add AI contribution guidelines by @joshka in
[#2013](https://github.com/ratatui/ratatui/pull/2013)

-
[98f85b8](98f85b8650)
_(uncategorized)_ Update link to scrollable widgets RFC by @MatrixFrog
in [#1994](https://github.com/ratatui/ratatui/pull/1994)

-
[055522e](055522ef7b)
_(uncategorized)_ Add docs for authoring widget crates by @j-g00da in
[#1955](https://github.com/ratatui/ratatui/pull/1955)

  > - added Authoring Widget Libraries sub-section
  > - moved built-in and third-party widgets sections higher

-
[617d318](617d31851a)
_(uncategorized)_ Improve Block docs by @joshka in
[#1953](https://github.com/ratatui/ratatui/pull/1953)

-
[8e2d568](8e2d568428)
_(uncategorized)_ Improve layout related docs by @joshka in
[#1948](https://github.com/ratatui/ratatui/pull/1948)

> Adds module level docs and more comprehensive docs on all the types in
  > the layout module
  >
  > Fixes #1937

-
[4c708dd](4c708ddf8a)
_(uncategorized)_ Improve docs for run/init/restore etc. by @joshka in
[#1947](https://github.com/ratatui/ratatui/pull/1947)

  > - **docs: document the init module**
  > - **docs: use the ratatui::run() methods in the main doc**
> - **docs: add more intradoc / website links and historical perspective
  >   on Terminal / backend**
  > - **docs: add notes about new run/init/restore methods and the
  >   defaultterminal type to terminal docs**

-
[5620e06](5620e06b1a)
_(uncategorized)_ Add crate organization sections to workspace by
@joshka in [#1946](https://github.com/ratatui/ratatui/pull/1946)

  > Adds summary-level crate organization documentation to all crates
> explaining the modular workspace structure and when to use each crate.
  > Links to ARCHITECTURE.md for detailed information.

-
[cfb65e6](cfb65e64ba)
_(uncategorized)_ Add examples for handling state by @joshka in
[#1849](https://github.com/ratatui/ratatui/pull/1849)

> Added comprehensive state management examples covering both immutable
  > and mutable patterns and documentation to help developers choose the
  > right approach for their applications.

-
[3de41a8](3de41a8249)
_(uncategorized)_ Document widgets module by @joshka in
[#1932](https://github.com/ratatui/ratatui/pull/1932)

  > Adds a good overview of the use and implementation of widget traits.
  >
  > Goals with the doc rewrite:
  >
> - document the rationale for the ratatui-widgets crate with info for
app
  >   builders and widget makers.
  > - Show how to use the widgets for rendering as well as implement the
  >   traits- document the differences and reasons for each trait
  > - document the historical perspective (to make it easy to understand
  >   older Ratatui apps as well as migrate to newer approaches
  > - give recommended approaches to implementing traits
  > - explain the differences between Consuming and Shared / Mutable
  >   Reference implementations of Widget
  > - explain the differences between using StatefulWidget and Mutable
  >   References
  > - Explain the use case for WidgetRef and StatefulWidgetRef
  > - Link out to third part widget lists
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/366
  >
  > ***

-
[ca2ad4a](ca2ad4a1f9)
_(uncategorized)_ Simplify ratatui-macro docs by @joshka in
[#1923](https://github.com/ratatui/ratatui/pull/1923)

-
[92b6a16](92b6a16bde)
_(uncategorized)_ Fix grammar in ratatui-widgets README by @sevki in
[#1885](https://github.com/ratatui/ratatui/pull/1885)

-
[da05957](da05957fa0)
_(uncategorized)_ Add widget-ref-container example by @joshka in
[#1603](https://github.com/ratatui/ratatui/pull/1603)

  > Implements ideas alluded to by
>
<https://discord.com/channels/1070692720437383208/1072907135664529508/1323061053990637640>
  > and followup conversations.

-
[1798512](1798512e94)
_(uncategorized)_ Fix wording in user_input example by @dawedawe in
[#1611](https://github.com/ratatui/ratatui/pull/1611)

  > Fix wording in `user_input.rs` example.

-
[03066d8](03066d81bf)
_(uncategorized)_ Fix punctuation in canvas.rs documentation by
@dawedawe in [#1583](https://github.com/ratatui/ratatui/pull/1583)

  > Fix end of sentence punctuation in canvas.rs docs.

-
[e411d9e](e411d9ec3e)
_(uncategorized)_ Add input form example by @joshka in
[#1551](https://github.com/ratatui/ratatui/pull/1551)

  > Demonstrates how to manage the cursor and input focus with a simple
  > form. Uses an enum to track the current input field and passes the
  > input events to the active field.
  >
> This is similar to the json tutorial on the website, but a bit simpler

-
[ed071f3](ed071f3723)
_(uncategorized)_ Add mouse-drawing example by @joshka in
[#1546](https://github.com/ratatui/ratatui/pull/1546)

  > Demonstrates how to handle mouse events

-
[46902f5](46902f5587)
_(uncategorized)_ Improve docs for workspace crates by @orhun in
[#1490](https://github.com/ratatui/ratatui/pull/1490)

> Overall makes improvements in the documentation of the workspace
crates and checking them.

-
[a6b5792](a6b579223f)
_(uncategorized)_ Fix example link in readme by @thomas-tacquet in
[#1462](https://github.com/ratatui/ratatui/pull/1462)

### Performance

-
[1f41a61](1f41a61008)
_(paragraph)_ Avoid unnecessary work when rendering by @alexpasmantier
in [#1622](https://github.com/ratatui/ratatui/pull/1622)

  > Improve render times for paragraphs that are scrolled.
  >
> Currently all `LineComposer`s are considered to be state machines
which
> means rendering a paragraph with a given Y offset requires computing
the
  > entire state up to Y before being able to render from Y onwards.
  >
> While this makes sense for Composers such as the `WordWrapper` (where
> one needs to consider all previous lines to determine where a given
line
> will end up), it means it also penalizes Composers which can render a
> given line "statelessely" (such as the `LineTruncator`) which actually
> end up doing a lot of unnecessary work (and on the critical rendering
  > path) when the offset gets high.

-
[ba9eed7](ba9eed7742)
_(table)_ Replace while loop with simple min operation by @EdJoPaTo in
[#1747](https://github.com/ratatui/ratatui/pull/1747)

### Styling

-
[ac60de3](ac60de3960)
_(uncategorized)_ Fix wrapping in doc comment by @joshka in
[#2104](https://github.com/ratatui/ratatui/pull/2104)

-
[2739391](2739391950)
_(uncategorized)_ Use Module imports_granularity by @joshka in
[#1728](https://github.com/ratatui/ratatui/pull/1728)

> I was swayed by the arguments about this made by the compiler team In
> <https://github.com/rust-lang/compiler-team/issues/750> and decided to
> look at how this organization affects ratatui. I found this reduces
the
> number of lines across the codebase by about 350 and makes the imports
  > more readable and definitely more greppable as you usually only have
> to read a single line. I've found in the past that maintaining imports
  > regularly leads to merge conflicts which have to be resolved by hand
  > and this change should reduce the likelihood of that happening.
  >
  > Main change is in rustfmt.toml, and the rest is just the result of
  > running `cargo xtask format`.
  >
  > While implementing this, cargo machete brings up that the various
  > backend crates are unused by the example crates.
  >
> The re-export of each backend crate under ratatui is to make it
possible
  > for libs that rely on a specific version of ratatui to use the same
  > version of the backend crate. Apps in general should use the backend
> crate directly rather than through ratatui as this is less confusing.
  >
> - Removes all usages of `ratatui::{crossterm, termion, termwiz}`` in
the
  >   examples.
> - Adds the backend crate to the dependencies of the examples that use
  >   the backend crate directly.

### Testing

-
[db65aa0](db65aa0ef7)
_(bench)_ Add benchmark for text by @orhun in
[#2160](https://github.com/ratatui/ratatui/pull/2160)

  > #2138
  >
  > ***

-
[a21501f](a21501f7f4)
_(bench)_ Added a benchmark for constraints by @kashregister in
[#2043](https://github.com/ratatui/ratatui/pull/2043)

  > I've added a new benchmark for constraints, which only takes into
> account the time it takes to generate a full layout using a single
type
  > of constraints only. Avoided rendering here as it resulted in more
> inaccurate benchmarks, and i believe it should be separated
nonetheless.

-
[39cd313](39cd313b3b)
_(layout)_ Add visual buffer tests for Rect methods by @orhun in
[#2124](https://github.com/ratatui/ratatui/pull/2124)

-
[8aefc06](8aefc06a90)
_(macros)_ Regenerate trybuild stderr by @ognis1205 in
[#2093](https://github.com/ratatui/ratatui/pull/2093)

  > ### Overview
  >
  > Updated the `.stderr` file corresponding to the
  > `ratatui-macros/tests/ui/fails.rs` compile-fail test.
  >
  > ### Changes
  >
  > - Updated `tests/ui/fails.stderr` to match the new compiler output.
  >
  > ### Impact
  >
  > - Affects only the trybuild UI tests
  > - No impact on production code
  >
  > ### Notes
  >
  > - The `.stderr` was generated using `TRYBUILD=overwrite cargo test`.
  >
  > Closes https://github.com/ratatui/ratatui/issues/2094

-
[deb1b8e](deb1b8ec43)
_(uncategorized)_ Ensure Style::new() and Style::default() are
equivalent by @cgzones in
[#1789](https://github.com/ratatui/ratatui/pull/1789)

### Miscellaneous Tasks

-
[abe2f27](abe2f27328)
_(backend)_ Change From<T> impls to new backend specific IntoBackend and
FromBackend traits by @joshka in
[#1464](https://github.com/ratatui/ratatui/pull/1464) [**breaking**]

  > Adds two traits `IntoCrossterm` and `FromCrossterm` for converting
> between ratatui and crossterm types. This is necessary in order to
avoid
> the orphan rule when implementing `From` for crossterm types once the
  > crossterm types are moved to a separate crate.
  >
> Similarly Termwiz and Termwiz gain FromTermion, IntoTermion,
FromTermwiz
  > and IntoTermwiz traits.
  >
> BREAKING CHANGE:The `From` and `Into` impls for backend types are now
  > replaced
  > with specific backend traits.
  >
  > ```diff
  > + use ratatui::backend::{FromCrossterm, IntoCrossterm};
  >
  > let crossterm_color = crossterm::style::Color::Black;
  > - let ratatui_color = crossterm_color.into();
  > - let ratatui_color = ratatui::style::Color::from(crossterm_color);
> + let ratatui_color =
ratatui::style::Color::from_crossterm(crossterm_color);
  > - let crossterm_color = ratatui_color.into();
> - let crossterm_color = crossterm::style::Color::from(ratatui_color);
  > + let crossterm_color = ratatui_color.into_crossterm();
  >
  > let crossterm_attribute = crossterm::style::types::Attribute::Bold;
  > - let ratatui_modifier = crossterm_attribute.into();
> - let ratatui_modifier =
ratatui::style::Modifier::from(crossterm_attribute);
> + let ratatui_modifier =
ratatui::style::Modifier::from_crossterm(crossterm_attribute);
  > - let crossterm_attribute = ratatui_modifier.into();
> - let crossterm_attribute =
crossterm::style::types::Attribute::from(ratatui_modifier);
  > + let crossterm_attribute = ratatui_modifier.into_crossterm();
  > ```
  >
> Similar conversions for `ContentStyle` -> `Style` and `Attributes` ->
  > `Modifier` exist for Crossterm,
  > and all the Termion and Termwiz types.
  >
  > ***

-
[0a47ebd](0a47ebd94b)
_(bencher)_ Update bencher CLI usage by @epompeii in
[#1470](https://github.com/ratatui/ratatui/pull/1470)

-
[b46778d](b46778dd1d)
_(breaking-changes)_ Add details to `no_std`-related breaking changes by
@j-g00da in [#1828](https://github.com/ratatui/ratatui/pull/1828)

  > Some corrections and added details to BREAKING-CHANGES.md.
  >
  > I decided to remove:
  >
  > - `Backend` now uses `Self::Error` for error handling instead of
  >   `std::io::Error`
  > - `Terminal<B>` now uses `B::Error` for error handling instead of
  >   `std::io::Error`
  >
> ...as we are still using `std::io::Error` in built-in backends, so
this
> will only be breaking if a third-party backend decides to use a custom
> error other than `std::io::Error`, which would be a breaking change in
  > downstream and not `ratatui`.
  >
  > The exception to that is `TestBackend`, which uses `Infallible`, but
  > this already has its own breaking changes entry.

-
[a0979d6](a0979d6871)
_(build)_ Remove cargo lint by @joshka in
[#1549](https://github.com/ratatui/ratatui/pull/1549)

  > Duplicate crate lint is too noisy and sensitive to upstream changes

-
[ae43ea7](ae43ea796a)
_(cell)_ Use Option instead of space (" ") for symbol by @joshka

> This change makes the `Cell::symbol` field an `Option<CompactString>`,
  > allowing it to represent an empty cell as `None` instead of an empty
  > string. The rationale for this is to later allow the merge symbol
> functionality to act differently based on whether a cell has
previously
> held a symbol or not, rather than always merging with an empty string.
> This will help make it possible to merge borders with titles with
spaces
  > and other symbols, without assuming that an empty string is always
  > equivalent to no symbol.
  >
  > - Default is now derived as `Option::None` works correctly.
> - PartialEq and Eq implementations are updated to treat `None` the
same
  >   as an empty string.
  > - merge_symbol against an empty cell will now just set the symbol
  >   rather than calling MergeStrategy::merge with an empty string.
  > - PartialEq, and Hash are manually implemented instead of being
  >   derived, and are updated to treat `None` equal to an empty string.

-
[887a636](887a6366e5)
_(ci)_ Override RUSTUP_TOOLCHAIN for the check step by @ognis1205 in
[#2116](https://github.com/ratatui/ratatui/pull/2116)

  > Summary
  > Fixes an issue where the "check" CI jobs for MSRV and stable were
> unintentionally using the stable toolchain from `rust-toolchain.toml`
  > instead of the matrix-specified toolchain.
  >
  > Details
  >
> - Added `RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}` to the "check" job
  >   in CI configuration.
  >
  > Additional Context
  >
  > - https://github.com/ratatui/ratatui/pull/2106
> -
https://discord.com/channels/1070692720437383208/1072879985762762812/1422345357131780177
  > - https://rust-lang.github.io/rustup/overrides.html#overrides

-
[34baaf1](34baaf1137)
_(ci)_ Override the toolchain for CI runs by @ognis1205 in
[#2106](https://github.com/ratatui/ratatui/pull/2106)

  > ### Summary
  >
  > Fixes an issue where the beta CI jobs were unintentionally using the
  > stable
  > toolchain from `rust-toolchain.toml` instead of the matrix-specified
  > toolchain.
  > This caused clippy to run against the wrong version.
  >
  > ### Details
  >
  > - Added `RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}` to the CI
  >   configuration
  >
  > ### Additional Context
  >
> -
https://discord.com/channels/1070692720437383208/1072879985762762812/1421990770482745415
  > - https://rust-lang.github.io/rustup/overrides.html#overrides

-
[e48aa9e](e48aa9ec09)
_(ci)_ Stop publish-alpha from running on forks by @j-g00da in
[#1916](https://github.com/ratatui/ratatui/pull/1916)

> I can't sleep because every Saturday alpha release fails on my ratatui
  > fork. This should fix my insomnia.

-
[b3f3c9b](b3f3c9bfd5)
_(ci)_ Disable running release-plz on forked repositories by @orhun in
[#1730](https://github.com/ratatui/ratatui/pull/1730)

  > See https://github.com/jdssl/ratatui/pull/1#issuecomment-2739366609

-
[eaa4038](eaa403856e)
_(ci)_ Install pre-built binaries for cargo-rdme by @orhun in
[#1477](https://github.com/ratatui/ratatui/pull/1477)

> `install-action` uses `cargo-binstall` to install the pre-built
binaries
  > of `cargo-rdme` (which was released in
  > https://github.com/orium/cargo-rdme/releases/tag/v1.4.7).
  >
> This will make the `check-readme` step faster in CI (now takes only 10
  > seconds).

-
[e5e2316](e5e2316451)
_(ci)_ Add check for keeping README.md up-to-date by @orhun in
[#1473](https://github.com/ratatui/ratatui/pull/1473)

-
[2ef3583](2ef3583eff)
_(ci)_ Replace cargo-make with a custom cargo-xtask by @joshka in
[#1461](https://github.com/ratatui/ratatui/pull/1461)

> This removes the need for cargo-make and replaces it with a custom
xtask
  > binary. See <https://github.com/matklad/cargo-xtask> for info.
  >
  > Rearranges the CI workflow to use the new xtask and simplify which
  > workflows that run.
  >
  > ***

-
[98df774](98df774d7f)
_(core)_ Move core types to ratatui-core by @joshka in
[#1460](https://github.com/ratatui/ratatui/pull/1460)

> The buffer, layout, style, symbols, text, and the top level of widgets
  > modules are moved to ratatui-core. This is the first step in
  > modularizing the library so that the core types can be used in other
  > projects without the need for the backend / widgets types.
  >
  > This helps reduce the need for updating other crates as often due to
  > semver changes outside of the core types.
  >
  > ***

-
[35eba76](35eba76b4d)
_(example)_ Move demo2 to top level folder by @joshka in
[#1524](https://github.com/ratatui/ratatui/pull/1524)

-
[5f57d35](5f57d35234)
_(examples)_ Add colors explorer demo app by @orhun in
[#1580](https://github.com/ratatui/ratatui/pull/1580)

  > related #1512
  >
  > Moves the colors examples to apps

-
[5c021bf](5c021bf344)
_(examples)_ Add chart demo app by @orhun in
[#1579](https://github.com/ratatui/ratatui/pull/1579)

  > related #1512
  >
  > Moves the chart example to apps

-
[9721300](9721300a47)
_(examples)_ Add canvas demo app by @orhun in
[#1578](https://github.com/ratatui/ratatui/pull/1578)

  > related #1512
  >
> This moves the canvas example to the apps and adds some interactivity
  > via changing the marker by pressing enter.

-
[a6a1368](a6a1368250)
_(examples)_ Add calendar explorer demo app by @orhun in
[#1571](https://github.com/ratatui/ratatui/pull/1571)

  > Related to #1512
  >
  > As discussed, this moves the calendar example from ratatui to app
> examples as an "explorer" example. It also adds interactivity where
you
  > can press s to toggle between different styles of calendars.
  >
  > ***

-
[819e92c](819e92cd44)
_(examples)_ Add weather demo app by @orhun in
[#1567](https://github.com/ratatui/ratatui/pull/1567)

  > related to #1512

-
[b5f7e44](b5f7e44183)
_(examples)_ Move async example to apps by @joshka in
[#1503](https://github.com/ratatui/ratatui/pull/1503)

  > Move async example to examples/apps/async as full project.
  > Simplify a little by removing the need for the github api token.

-
[17316ec](17316ec5d0)
_(github)_ Enable sponsorship button by @orhun in
[#1478](https://github.com/ratatui/ratatui/pull/1478)

-
[d02995f](d02995fda1)
_(gitignore)_ Add `.env` to `.gitignore` by @j-g00da in
[#1949](https://github.com/ratatui/ratatui/pull/1949)

-
[b4a71e5](b4a71e5fd5)
_(lint)_ Add `std` instead of `core`/`alloc` lints to `ratatui-widgets`
by @j-g00da in [#1763](https://github.com/ratatui/ratatui/pull/1763)

  > Resolves #1761

-
[cef617c](cef617cc35)
_(lint)_ Add `std` instead of `core`/`alloc` lints to `ratatui-core` by
@j-g00da in [#1759](https://github.com/ratatui/ratatui/pull/1759)

  > Resolves #1752

-
[d3f01eb](d3f01ebf6e)
_(lint)_ Ensure lint config is correct by @joshka in
[#1528](https://github.com/ratatui/ratatui/pull/1528)

  > - Move lints to workspace manifest
  > - Add lint config to backend crates
  > - Fix one small lint error

-
[9fb0544](9fb054453d)
_(release)_ Initialize release-plz by @orhun in
[#1550](https://github.com/ratatui/ratatui/pull/1550)

  > See https://github.com/ratatui/ratatui/pull/1550

-
[60a8191](60a81913ed)
_(widgets)_ Move crossterm to dev-dependencies by @j-g00da in
[#1834](https://github.com/ratatui/ratatui/pull/1834)

  > Crossterm in widgets is used only in tests.

-
[2b7ec5c](2b7ec5cb7f)
_(widgets)_ Enable calendar widget as default by @orhun in
[#1521](https://github.com/ratatui/ratatui/pull/1521)

  > We now expect that you disable the default features if you want less
  > dependencies

-
[d201b8e](d201b8e5dd)
_(xtask)_ Check lints for only library targets by @orhun in
[#1531](https://github.com/ratatui/ratatui/pull/1531)

  > Makes it possible to filter workspace packages by their targets.
> (e.g. when we want to retrieve all the binary targets / examples,
etc.)

-
[297d264](297d264c6b)
_(uncategorized)_ Update maintainers by @orhun in
[#2122](https://github.com/ratatui/ratatui/pull/2122)

-
[91fa249](91fa249cd4)
_(uncategorized)_ Remove obsolete doc_auto_cfg feature by @ognis1205 in
[#2103](https://github.com/ratatui/ratatui/pull/2103)

  > The doc_auto_cfg feature was incorporated into the doc_cfg feature
  > in https://github.com/rust-lang/rust/pull/138907
  >
  > Closes #2102

-
[46e7c6c](46e7c6cbbf)
_(uncategorized)_ Document rustfmt options by @joshka in
[#2055](https://github.com/ratatui/ratatui/pull/2055)

-
[719badb](719badb5b8)
_(uncategorized)_ Skip `alpha` and `beta` tags in `cliff.toml` by
@j-g00da in [#2026](https://github.com/ratatui/ratatui/pull/2026)

  > https://github.com/ratatui/ratatui/pull/2025#issuecomment-3135177683

-
[0afb1a9](0afb1a99af)
_(uncategorized)_ Ignore `beta` and `rc` tags in `cliff.toml` by
@j-g00da in [#2025](https://github.com/ratatui/ratatui/pull/2025)

-
[5ae224b](5ae224b244)
_(uncategorized)_ Prepare for beta release by @j-g00da in
[#2022](https://github.com/ratatui/ratatui/pull/2022)

-
[cfebd68](cfebd68e18)
_(uncategorized)_ Fix typo in CONTRIBUTING.md by @kdheepak in
[#2001](https://github.com/ratatui/ratatui/pull/2001)

  > Removes a hanging opening code block:
  >
  > ````
  > ```suggestion
  > ````

-
[572749f](572749f388)
_(uncategorized)_ Update contributing guidelines and add
copilot-instructions by @joshka in
[#1998](https://github.com/ratatui/ratatui/pull/1998)

  > See
>
https://docs.github.com/en/copilot/how-tos/agents/copilot-code-review/using-copilot-code-review
  >
> These instructions will be used by copilot when it performs automated
PR
> reviews, and helps provide guardrails for our standards. Over time we
> might grow these to capture any consistent problems that we start
seeing
  > when reviewing.
  >
  > ***

-
[0148b62](0148b62f0c)
_(uncategorized)_ Remove cargo_metadata dep from xtask by @joshka in
[#1993](https://github.com/ratatui/ratatui/pull/1993)

  > Removed due to hard N-2 MSRV requirement, whereas we use a soft N-2
> (only update when necessary). This makes it painful to be able to test
> our actual msrv (as the xtask has to be built with the version that
its
> deps support, while still wanting to check the msrv version, so we'd
end
  > up with 2 versions in the one CI task and this would get annoying to
  > check).
  >
> See https://github.com/rust-lang/cargo/issues/15746 for more details.
  >
> Partially implements #1820 - mainly as a problem solution rather than
a
  > specific goal to use cargo-hack

-
[9bc5739](9bc573931c)
_(uncategorized)_ Remove clap-cargo from xtask by @joshka in
[#1992](https://github.com/ratatui/ratatui/pull/1992)

  > Removed to avoid needing to bump our msrv. See
>
https://github.com/rust-lang/cargo/issues/15746\#issuecomment-3071774343
  > for more details.

-
[0e10170](0e10170e19)
_(uncategorized)_ Change Borders::NONE to a proper const by @joshka in
[#1985](https://github.com/ratatui/ratatui/pull/1985)

  > https://docs.rs/bitflags/latest/bitflags/#zero-bit-flags
  >
  > > Flags with no bits set should be avoided because they interact
  > > strangely with
  >
>
[Flags::contains](https://docs.rs/bitflags/latest/bitflags/trait.Flags.html#method.contains)
  > and
  >
>
[Flags::intersects](https://docs.rs/bitflags/latest/bitflags/trait.Flags.html#method.intersects).
> A zero-bit flag is always contained, but is never intersected. The
names
  > of zero-bit flags can be parsed, but are never formatted.
  >
> Removing this simplifies the manual Debug impl that previously had to
  > check for Borders::NONE and now does not.

-
[8e3bd11](8e3bd11d60)
_(uncategorized)_ Add svg logo asset by @LitoMore in
[#1967](https://github.com/ratatui/ratatui/pull/1967)

> Added a shields.io style svg logo and a nicer version of the original
logo.
> The simplified icon will be added and available directly from
shields.io via:
  >
  > - https://github.com/simple-icons/simple-icons/pull/13593

-
[92bb9b2](92bb9b2219)
_(uncategorized)_ Remove `Title` references by @j-g00da in
[#1943](https://github.com/ratatui/ratatui/pull/1943)

-
[d6647db](d6647db744)
_(uncategorized)_ Remove some allow attributes for fixed clippy bugs by
@joshka in [#1944](https://github.com/ratatui/ratatui/pull/1944)

-
[3f48bde](3f48bde3c6)
_(uncategorized)_ Remove OpenSSL license by @joshka in
[#1942](https://github.com/ratatui/ratatui/pull/1942)

  > Only keep licenses in the allow list that are actually used

-
[4c86513](4c86513790)
_(uncategorized)_ Remove block::Title by @joshka in
[#1926](https://github.com/ratatui/ratatui/pull/1926)

> The title alignment is better expressed in the `Line` as this fits
more
  > coherently with the rest of the library.
  >
  > BREAKING CHANGES:
  >
  > - `widgets::block` is no longer exported
  > - `widgets::block::Title` no longer exists
  > - `widgets::block::Position` is now `widgets::TitlePosition`
> - `Block::title()` now accepts `Into::<Line>` instead of `Into<Title>`
  > - `BlockExt` is now exported at widgets::`BlockExt`
  >
  > Closes:https://github.com/ratatui/ratatui/issues/738

-
[272f5c0](272f5c05dc)
_(uncategorized)_ Fix new lints by @joshka in
[#1922](https://github.com/ratatui/ratatui/pull/1922)

-
[770cb7c](770cb7c3c3)
_(uncategorized)_ Add tests for combining list styles by @joshka in
[#1884](https://github.com/ratatui/ratatui/pull/1884)

-
[dbfb2c3](dbfb2c3399)
_(uncategorized)_ Upgrade to Rust Edition 2024 by @MatrixFrog in
[#1863](https://github.com/ratatui/ratatui/pull/1863)

  > https://doc.rust-lang.org/edition-guide/rust-2024/index.html
  >
  > Fixes #1727

-
[7cb35d4](7cb35d4be1)
_(uncategorized)_ Update to Rust version 1.85.0 by @MatrixFrog in
[#1860](https://github.com/ratatui/ratatui/pull/1860)

  > This is a small step toward fixing #1727

-
[a07f5be](a07f5bec20)
_(uncategorized)_ Move dependency management to workspace by @joshka in
[#1858](https://github.com/ratatui/ratatui/pull/1858)

  > Move all dependency management to the workspace level. This makes it
> easier to manage dependencies across multiple crates in the workspace.
  >
> This also changes the versions of each dependency to track based on
the
> semver compatible version of the dependency (e.g. 0.1 instead of 0.1.0
  > or 2.9 instead of 2.9.0 to avoid having to regularly update the toml
  > files and to communicate that Ratatui will still generally work with
> versions of the dependencies that are not the fully latest version.
The
  > exact version of the dependencies is still tracked in the Cargo.lock
  > file.
  >
> Several dependencies that are fairly stable are changed to track a
less
  > specific version (e.g. serde 1 instead of 1.0.x).
  >
  > The following dependencies are updated to their latest versions:
  >
  > - bitflags (2.3 -> 2.9)
  > - strum (0.26 -> 0.27)
  > - strum_macros (0.26 -> 0.27)
  > - all other semver compatible updates

-
[1874b9d](1874b9dd55)
_(uncategorized)_ Move time to dev-dependencies by @j-g00da in
[#1835](https://github.com/ratatui/ratatui/pull/1835)

-
[d88cd29](d88cd29079)
_(uncategorized)_ Add 'const' to functions where possible. by
@MatrixFrog in [#1802](https://github.com/ratatui/ratatui/pull/1802)

> The Clippy check for this (missing_const_for_fn) is already enabled,
but
  > catches more cases in upcoming toolchain versions.
  >
  > This is part of the work to unblock #1727

-
[bb06889](bb068892c9)
_(uncategorized)_ Fix io_other_error clippy lints by @joshka in
[#1756](https://github.com/ratatui/ratatui/pull/1756)

> Pre-emptive fix for new lint to be added in 1.87 (currently in beta).
  >
>
https://rust-lang.github.io/rust-clippy/master/index.html\#io_other_error

-
[0f80c5e](0f80c5e87e)
_(uncategorized)_ Use expect() instead of allow() for lint overrides by
@cgzones in [#1786](https://github.com/ratatui/ratatui/pull/1786)
[**breaking**]

  > BREAKING CHANGE:MSRV is now 1.81

-
[fe8577c](fe8577c070)
_(uncategorized)_ Remove paste dependency by @joshka in
[#1713](https://github.com/ratatui/ratatui/pull/1713)

> The paste crate is no longer maintained. Replaces the usages of this
in
> the Stylize declarative macros with hard coded values. These macros
are
> internal implementation detail to ratatui and so the changes should
have
  > no impact on users.
  >
  > Fixes:https://github.com/ratatui/ratatui/issues/1712

-
[255e466](255e4661a8)
_(uncategorized)_ Cargo update - pull in fixed version of ring crate by
@joshka in [#1710](https://github.com/ratatui/ratatui/pull/1710)

-
[f05feac](f05feac337)
_(uncategorized)_ Sort dependencies in Cargo.toml by @canac in
[#1662](https://github.com/ratatui/ratatui/pull/1662)

-
[7eab88f](7eab88fe9a)
_(uncategorized)_ Remove unused deps by @joshka in
[#1661](https://github.com/ratatui/ratatui/pull/1661)

-
[37a1c6f](37a1c6f89b)
_(uncategorized)_ Remove some examples by @orhun in
[#1645](https://github.com/ratatui/ratatui/pull/1645)

-
[6f21319](6f213191ef)
_(uncategorized)_ Rename examples with clashing names by @joshka in
[#1597](https://github.com/ratatui/ratatui/pull/1597)

> These will eventually be moved / consolidated elsewhere, but this
clears
  > the warnings while building for now.

-
[11cbb2b](11cbb2ba87)
_(uncategorized)_ Use cargo xtask for bacon clippy command by @joshka in
[#1592](https://github.com/ratatui/ratatui/pull/1592)

-
[b544e39](b544e394c9)
_(uncategorized)_ Use clap instead of argh for demo example by @joshka
in [#1591](https://github.com/ratatui/ratatui/pull/1591)

-
[9a54198](9a541981b8)
_(uncategorized)_ Make source files non-executable by @orhun in
[#1577](https://github.com/ratatui/ratatui/pull/1577)

  > ```bash
> find . -type f -not -path './.git/*' -not -name '*.bash' -exec chmod
644 {} +
  > ```
  >
  > fixes #1576

-
[357ae7e](357ae7e251)
_(uncategorized)_ Move terminal types to ratatui-core by @joshka in
[#1530](https://github.com/ratatui/ratatui/pull/1530) [**breaking**]

  > - Move Terminal, TerminalOptions, ViewPort, CompletedFrame, Frame to
  >   ratatui-core crate
> - Move render_widget_ref() and render_stateful_widget_ref() to
extension
  >   trait (FrameExt) due as the Ref types are unstable and kept in the
  >   main lib instead of -core
  > - Fix rustdoc errors / feature config issues
  >
  > BREAKING CHANGE:to call `Frame::render_widget_ref()` or
  >
  > `Frame::render_stateful_widget_ref()` you now need to import the
  > FrameExt trait from `ratatui::widgets` and enable the
  > `unstable-widget-ref` feature.

-
[21e62d8](21e62d84c2)
_(uncategorized)_ Move the demo example to main folder by @joshka in
[#1523](https://github.com/ratatui/ratatui/pull/1523)

  > Add a top level examples folder for more app-ish examples
  > Move the demo example into the top level folder.
  >
  > ***

-
[fbf6050](fbf6050c86)
_(uncategorized)_ Prepare alpha modularization release by @joshka in
[#1525](https://github.com/ratatui/ratatui/pull/1525)

> This is the first modularization -alpha release. It captures the
changes
  > necessary to manual publish. And ensures all the crates are properly
> setup and to set a baseline for comparison in future release checks
etc.
  >
  > This does not update / check the git-cliff setup / changelog
  >
  > Part of: #1388

-
[e4e95bc](e4e95bcecf)
_(uncategorized)_ Remove --color always flags from bacon.toml by @joshka
in [#1502](https://github.com/ratatui/ratatui/pull/1502)

  > No longer necessary as of bacon 3.3

-
[a41c97b](a41c97b413)
_(uncategorized)_ Move unstable widget refs to ratatui by @joshka in
[#1491](https://github.com/ratatui/ratatui/pull/1491) [**breaking**]

  > These are less stable than the non-ref traits as we have not yet
  > committed to the exact API. This change moves them to ratatui from
  > ratatui-core.
  >
  > To facilitate this:
  >
> - implementations of WidgetRef for all internal widgets are removed
and
  >   replaced with implementations of Widget for references to those
  >   widgets.
> - Widget is now implemented for Option<W> where W: Widget, allowing
for
  >   rendering of optional widgets.
> - The blanket implementation of Widget for WidgetRef is reversed, to
be
  >   a blanket implementation of WidgetRef for all &W where W: Widget.
  >
> BREAKING CHANGE:implementations of WidgetRef no longer have a blanket
  > implementation of Widget, so Widgets should generally implement the
  > Widget trait on a reference to the widget rather than implementing
  > WidgetRef directly. This has the advantage of not requiring unstable
  > features to be enabled.
  >
  > Part of: https://github.com/ratatui/ratatui/issues/1388

-
[e7085e3](e7085e3a3e)
_(uncategorized)_ Move widgets into ratatui-widgets crate by @joshka in
[#1474](https://github.com/ratatui/ratatui/pull/1474)

> All the widgets now live in their own ratatui-widgets crate, but are
re-exported in the main ratatui crate.
> This makes it easier to use portions of the ratatui library and is
part of the effort to modularize
  >
  > Part of: #1388
  >
  > ***

-
[f1d0a18](f1d0a18375)
_(uncategorized)_ Move ratatui crate into workspace folder by @joshka in
[#1459](https://github.com/ratatui/ratatui/pull/1459)

  > This is the first step towards modularization. Handling the move
  > as a separate step rather than combining it should make it easier
  > to rebase other PRs when necessary.
  >
  > ***

-
[55fb2d2](55fb2d2e56)
_(uncategorized)_ Update repo links to ratatui instead of ratatui-org by
@joshka in [#1458](https://github.com/ratatui/ratatui/pull/1458)

### Continuous Integration

-
[c01b7d4](c01b7d43ea)
_(uncategorized)_ Remove old release workflows by @joshka in
[#2015](https://github.com/ratatui/ratatui/pull/2015)

-
[02ca587](02ca5870c5)
_(uncategorized)_ Add environment to release workflow by @joshka in
[#1983](https://github.com/ratatui/ratatui/pull/1983)

>
https://github.com/rust-lang/crates.io/issues/11564#issuecomment-3066696820

-
[821611f](821611f76f)
_(uncategorized)_ Use trusted publishing by @joshka in
[#1981](https://github.com/ratatui/ratatui/pull/1981)

>
https://blog.rust-lang.org/2025/07/11/crates-io-development-update-2025-07/
  >
  > https://crates.io/docs/trusted-publishing

-
[1f0c2ee](1f0c2ee18e)
_(uncategorized)_ Audit github workflows with zizmor by @joshka in
[#1961](https://github.com/ratatui/ratatui/pull/1961)

  > Fixes https://github.com/ratatui/ratatui/issues/1950

-
[a0746ba](a0746bad7e)
_(uncategorized)_ Add job to check no-std build by @joshka in
[#1851](https://github.com/ratatui/ratatui/pull/1851)

> Uses x86_64-unknown-none as an arbitrary target that does not support
  > the std library
  >
  > Resolves:https://github.com/ratatui/ratatui/issues/1843

-
[5a3be12](5a3be12ebd)
_(uncategorized)_ Run clippy using rust stable and beta by @joshka in
[#1757](https://github.com/ratatui/ratatui/pull/1757)

> This makes it possible to pre-emptively catch upcoming clippy issues.
We
  > should not block PRs on these generally (unless the PR introduces a
> valid clippy warning), so the workflow is set up to not fail on beta.

-
[e7defb3](e7defb36de)
_(uncategorized)_ Remove bencher workflows by @joshka in
[#1719](https://github.com/ratatui/ratatui/pull/1719)

  > These actions are currently unused as we haven't
  > invested the time necessary to understand how best
  > to use them. We can always re-add them later if we
  > find them useful.

-
[9398a25](9398a2550a)
_(uncategorized)_ Add workflow_dispatch trigger for release-plz by
@joshka in [#1693](https://github.com/ratatui/ratatui/pull/1693)

-
[57c2326](57c2326574)
_(uncategorized)_ Run cargo-deny directly rather than via action by
@joshka in [#1621](https://github.com/ratatui/ratatui/pull/1621)

  > Improves CI time

-
[4a871f9](4a871f993e)
_(uncategorized)_ Refactor xtask / toml formatting by @joshka in
[#1602](https://github.com/ratatui/ratatui/pull/1602)

  > - format toml files using taplo
  > - add toml formatting check to CI
  > - use xtask consistently from bacon
> - refactor xtask commands to take params instead of multiple commands

### Reverted Commits

-
[cace1e0](cace1e099c)
_(release)_ Prepare for beta release by @orhun in
[#2117](https://github.com/ratatui/ratatui/pull/2117)

  > This reverts commit 5ae224b244 so that
  > `release-plz` is being triggered again.
  >
> See
https://github.com/ratatui/ratatui/pull/2022#issuecomment-3349094310
  > for rationale.

</details>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
2025-11-01 02:22:55 +03:00
77 changed files with 6672 additions and 2103 deletions

View File

@@ -13,27 +13,43 @@ A detailed and complete issue is more likely to be processed quickly.
-->
## Description
<!--
A clear and concise description of what the bug is.
-->
## To Reproduce
<!--
Try to reduce the issue to a simple code sample exhibiting the problem.
Ideally, fork the project and add a test or an example.
-->
## Expected behavior
<!--
A clear and concise description of what you expected to happen.
-->
## Screenshots
<!--
If applicable, add screenshots, gifs or videos to help explain your problem.
-->
## Are you willing to contribute a fix?
<!--
If you would like to work on a fix, check one of the boxes below. Maintainers can help point
you to the right place in the codebase.
-->
- [ ] I am willing to open a PR for this bug.
- [ ] I can try to investigate, but I will need guidance.
- [ ] I am not able to work on a fix right now.
## Environment
<!--
Add a description of the systems where you are observing the issue. For example:
- OS: Linux
@@ -50,6 +66,7 @@ Add a description of the systems where you are observing the issue. For example:
- Backend:
## Additional context
<!--
Add any other context about the problem here.
If you already looked into the issue, include all the leads you have explored.

View File

@@ -8,11 +8,13 @@ assignees: ''
---
## Problem
<!--
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-->
## Solution
<!--
A clear and concise description of what you want to happen.
Things to consider:
@@ -22,11 +24,24 @@ Things to consider:
-->
## Alternatives
<!--
A clear and concise description of any alternative solutions or features you've considered.
-->
## Are you willing to contribute an implementation?
<!--
If you would like to work on this, check one of the boxes below. Maintainers can help refine
the scope and discuss approach.
-->
- [ ] I am willing to open a PR implementing this.
- [ ] I can try to implement it, but I will need guidance.
- [ ] I am not able to implement this right now.
## Additional context
<!--
Add any other context or screenshots about the feature request here.
-->

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Check semver

View File

@@ -29,15 +29,15 @@ jobs:
name: Check Formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: nightly
components: rustfmt
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: taplo-cli
- run: cargo xtask format --check
@@ -48,27 +48,32 @@ jobs:
name: Check Typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: crate-ci/typos@80c8a4945eec0f6d464eaf9e65ed98ef085283d1 # master
- uses: crate-ci/typos@bb4666ad77b539a6b4ce4eda7ebb6de553704021 # master
# Check for any disallowed dependencies in the codebase due to license / security issues.
# See <https://github.com/EmbarkStudios/cargo-deny>
dependencies:
name: Check Dependencies
cargo-deny:
runs-on: ubuntu-latest
strategy:
matrix:
checks:
- advisories
- bans licenses sources
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: ${{ matrix.checks == 'advisories' }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979 # v2
with:
toolchain: stable
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
with:
tool: cargo-deny
- run: cargo deny --log-level info --all-features check
rust-toolchain: stable
log-level: info
arguments: --all-features --exclude-unpublished
command: check ${{ matrix.checks }}
# Check for any unused dependencies in the codebase.
# See <https://github.com/bnjbvr/cargo-machete/>
@@ -76,7 +81,7 @@ jobs:
name: Check Unused Dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: bnjbvr/cargo-machete@7959c845782fed02ee69303126d4a12d64f1db18 # v0.9.1
@@ -95,14 +100,14 @@ jobs:
toolchain: ["stable", "beta"]
continue-on-error: ${{ matrix.toolchain == 'beta' }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: ${{ matrix.toolchain }}
components: clippy
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask clippy
env:
RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}
@@ -112,10 +117,10 @@ jobs:
name: Check Markdown
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20
- uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # v21
with:
globs: |
'**/*.md'
@@ -127,19 +132,19 @@ jobs:
name: Coverage Report
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
components: llvm-tools
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-llvm-cov
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask coverage
- uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5
- uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
@@ -151,19 +156,19 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
toolchain: ["1.85.0", "stable"]
toolchain: ["1.86.0", "stable"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: ${{ matrix.toolchain }}
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-hack
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask check --all-features
env:
RUSTUP_TOOLCHAIN: ${{ matrix.toolchain }}
@@ -172,14 +177,14 @@ jobs:
name: Build No-Std
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
targets: x86_64-unknown-none
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
# This makes it easier to debug the exact versions of the dependencies
- run: cargo tree --target x86_64-unknown-none -p ratatui-core
- run: cargo tree --target x86_64-unknown-none -p ratatui-widgets
@@ -195,11 +200,11 @@ jobs:
name: Check README
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-rdme
- run: cargo xtask readme --check
@@ -212,19 +217,19 @@ jobs:
env:
RUSTDOCFLAGS: -Dwarnings
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: nightly
- uses: dtolnay/install@74f735cdf643820234e37ae1c4089a08fd266d8a # master
with:
crate: cargo-docs-rs
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-hack
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask docs
# Run cargo test on the documentation of the crate. This will catch any code examples that don't
@@ -233,16 +238,16 @@ jobs:
name: Test Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-hack
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask test-docs
# Run cargo test on the libraries of the crate.
@@ -252,18 +257,18 @@ jobs:
strategy:
fail-fast: false
matrix:
toolchain: ["1.85.0", "stable"]
toolchain: ["1.86.0", "stable"]
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
- uses: taiki-e/install-action@c5b1b6f479c32f356cc6f4ba672a47f63853b13b # v2
- uses: taiki-e/install-action@3522286d40783523f9c7880e33f785905b4c20d0 # v2
with:
tool: cargo-hack
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask test-libs
# Run cargo test on all the backends.
@@ -280,11 +285,11 @@ jobs:
- os: windows-latest
backend: termion
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
- uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- run: cargo xtask test-backend ${{ matrix.backend }}

View File

@@ -23,18 +23,18 @@ jobs:
if: ${{ github.repository_owner == 'ratatui' }}
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
- uses: rust-lang/crates-io-auth-action@041cce5b4b821e6b0ebc9c9c38b58cac4e34dcc2 # v1
- uses: rust-lang/crates-io-auth-action@b7e9a28eded4986ec6b1fa40eeee8f8f165559ec # v1
id: auth
- name: Run release-plz
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
uses: release-plz/action@487eb7b5c085a664d5c5ca05f4159bd9b591182a # v0.5
with:
command: release
env:
@@ -54,16 +54,16 @@ jobs:
cancel-in-progress: false
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@6d653acede28d24f02e3cd41383119e8b1b35921 # master
uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
with:
toolchain: stable
- name: Run release-plz
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
uses: release-plz/action@487eb7b5c085a664d5c5ca05f4159bd9b591182a # v0.5
with:
command: release-pr
env:

View File

@@ -18,9 +18,9 @@ jobs:
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@e673c3917a1aef3c65c972347ed84ccd013ecda4 # v0.2.0
uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0

View File

@@ -10,7 +10,9 @@ GitHub with a [breaking change] label.
This is a quick summary of the sections below:
- [v0.30.0 Unreleased](#v0300-unreleased)
- [v0.30.1](#v0301)
- Adding `AsRef` impls for widgets may affect type inference in rare cases
- [v0.30.0](#v0300)
- `Flex::SpaceAround` now mirrors flexbox: space between items is twice the size of the outer gaps
are twice the size of first and last elements
- `block::Title` no longer exists
@@ -18,7 +20,7 @@ This is a quick summary of the sections below:
- `FrameExt` trait for `unstable-widget-ref` feature
- `List::highlight_symbol` now accepts `Into<Line>` instead of `&str`
- 'layout::Alignment' is renamed to 'layout::HorizontalAlignment'
- The MSRV is now 1.85.0
- MSRV is now 1.86.0
- `Backend` now requires an associated `Error` type and `clear_region` method
- `TestBackend` now uses `core::convert::Infallible` for error handling instead of `std::io::Error`
- Disabling `default-features` will now disable layout cache, which can have a negative impact on performance
@@ -27,6 +29,9 @@ This is a quick summary of the sections below:
- Disabling `default-features` suppresses the error message if `show_cursor()` fails when dropping
`Terminal`
- Support a broader range for `unicode-width` version
- `Marker` is now non-exhaustive
- `symbols::braille::BLANK` and `symbols::braille::DOTS` have been removed in favor of an ordered
array of all Braille characters
- [v0.29.0](#v0290)
- `Sparkline::data` takes `IntoIterator<Item = SparklineBar>` instead of `&[u64]` and is no longer
const
@@ -90,7 +95,36 @@ This is a quick summary of the sections below:
- MSRV is now 1.63.0
- `List` no longer ignores empty strings
## v0.30.0 Unreleased
## [v0.30.1](https://github.com/ratatui/ratatui/releases/tag/ratatui-v0.30.1)
### Adding `AsRef` impls for widgets may affect type inference ([#2297])
[#2297]: https://github.com/ratatui/ratatui/pull/2297
Adding `AsRef<Self>` for built-in widgets can change type inference outcomes in rare cases where
`AsRef` is part of a trait bound, and can also conflict with downstream blanket or manual `AsRef`
impls for widget types. If you hit new ambiguity errors, add explicit type annotations or specify
the concrete widget type to guide inference, and remove any redundant `AsRef` impls.
## [v0.30.0](https://github.com/ratatui/ratatui/releases/tag/ratatui-v0.30.0)
### `Marker` is now non-exhaustive ([#2236])
[#2236]: https://github.com/ratatui/ratatui/pull/2236
The `Marker` enum is now marked as `#[non_exhaustive]`, if you were matching on `Marker` exhaustively,
you will need to add a wildcard arm:
```diff
match marker {
Marker::Dot => { /* ... */ }
Marker::Block => { /* ... */ }
Marker::Bar => { /* ... */ }
Marker::Braille => { /* ... */ }
Marker::HalfBlock => { /* ... */ }
+ _ => { /* ... */ }
}
```
### `Flex::SpaceAround` now mirrors flexbox: space between items is twice the size of the outer gaps ([#1952])
@@ -235,11 +269,11 @@ instead.
+ fn run(mut terminal: DefaultTerminal) -> io::Result<()> {
```
### The MSRV is now 1.85.0 ([#1860])
### MSRV is now 1.86.0 ([#2230])
[#1860]: https://github.com/ratatui/ratatui/pull/1860
[#2230]: https://github.com/ratatui/ratatui/pull/2230
The minimum supported Rust version (MSRV) is now 1.85.0.
The minimum supported Rust version (MSRV) is now 1.86.0.
### `layout::Alignment` is renamed to `layout::HorizontalAlignment` ([#1735])
@@ -1087,7 +1121,7 @@ previously did not need to use type annotations to fail to compile. To fix this,
[#133]: https://github.com/ratatui/ratatui/issues/133
Code using the `Block` marker that previously rendered using a half block character (`'▀'``) now
Code using the `Block` marker that previously rendered using a half block character (`'▀'`) now
renders using the full block character (`'█'`). A new marker variant`Bar` is introduced to replace
the existing code.

File diff suppressed because it is too large Load Diff

758
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ readme = "README.md"
license = "MIT"
exclude = ["assets/*", ".github", "Makefile.toml", "CONTRIBUTING.md", "*.log", "tags"]
edition = "2024"
rust-version = "1.85.0"
rust-version = "1.86.0"
[workspace.dependencies]
anstyle = "1"
@@ -33,7 +33,7 @@ bitflags = "2.10"
clap = { version = "4.5", features = ["derive"] }
color-eyre = "0.6"
compact_str = { version = "0.9", default-features = false }
criterion = { version = "0.7", features = ["html_reports"] }
criterion = { version = "0.8", features = ["html_reports"] }
crossterm = "0.29"
document-features = "0.2"
fakeit = "1"
@@ -45,18 +45,18 @@ itertools = { version = "0.14", default-features = false, features = ["use_alloc
kasuari = { version = "0.4", default-features = false }
line-clipping = "0.3"
lru = "0.16"
octocrab = "0.47"
octocrab = "0.49"
palette = "0.7"
pretty_assertions = "1"
rand = "0.9"
rand_chacha = "0.9"
ratatui = { path = "ratatui", version = "0.30.0-beta.0" }
ratatui-core = { path = "ratatui-core", version = "0.1.0-beta.0" }
ratatui-crossterm = { path = "ratatui-crossterm", version = "0.1.0-beta.0" }
ratatui-macros = { path = "ratatui-macros", version = "0.7.0-beta.0" }
ratatui-termion = { path = "ratatui-termion", version = "0.1.0-beta.0" }
ratatui-termwiz = { path = "ratatui-termwiz", version = "0.1.0-beta.0" }
ratatui-widgets = { path = "ratatui-widgets", version = "0.3.0-beta.0" }
ratatui = { path = "ratatui", version = "0.30.0" }
ratatui-core = { path = "ratatui-core", version = "0.1.0" }
ratatui-crossterm = { path = "ratatui-crossterm", version = "0.1.0" }
ratatui-macros = { path = "ratatui-macros", version = "0.7.0" }
ratatui-termion = { path = "ratatui-termion", version = "0.1.0" }
ratatui-termwiz = { path = "ratatui-termwiz", version = "0.1.0" }
ratatui-widgets = { path = "ratatui-widgets", version = "0.3.0" }
rstest = "0.26"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@@ -64,7 +64,7 @@ strum = { version = "0.27", default-features = false, features = ["derive"] }
termion = "4"
termwiz = "0.23"
thiserror = { version = "2", default-features = false }
time = { version = "0.3", default-features = false }
time = { version = "0.3.37", default-features = false }
tokio = "1"
tokio-stream = "0.1"
tracing = "0.1"
@@ -107,6 +107,7 @@ empty_line_after_doc_comments = "warn"
equatable_if_let = "warn"
fn_to_numeric_cast_any = "warn"
format_push_string = "warn"
implicit_clone = "warn"
map_err_ignore = "warn"
missing_const_for_fn = "warn"
mixed_read_write_in_expression = "warn"
@@ -118,6 +119,5 @@ redundant_type_annotations = "warn"
rest_pat_in_fully_bound_structs = "warn"
string_lit_chars_any = "warn"
string_slice = "warn"
string_to_string = "warn"
unnecessary_self_imports = "warn"
use_self = "warn"

View File

@@ -34,7 +34,7 @@ body = """
{% macro commit(commit) -%}
- [{{ commit.id | truncate(length=7, end="") }}]({{ "https://github.com/ratatui/ratatui/commit/" ~ commit.id }}) \
*({{commit.scope | default(value = "uncategorized") | lower }})* {{ commit.message | upper_first | trim }}\
{% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif -%}\
{% if commit.remote.username %} by `@{{ commit.remote.username }}`{%- endif -%}\
{% if commit.remote.pr_number %} in [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}){%- endif %}\
{%- if commit.breaking %} [**breaking**]{% endif %}
{%- if commit.body %}\n\n{{ commit.body | indent(prefix=" > ", first=true, blank=true) }}
@@ -123,6 +123,7 @@ commit_preprocessors = [
{ pattern = '\<[f]eatuers\>', replace = "features" },
{ pattern = '\<[s]pecically\>', replace = "specially" },
{ pattern = '\<[g]ague\>', replace = "gauge" },
{ pattern = '\<[a]rithmentic\>', replace = "arithmetic" },
{ pattern = '\<[i]ntructions\>', replace = "instructions" },
{ pattern = '\<[i]mplementated\>', replace = "implemented" },
]

View File

@@ -206,7 +206,7 @@ Shows how to use the [tracing](https://crates.io/crates/tracing) crate to log to
## User Input
Shows how to handle user input. [Source](./apps/user-input/). [Source](./apps/user-input/).
Shows how to handle user input. [Source](./apps/user-input/).
![User input demo][user-input.gif]

View File

@@ -122,8 +122,12 @@ impl App {
Marker::Dot => Marker::Braille,
Marker::Braille => Marker::Block,
Marker::Block => Marker::HalfBlock,
Marker::HalfBlock => Marker::Bar,
Marker::HalfBlock => Marker::Quadrant,
Marker::Quadrant => Marker::Sextant,
Marker::Sextant => Marker::Octant,
Marker::Octant => Marker::Bar,
Marker::Bar => Marker::Dot,
_ => unreachable!(),
};
}

View File

@@ -1,3 +1,5 @@
use std::cmp::Ordering;
/// A Ratatui example that demonstrates how different layout constraints work.
///
/// It also supports swapping constraints, adding and removing blocks, and changing the spacing
@@ -30,7 +32,7 @@ fn main() -> Result<()> {
#[derive(Default)]
struct App {
mode: AppMode,
spacing: u16,
spacing: i16,
constraints: Vec<Constraint>,
selected_index: usize,
value: u16,
@@ -269,7 +271,7 @@ impl App {
}
fn instructions() -> impl Widget {
let text = "◄ ►: select, ▲ ▼: edit, 1-6: swap, a: add, x: delete, q: quit, + -: spacing";
let text = "◄ ►: select, ▲ ▼: edit, 1-6: swap, a: add, x: delete, q: quit, +/-: spacing";
Paragraph::new(text)
.fg(Self::TEXT_COLOR)
.centered()
@@ -307,10 +309,12 @@ impl App {
///
/// Only shows the gap when spacing is not zero
fn axis(&self, width: u16) -> impl Widget {
let label = if self.spacing != 0 {
format!("{} px (gap: {} px)", width, self.spacing)
} else {
format!("{width} px")
let label = match self.spacing.cmp(&0) {
Ordering::Greater => format!("{width} px (gap: {} px)", self.spacing),
Ordering::Less => {
format!("{width} px (overlap: {} px)", self.spacing.unsigned_abs())
}
Ordering::Equal => format!("{width} px"),
};
let bar_width = width.saturating_sub(2) as usize; // we want to `<` and `>` at the ends
let width_bar = format!("<{label:-^bar_width$}>");

View File

@@ -123,9 +123,9 @@ impl InputForm {
frame.render_widget(&self.age, age_area);
let cursor_position = match self.focus {
Focus::FirstName => first_name_area.offset(self.first_name.cursor_offset()),
Focus::LastName => last_name_area.offset(self.last_name.cursor_offset()),
Focus::Age => age_area.offset(self.age.cursor_offset()),
Focus::FirstName => first_name_area + self.first_name.cursor_offset(),
Focus::LastName => last_name_area + self.last_name.cursor_offset(),
Focus::Age => age_area + self.age.cursor_offset(),
};
frame.set_cursor_position(cursor_position);
}

View File

@@ -11,10 +11,10 @@
use color_eyre::Result;
use crossterm::event::{self, KeyCode};
use ratatui::Frame;
use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::layout::{Constraint, Layout};
use ratatui::style::Stylize;
use ratatui::text::Line;
use ratatui::widgets::{Block, Clear};
use ratatui::widgets::{Block, Clear, Paragraph};
fn main() -> Result<()> {
color_eyre::install()?;
@@ -52,19 +52,14 @@ fn render(frame: &mut Frame, show_popup: bool) {
frame.render_widget(Block::bordered().title("Content").on_blue(), content);
if show_popup {
let popup = Block::bordered().title("Popup");
let popup_area = centered_area(area, 60, 20);
let popup_block = Block::bordered().title("Popup");
let centered_area = area.centered(Constraint::Percentage(60), Constraint::Percentage(20));
// clears out any background in the area before rendering the popup
frame.render_widget(Clear, popup_area);
frame.render_widget(popup, popup_area);
frame.render_widget(Clear, centered_area);
let paragraph = Paragraph::new("Lorem ipsum").block(popup_block);
frame.render_widget(paragraph, centered_area);
// another solution is to use the inner area of the block
// let inner_area = popup_block.inner(centered_area);
// frame.render_widget(your_widget, inner_area);
}
}
/// Create a centered rect using up certain percentage of the available rect
fn centered_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
let [area] = area.layout(&vertical);
let [area] = area.layout(&horizontal);
area
}

View File

@@ -222,6 +222,19 @@ impl App {
let item = data.ref_array();
item.into_iter()
.map(|content| Cell::from(Text::from(format!("\n{content}\n"))))
.enumerate()
.map(|(idx, cell)| {
if i == 3 && idx == 1 {
Cell::from(Text::from(
// Gratuitously long error message to demonstrate column_span(2)
"\n[no address or email address is available for this person]\n"
.to_string(),
))
.column_span(2)
} else {
cell
}
})
.collect::<Row>()
.style(Style::new().fg(self.colors.row_fg).bg(color))
.height(4)

View File

@@ -6,7 +6,8 @@ Set Theme "Aardvark Blue"
# The reason for this strange size is that the social preview image for this
# demo is 1280x64 with 80 pixels of padding on each side. We want a version
# without the padding for README.md, etc.
Set Width 1120
# Please note that based on the width the demo may wrap and look corrupted.
Set Width 1160
Set Height 480
Set Padding 0
Hide

View File

@@ -1,13 +1,13 @@
[package]
name = "ratatui-core"
version = "0.1.0"
description = """
Core types and traits for the Ratatui Terminal UI library.
Widget libraries should use this crate. Applications should use the main Ratatui crate.
"""
version = "0.1.0-beta.0"
documentation = "https://docs.rs/ratatui-core"
readme = "README.md"
authors.workspace = true
documentation.workspace = true
repository.workspace = true
homepage.workspace = true
keywords.workspace = true

View File

@@ -109,19 +109,28 @@ use crate::layout::{Position, Size};
mod test;
pub use self::test::TestBackend;
/// Enum representing the different types of clearing operations that can be performed
/// on the terminal screen.
/// Defines which region of the terminal's visible display area is cleared.
///
/// Clearing operates on character cells in the active display surface. It does not move, hide, or
/// reset the cursor position. If the cursor lies inside the cleared region, the character cell at
/// the cursor position is cleared as well.
///
/// Clearing applies to the terminal's visible display area, not just content previously drawn by
/// Ratatui. No guarantees are made about scrollback, history, or off-screen buffers.
#[derive(Debug, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum ClearType {
/// Clear the entire screen.
/// Clears all character cells in the visible display area.
All,
/// Clear everything after the cursor.
/// Clears all character cells from the cursor position (inclusive) through the end of the
/// display area.
AfterCursor,
/// Clear everything before the cursor.
/// Clears all character cells from the start of the display area through the cursor position
/// (inclusive).
BeforeCursor,
/// Clear the current line.
/// Clears all character cells in the cursor's current line.
CurrentLine,
/// Clear everything from the cursor until the next newline.
/// Clears all character cells from the cursor position (inclusive) to the end of the current
/// line.
UntilNewLine,
}
@@ -237,7 +246,14 @@ pub trait Backend {
self.set_cursor_position(Position { x, y })
}
/// Clears the whole terminal screen
/// Clears all character cells in the terminal's visible display area.
///
/// This operation preserves the cursor position. If the cursor lies within the cleared
/// region, the character cell at the cursor position is cleared. No guarantees are made about
/// scrollback, history, or off-screen buffers.
///
/// This is equivalent to calling [`clear_region`](Self::clear_region) with
/// [`ClearType::All`].
///
/// # Example
///
@@ -251,7 +267,13 @@ pub trait Backend {
/// ```
fn clear(&mut self) -> Result<(), Self::Error>;
/// Clears a specific region of the terminal specified by the [`ClearType`] parameter
/// Clears a specific region of the terminal's visible display area, as defined by
/// [`ClearType`].
///
/// This operation preserves the cursor position. If the cursor lies within the cleared
/// region, the character cell at the cursor position is cleared. Clearing applies to the
/// active display surface only and does not make guarantees about scrollback, history, or
/// off-screen buffers.
///
/// This method is optional and may not be implemented by all backends. The default
/// implementation calls [`clear`] if the `clear_type` is [`ClearType::All`] and returns an

View File

@@ -105,6 +105,19 @@ impl TestBackend {
&self.buffer
}
/// Returns whether the cursor is visible.
pub const fn cursor_visible(&self) -> bool {
self.cursor
}
/// Returns the current cursor position.
pub const fn cursor_position(&self) -> Position {
Position {
x: self.pos.0,
y: self.pos.1,
}
}
/// Returns a reference to the internal scrollback buffer of the `TestBackend`.
///
/// The scrollback buffer represents the part of the screen that is currently hidden from view,
@@ -275,12 +288,12 @@ impl Backend for TestBackend {
let region = match clear_type {
ClearType::All => return self.clear(),
ClearType::AfterCursor => {
let index = self.buffer.index_of(self.pos.0, self.pos.1) + 1;
let index = self.buffer.index_of(self.pos.0, self.pos.1);
&mut self.buffer.content[index..]
}
ClearType::BeforeCursor => {
let index = self.buffer.index_of(self.pos.0, self.pos.1);
&mut self.buffer.content[..index]
&mut self.buffer.content[..=index]
}
ClearType::CurrentLine => {
let line_start_index = self.buffer.index_of(0, self.pos.1);
@@ -620,7 +633,7 @@ mod tests {
backend.assert_buffer_lines([
"aaaaaaaaaa",
"aaaaaaaaaa",
"aaaa ",
"aaa ",
" ",
" ",
]);
@@ -644,7 +657,7 @@ mod tests {
" ",
" ",
" ",
" aaaaa",
" aaaa",
"aaaaaaaaaa",
]);
}

View File

@@ -25,7 +25,7 @@ use crate::text::{Line, Span};
/// use ratatui_core::layout::{Position, Rect};
/// use ratatui_core::style::{Color, Style};
///
/// # fn foo() -> Option<()> {
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let mut buf = Buffer::empty(Rect {
/// x: 0,
/// y: 0,
@@ -39,13 +39,15 @@ use crate::text::{Line, Span};
///
/// // indexing using (x, y) tuple (which is converted to Position)
/// buf[(0, 1)].set_symbol("B");
/// assert_eq!(buf[(0, 1)].symbol(), "x");
/// assert_eq!(buf[(0, 1)].symbol(), "B");
///
/// // getting an Option instead of panicking if the position is outside the buffer
/// let cell = buf.cell_mut(Position { x: 0, y: 2 })?;
/// let cell = buf
/// .cell_mut(Position { x: 0, y: 2 })
/// .ok_or("cell not found")?;
/// cell.set_symbol("C");
///
/// let cell = buf.cell(Position { x: 0, y: 2 })?;
/// let cell = buf.cell(Position { x: 0, y: 2 }).ok_or("cell not found")?;
/// assert_eq!(cell.symbol(), "C");
///
/// buf.set_string(
@@ -58,7 +60,7 @@ use crate::text::{Line, Span};
/// assert_eq!(cell.symbol(), "r");
/// assert_eq!(cell.fg, Color::Red);
/// assert_eq!(cell.bg, Color::White);
/// # Some(())
/// # Ok(())
/// # }
/// ```
#[derive(Default, Clone, Eq, PartialEq, Hash)]
@@ -216,6 +218,9 @@ impl Buffer {
///
/// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
///
/// Usage discouraged, as it exposes `self.content` as a linearly indexable array, which limits
/// potential future abstractions. See <https://github.com/ratatui/ratatui/issues/1122>.
///
/// # Examples
///
/// ```
@@ -269,10 +274,13 @@ impl Buffer {
Some(y * width + x)
}
/// Returns the (global) coordinates of a cell given its index
/// Returns the (global) coordinates of a cell given its index.
///
/// Global coordinates are offset by the Buffer's area offset (`x`/`y`).
///
/// Usage discouraged, as it exposes `self.content` as a linearly indexable array, which limits
/// potential future abstractions. See <https://github.com/ratatui/ratatui/issues/1122>.
///
/// # Examples
///
/// ```

View File

@@ -316,6 +316,7 @@ mod direction;
mod flex;
mod layout;
mod margin;
mod offset;
mod position;
mod rect;
mod size;
@@ -326,6 +327,7 @@ pub use direction::Direction;
pub use flex::Flex;
pub use layout::{Layout, Spacing};
pub use margin::Margin;
pub use offset::Offset;
pub use position::Position;
pub use rect::{Columns, Offset, Positions, Rect, Rows};
pub use rect::{Columns, Positions, Rect, Rows};
pub use size::Size;

View File

@@ -12,11 +12,27 @@ use strum::{Display, EnumString};
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Direction {
/// Layout segments are arranged side by side (left to right).
Horizontal,
/// Layout segments are arranged top to bottom (default).
#[default]
Vertical,
}
impl Direction {
/// The perpendicular direction to this direction.
///
/// `Horizontal` returns `Vertical`, and `Vertical` returns `Horizontal`.
#[inline]
#[must_use = "returns the perpendicular direction"]
pub const fn perpendicular(self) -> Self {
match self {
Self::Horizontal => Self::Vertical,
Self::Vertical => Self::Horizontal,
}
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
@@ -37,4 +53,11 @@ mod tests {
assert_eq!("Vertical".parse::<Direction>(), Ok(Direction::Vertical));
assert_eq!("".parse::<Direction>(), Err(ParseError::VariantNotFound));
}
#[test]
fn other() {
use Direction::*;
assert_eq!(Horizontal.perpendicular(), Vertical);
assert_eq!(Vertical.perpendicular(), Horizontal);
}
}

View File

@@ -0,0 +1,66 @@
use crate::layout::Position;
/// Amounts by which to move a [`Rect`](crate::layout::Rect).
///
/// Positive numbers move to the right/bottom and negative to the left/top.
///
/// See [`Rect::offset`](crate::layout::Rect::offset) for usage.
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Offset {
/// How much to move on the X axis
pub x: i32,
/// How much to move on the Y axis
pub y: i32,
}
impl Offset {
/// A zero offset
pub const ZERO: Self = Self::new(0, 0);
/// The minimum offset
pub const MIN: Self = Self::new(i32::MIN, i32::MIN);
/// The maximum offset
pub const MAX: Self = Self::new(i32::MAX, i32::MAX);
/// Creates a new `Offset` with the given values.
pub const fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
}
impl From<Position> for Offset {
fn from(position: Position) -> Self {
Self {
x: i32::from(position.x),
y: i32::from(position.y),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_sets_components() {
assert_eq!(Offset::new(-3, 7), Offset { x: -3, y: 7 });
}
#[test]
fn constants_match_expected_values() {
assert_eq!(Offset::ZERO, Offset::new(0, 0));
assert_eq!(Offset::MIN, Offset::new(i32::MIN, i32::MIN));
assert_eq!(Offset::MAX, Offset::new(i32::MAX, i32::MAX));
}
#[test]
fn from_position_converts_coordinates() {
let position = Position::new(4, 9);
let offset = Offset::from(position);
assert_eq!(offset, Offset::new(4, 9));
}
}

View File

@@ -1,7 +1,8 @@
#![warn(missing_docs)]
use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use crate::layout::Rect;
use crate::layout::{Offset, Rect};
/// Position in the terminal coordinate system.
///
@@ -23,10 +24,18 @@ use crate::layout::Rect;
/// - [`from(Rect)`](Self::from) - Create from [`Rect`] (uses top-left corner)
/// - [`into((u16, u16))`] - Convert to `(u16, u16)` tuple
///
/// # Movement
///
/// - [`offset`](Self::offset) - Move by an [`Offset`]
/// - [`Add<Offset>`](core::ops::Add) and [`Sub<Offset>`](core::ops::Sub) - Shift by offsets with
/// clamping
/// - [`AddAssign<Offset>`](core::ops::AddAssign) and [`SubAssign<Offset>`](core::ops::SubAssign) -
/// In-place shifting
///
/// # Examples
///
/// ```
/// use ratatui_core::layout::{Position, Rect};
/// use ratatui_core::layout::{Offset, Position, Rect};
///
/// // the following are all equivalent
/// let position = Position { x: 1, y: 2 };
@@ -36,6 +45,10 @@ use crate::layout::Rect;
///
/// // position can be converted back into the components when needed
/// let (x, y) = position.into();
///
/// // movement by offsets
/// let position = Position::new(5, 5) + Offset::new(2, -3);
/// assert_eq!(position, Position::new(7, 2));
/// ```
///
/// For comprehensive layout documentation and examples, see the [`layout`](crate::layout) module.
@@ -57,12 +70,27 @@ pub struct Position {
impl Position {
/// Position at the origin, the top left edge at 0,0
pub const ORIGIN: Self = Self { x: 0, y: 0 };
pub const ORIGIN: Self = Self::new(0, 0);
/// Position at the minimum x and y values
pub const MIN: Self = Self::ORIGIN;
/// Position at the maximum x and y values
pub const MAX: Self = Self::new(u16::MAX, u16::MAX);
/// Create a new position
pub const fn new(x: u16, y: u16) -> Self {
Self { x, y }
}
/// Moves the position by the given offset.
///
/// Positive offsets move right and down, negative offsets move left and up. Values that would
/// move the position outside the `u16` range are clamped to the nearest edge.
#[must_use = "method returns the modified value"]
pub fn offset(self, offset: Offset) -> Self {
self + offset
}
}
impl From<(u16, u16)> for Position {
@@ -89,6 +117,68 @@ impl fmt::Display for Position {
}
}
impl Add<Offset> for Position {
type Output = Self;
/// Moves the position by the given offset.
///
/// Values that would move the position outside the `u16` range are clamped to the nearest
/// edge.
fn add(self, offset: Offset) -> Self {
let max = i32::from(u16::MAX);
let x = i32::from(self.x).saturating_add(offset.x).clamp(0, max) as u16;
let y = i32::from(self.y).saturating_add(offset.y).clamp(0, max) as u16;
Self { x, y }
}
}
impl Add<Position> for Offset {
type Output = Position;
/// Moves the position by the given offset.
///
/// Values that would move the position outside the `u16` range are clamped to the nearest
/// edge.
fn add(self, position: Position) -> Position {
position + self
}
}
impl Sub<Offset> for Position {
type Output = Self;
/// Moves the position by the inverse of the given offset.
///
/// Values that would move the position outside the `u16` range are clamped to the nearest
/// edge.
fn sub(self, offset: Offset) -> Self {
let max = i32::from(u16::MAX);
let x = i32::from(self.x).saturating_sub(offset.x).clamp(0, max) as u16;
let y = i32::from(self.y).saturating_sub(offset.y).clamp(0, max) as u16;
Self { x, y }
}
}
impl AddAssign<Offset> for Position {
/// Moves the position in place by the given offset.
///
/// Values that would move the position outside the `u16` range are clamped to the nearest
/// edge.
fn add_assign(&mut self, offset: Offset) {
*self = *self + offset;
}
}
impl SubAssign<Offset> for Position {
/// Moves the position in place by the inverse of the given offset.
///
/// Values that would move the position outside the `u16` range are clamped to the nearest
/// edge.
fn sub_assign(&mut self, offset: Offset) {
*self = *self - offset;
}
}
#[cfg(test)]
mod tests {
use alloc::string::ToString;
@@ -98,15 +188,15 @@ mod tests {
#[test]
fn new() {
let position = Position::new(1, 2);
assert_eq!(position.x, 1);
assert_eq!(position.y, 2);
assert_eq!(position, Position { x: 1, y: 2 });
}
#[test]
fn from_tuple() {
let position = Position::from((1, 2));
assert_eq!(position.x, 1);
assert_eq!(position.y, 2);
assert_eq!(position, Position { x: 1, y: 2 });
}
#[test]
@@ -121,8 +211,8 @@ mod tests {
fn from_rect() {
let rect = Rect::new(1, 2, 3, 4);
let position = Position::from(rect);
assert_eq!(position.x, 1);
assert_eq!(position.y, 2);
assert_eq!(position, Position { x: 1, y: 2 });
}
#[test]
@@ -130,4 +220,34 @@ mod tests {
let position = Position::new(1, 2);
assert_eq!(position.to_string(), "(1, 2)");
}
#[test]
fn offset_moves_position() {
let position = Position::new(2, 3).offset(Offset::new(5, 7));
assert_eq!(position, Position::new(7, 10));
}
#[test]
fn offset_clamps_to_bounds() {
let position = Position::new(1, 1).offset(Offset::MAX);
assert_eq!(position, Position::MAX);
}
#[test]
fn add_and_subtract_offset() {
let position = Position::new(10, 10) + Offset::new(-3, 4) - Offset::new(5, 20);
assert_eq!(position, Position::new(2, 0));
}
#[test]
fn add_assign_and_sub_assign_offset() {
let mut position = Position::new(5, 5);
position += Offset::new(2, 3);
position -= Offset::new(10, 1);
assert_eq!(position, Position::new(0, 7));
}
}

View File

@@ -3,10 +3,11 @@ use core::array::TryFromSliceError;
use core::cmp::{max, min};
use core::fmt;
use crate::layout::{Margin, Position, Size};
pub use self::iter::{Columns, Positions, Rows};
use crate::layout::{Margin, Offset, Position, Size};
mod iter;
pub use iter::*;
mod ops;
use super::{Constraint, Flex, Layout};
@@ -45,6 +46,7 @@ use super::{Constraint, Flex, Layout};
///
/// - [`inner`](Self::inner), [`outer`](Self::outer) - Apply margins to shrink or expand
/// - [`offset`](Self::offset) - Move the rectangle by a relative amount
/// - [`resize`](Self::resize) - Change the rectangle size while keeping the bottom/right in range
/// - [`union`](Self::union) - Combine with another rectangle to create a bounding box
/// - [`intersection`](Self::intersection) - Find the overlapping area with another rectangle
/// - [`clamp`](Self::clamp) - Constrain the rectangle to fit within another
@@ -66,21 +68,67 @@ use super::{Constraint, Flex, Layout};
///
/// # Examples
///
/// To create a new `Rect`, use [`Rect::new`]. The size of the `Rect` will be clamped to keep the
/// right and bottom coordinates within `u16`. Note that this clamping does not occur when creating
/// a `Rect` directly.
///
/// ```rust
/// use ratatui_core::layout::Rect;
///
/// let rect = Rect::new(1, 2, 3, 4);
/// assert_eq!(
/// rect,
/// Rect {
/// x: 1,
/// y: 2,
/// width: 3,
/// height: 4
/// }
/// );
/// ```
///
/// You can also create a `Rect` from a [`Position`] and a [`Size`].
///
/// ```rust
/// use ratatui_core::layout::{Position, Rect, Size};
///
/// // Create a rectangle manually
/// let rect = Rect::new(10, 5, 80, 20);
/// assert_eq!(rect.x, 10);
/// assert_eq!(rect.y, 5);
/// assert_eq!(rect.width, 80);
/// assert_eq!(rect.height, 20);
/// let position = Position::new(1, 2);
/// let size = Size::new(3, 4);
/// let rect = Rect::from((position, size));
/// assert_eq!(
/// rect,
/// Rect {
/// x: 1,
/// y: 2,
/// width: 3,
/// height: 4
/// }
/// );
/// ```
///
/// // Create from position and size
/// let rect = Rect::from((Position::new(10, 5), Size::new(80, 20)));
/// To move a `Rect` without modifying its size, add or subtract an [`Offset`] to it.
///
/// ```rust
/// use ratatui_core::layout::{Offset, Rect};
///
/// let rect = Rect::new(1, 2, 3, 4);
/// let offset = Offset::new(5, 6);
/// let moved_rect = rect + offset;
/// assert_eq!(moved_rect, Rect::new(6, 8, 3, 4));
/// ```
///
/// To resize a `Rect` while ensuring it stays within bounds, use [`Rect::resize`]. The size is
/// clamped so that `right()` and `bottom()` do not exceed `u16::MAX`.
///
/// ```rust
/// use ratatui_core::layout::{Rect, Size};
///
/// let rect = Rect::new(u16::MAX - 1, u16::MAX - 1, 1, 1).resize(Size::new(10, 10));
/// assert_eq!(rect, Rect::new(u16::MAX - 1, u16::MAX - 1, 1, 1));
/// ```
///
/// For comprehensive layout documentation and examples, see the [`layout`](crate::layout) module.
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rect {
@@ -94,30 +142,6 @@ pub struct Rect {
pub height: u16,
}
/// Amounts by which to move a [`Rect`](crate::layout::Rect).
///
/// Positive numbers move to the right/bottom and negative to the left/top.
///
/// See [`Rect::offset`]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Offset {
/// How much to move on the X axis
pub x: i32,
/// How much to move on the Y axis
pub y: i32,
}
impl Offset {
/// A zero offset
pub const ZERO: Self = Self { x: 0, y: 0 };
/// Creates a new `Offset` with the given values.
pub const fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
}
impl fmt::Display for Rect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}x{}+{}+{}", self.width, self.height, self.x, self.y)
@@ -133,6 +157,12 @@ impl Rect {
height: 0,
};
/// The minimum possible Rect
pub const MIN: Self = Self::ZERO;
/// The maximum possible Rect
pub const MAX: Self = Self::new(0, 0, u16::MAX, u16::MAX);
/// Creates a new `Rect`, with width and height limited to keep both bounds within `u16`.
///
/// If the width or height would cause the right or bottom coordinate to be larger than the
@@ -147,15 +177,8 @@ impl Rect {
/// let rect = Rect::new(1, 2, 3, 4);
/// ```
pub const fn new(x: u16, y: u16, width: u16, height: u16) -> Self {
// these calculations avoid using min so that this function can be const
let max_width = u16::MAX - x;
let max_height = u16::MAX - y;
let width = if width > max_width { max_width } else { width };
let height = if height > max_height {
max_height
} else {
height
};
let width = x.saturating_add(width) - x;
let height = y.saturating_add(height) - y;
Self {
x,
y,
@@ -260,13 +283,19 @@ impl Rect {
/// See [`Offset`] for details.
#[must_use = "method returns the modified value"]
pub fn offset(self, offset: Offset) -> Self {
self + offset
}
/// Resizes the `Rect`, clamping to keep the right and bottom within `u16::MAX`.
///
/// The position is preserved. If the requested size would push the `Rect` beyond the bounds of
/// `u16`, the width or height is reduced so that [`right`](Self::right) and
/// [`bottom`](Self::bottom) remain within range.
#[must_use = "method returns the modified value"]
pub const fn resize(self, size: Size) -> Self {
Self {
x: i32::from(self.x)
.saturating_add(offset.x)
.clamp(0, i32::from(u16::MAX - self.width)) as u16,
y: i32::from(self.y)
.saturating_add(offset.y)
.clamp(0, i32::from(u16::MAX - self.height)) as u16,
width: self.x.saturating_add(size.width).saturating_sub(self.x),
height: self.y.saturating_add(size.height).saturating_sub(self.y),
..self
}
}
@@ -811,6 +840,16 @@ mod tests {
assert!(!Rect::new(1, 2, 3, 4).intersects(Rect::new(5, 6, 7, 8)));
}
#[rstest]
#[case::corner(Rect::new(0, 0, 10, 10), Rect::new(10, 10, 20, 20))]
#[case::edge(Rect::new(0, 0, 10, 10), Rect::new(10, 0, 20, 10))]
#[case::no_intersect(Rect::new(0, 0, 10, 10), Rect::new(11, 11, 20, 20))]
#[case::contains(Rect::new(0, 0, 20, 20), Rect::new(5, 5, 10, 10))]
fn mutual_intersect(#[case] rect0: Rect, #[case] rect1: Rect) {
assert_eq!(rect0.intersection(rect1), rect1.intersection(rect0));
assert_eq!(rect0.intersects(rect1), rect1.intersects(rect0));
}
// the bounds of this rect are x: [1..=3], y: [2..=5]
#[rstest]
#[case::inside_top_left(Rect::new(1, 2, 3, 4), Position { x: 1, y: 2 }, true)]
@@ -857,6 +896,18 @@ mod tests {
);
}
#[test]
fn resize_updates_size() {
let rect = Rect::new(10, 20, 5, 5).resize(Size::new(30, 40));
assert_eq!(rect, Rect::new(10, 20, 30, 40));
}
#[test]
fn resize_clamps_at_bounds() {
let rect = Rect::new(u16::MAX - 2, u16::MAX - 3, 1, 1).resize(Size::new(10, 10));
assert_eq!(rect, Rect::new(u16::MAX - 2, u16::MAX - 3, 2, 3));
}
#[test]
fn can_be_const() {
const RECT: Rect = Rect {

View File

@@ -0,0 +1,136 @@
use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
use super::{Offset, Rect};
impl Neg for Offset {
type Output = Self;
/// Negates the offset.
///
/// # Panics
///
/// Panics if the negated value overflows (i.e. `x` or `y` is `i32::MIN`).
fn neg(self) -> Self {
Self {
x: self.x.neg(),
y: self.y.neg(),
}
}
}
impl Add<Offset> for Rect {
type Output = Self;
/// Moves the rect by an offset without changing its size.
///
/// If the offset would move the any of the rect's edges outside the bounds of `u16`, the
/// rect's position is clamped to the nearest edge.
fn add(self, offset: Offset) -> Self {
let max_x = i32::from(u16::MAX - self.width);
let max_y = i32::from(u16::MAX - self.height);
let x = i32::from(self.x).saturating_add(offset.x).clamp(0, max_x) as u16;
let y = i32::from(self.y).saturating_add(offset.y).clamp(0, max_y) as u16;
Self { x, y, ..self }
}
}
impl Add<Rect> for Offset {
type Output = Rect;
/// Moves the rect by an offset without changing its size.
///
/// If the offset would move the any of the rect's edges outside the bounds of `u16`, the
/// rect's position is clamped to the nearest edge.
fn add(self, rect: Rect) -> Rect {
rect + self
}
}
impl Sub<Offset> for Rect {
type Output = Self;
/// Subtracts an offset from the rect without changing its size.
///
/// If the offset would move the any of the rect's edges outside the bounds of `u16`, the
/// rect's position is clamped to the nearest
fn sub(self, offset: Offset) -> Self {
// Note this cannot be simplified to `self + -offset` because `Offset::MIN` would overflow
let max_x = i32::from(u16::MAX - self.width);
let max_y = i32::from(u16::MAX - self.height);
let x = i32::from(self.x).saturating_sub(offset.x).clamp(0, max_x) as u16;
let y = i32::from(self.y).saturating_sub(offset.y).clamp(0, max_y) as u16;
Self { x, y, ..self }
}
}
impl AddAssign<Offset> for Rect {
/// Moves the rect by an offset in place without changing its size.
///
/// If the offset would move the any of the rect's edges outside the bounds of `u16`, the
/// rect's position is clamped to the nearest edge.
fn add_assign(&mut self, offset: Offset) {
*self = *self + offset;
}
}
impl SubAssign<Offset> for Rect {
/// Moves the rect by an offset in place without changing its size.
///
/// If the offset would move the any of the rect's edges outside the bounds of `u16`, the
/// rect's position is clamped to the nearest edge.
fn sub_assign(&mut self, offset: Offset) {
*self = *self - offset;
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
#[rstest]
#[case::zero(Rect::new(3, 4, 5, 6), Offset::ZERO, Rect::new(3, 4, 5, 6))]
#[case::positive(Rect::new(3, 4, 5, 6), Offset::new(1, 2), Rect::new(4, 6, 5, 6))]
#[case::negative(Rect::new(3, 4, 5, 6), Offset::new(-1, -2), Rect::new(2, 2, 5, 6))]
#[case::saturate_negative(Rect::new(3, 4, 5, 6), Offset::MIN, Rect::new(0, 0, 5, 6))]
#[case::saturate_positive(Rect::new(3, 4, 5, 6), Offset::MAX, Rect::new(u16::MAX- 5, u16::MAX - 6, 5, 6))]
fn add_offset(#[case] rect: Rect, #[case] offset: Offset, #[case] expected: Rect) {
assert_eq!(rect + offset, expected);
assert_eq!(offset + rect, expected);
}
#[rstest]
#[case::zero(Rect::new(3, 4, 5, 6), Offset::ZERO, Rect::new(3, 4, 5, 6))]
#[case::positive(Rect::new(3, 4, 5, 6), Offset::new(1, 2), Rect::new(2, 2, 5, 6))]
#[case::negative(Rect::new(3, 4, 5, 6), Offset::new(-1, -2), Rect::new(4, 6, 5, 6))]
#[case::saturate_negative(Rect::new(3, 4, 5, 6), Offset::MAX, Rect::new(0, 0, 5, 6))]
#[case::saturate_positive(Rect::new(3, 4, 5, 6), -Offset::MAX, Rect::new(u16::MAX - 5, u16::MAX - 6, 5, 6))]
fn sub_offset(#[case] rect: Rect, #[case] offset: Offset, #[case] expected: Rect) {
assert_eq!(rect - offset, expected);
}
#[rstest]
#[case::zero(Rect::new(3, 4, 5, 6), Offset::ZERO, Rect::new(3, 4, 5, 6))]
#[case::positive(Rect::new(3, 4, 5, 6), Offset::new(1, 2), Rect::new(4, 6, 5, 6))]
#[case::negative(Rect::new(3, 4, 5, 6), Offset::new(-1, -2), Rect::new(2, 2, 5, 6))]
#[case::saturate_negative(Rect::new(3, 4, 5, 6), Offset::MIN, Rect::new(0, 0, 5, 6))]
#[case::saturate_positive(Rect::new(3, 4, 5, 6), Offset::MAX, Rect::new(u16::MAX - 5, u16::MAX - 6, 5, 6))]
fn add_assign_offset(#[case] rect: Rect, #[case] offset: Offset, #[case] expected: Rect) {
let mut rect = rect;
rect += offset;
assert_eq!(rect, expected);
}
#[rstest]
#[case::zero(Rect::new(3, 4, 5, 6), Offset::ZERO, Rect::new(3, 4, 5, 6))]
#[case::positive(Rect::new(3, 4, 5, 6), Offset::new(1, 2), Rect::new(2, 2, 5, 6))]
#[case::negative(Rect::new(3, 4, 5, 6), Offset::new(-1, -2), Rect::new(4, 6, 5, 6))]
#[case::saturate_negative(Rect::new(3, 4, 5, 6), Offset::MAX, Rect::new(0, 0, 5, 6))]
#[case::saturate_positive(Rect::new(3, 4, 5, 6), -Offset::MAX, Rect::new(u16::MAX - 5, u16::MAX - 6, 5, 6))]
fn sub_assign_offset(#[case] rect: Rect, #[case] offset: Offset, #[case] expected: Rect) {
let mut rect = rect;
rect -= offset;
assert_eq!(rect, expected);
}
}

View File

@@ -24,14 +24,20 @@ use crate::layout::Rect;
/// - [`from(Rect)`](Self::from) - Create from [`Rect`] (uses width and height)
/// - [`into((u16, u16))`] - Convert to `(u16, u16)` tuple
///
/// # Computation
///
/// - [`area`](Self::area) - Compute the total number of cells covered by the size
///
/// # Examples
///
/// ```rust
/// use ratatui_core::layout::{Rect, Size};
///
/// let size = Size::new(80, 24);
/// assert_eq!(size.area(), 1920);
/// let size = Size::from((80, 24));
/// let size = Size::from(Rect::new(0, 0, 80, 24));
/// assert_eq!(size.area(), 1920);
/// ```
///
/// For comprehensive layout documentation and examples, see the [`layout`](crate::layout) module.
@@ -48,10 +54,24 @@ impl Size {
/// A zero sized Size
pub const ZERO: Self = Self::new(0, 0);
/// The minimum possible Size
pub const MIN: Self = Self::ZERO;
/// The maximum possible Size
pub const MAX: Self = Self::new(u16::MAX, u16::MAX);
/// Create a new `Size` struct
pub const fn new(width: u16, height: u16) -> Self {
Self { width, height }
}
/// Compute the total area of the size as a `u32`.
///
/// The multiplication uses `u32` to avoid overflow when the width and height are at their
/// `u16` maximum values.
pub const fn area(self) -> u32 {
self.width as u32 * self.height as u32
}
}
impl From<(u16, u16)> for Size {
@@ -60,6 +80,12 @@ impl From<(u16, u16)> for Size {
}
}
impl From<Size> for (u16, u16) {
fn from(size: Size) -> Self {
(size.width, size.height)
}
}
impl From<Rect> for Size {
fn from(rect: Rect) -> Self {
rect.as_size()
@@ -92,6 +118,14 @@ mod tests {
assert_eq!(size.height, 20);
}
#[test]
fn to_tuple() {
let size = Size::from((10, 20));
let (width, height) = size.into();
assert_eq!(size.width, width);
assert_eq!(size.height, height);
}
#[test]
fn from_rect() {
let size = Size::from(Rect::new(0, 0, 10, 20));
@@ -103,4 +137,11 @@ mod tests {
fn display() {
assert_eq!(Size::new(10, 20).to_string(), "10x20");
}
#[test]
fn area() {
assert_eq!(Size::new(10, 20).area(), 200);
assert_eq!(Size::new(0, 0).area(), 0);
assert_eq!(Size::new(u16::MAX, u16::MAX).area(), 4_294_836_225_u32);
}
}

View File

@@ -250,17 +250,41 @@ pub struct Style {
/// The modifiers to add.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Modifier::is_empty")
serde(
default,
skip_serializing_if = "Modifier::is_empty",
deserialize_with = "deserialize_modifier"
)
)]
pub add_modifier: Modifier,
/// The modifiers to remove.
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Modifier::is_empty")
serde(
default,
skip_serializing_if = "Modifier::is_empty",
deserialize_with = "deserialize_modifier"
)
)]
pub sub_modifier: Modifier,
}
#[cfg(feature = "serde")]
/// Deserialize a [`Modifier`] while treating missing or `null` values as empty.
///
/// This helper is used with serde to coerce absent or `null` modifier fields to
/// [`Modifier::empty`], allowing configuration files to omit these fields
/// without triggering deserialization errors.
fn deserialize_modifier<'de, D>(deserializer: D) -> Result<Modifier, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
Option::<Modifier>::deserialize(deserializer)
.map(|modifier| modifier.unwrap_or_else(Modifier::empty))
}
/// A custom debug implementation that prints only the fields that are not the default, and unwraps
/// the `Option`s.
impl fmt::Debug for Style {
@@ -409,6 +433,22 @@ impl Style {
self
}
/// Returns `true` if the style has the given modifier set.
///
/// ## Examples
///
/// ```rust
/// use ratatui_core::style::{Modifier, Style};
///
/// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);
/// assert!(style.has_modifier(Modifier::BOLD));
/// assert!(style.has_modifier(Modifier::ITALIC));
/// assert!(!style.has_modifier(Modifier::UNDERLINED));
/// ```
pub const fn has_modifier(self, modifier: Modifier) -> bool {
self.add_modifier.contains(modifier) && !self.sub_modifier.contains(modifier)
}
/// Results in a combined style that is equivalent to applying the two individual styles to
/// a style one after the other.
///
@@ -788,6 +828,28 @@ mod tests {
assert_eq!(ALL, ALL_SHORT);
}
#[test]
fn has_modifier_checks() {
// basic presence
let style = Style::new().add_modifier(Modifier::BOLD | Modifier::ITALIC);
assert!(style.has_modifier(Modifier::BOLD));
assert!(style.has_modifier(Modifier::ITALIC));
assert!(!style.has_modifier(Modifier::UNDERLINED));
// removal prevents the modifier from being reported as present
let style = Style::new()
.add_modifier(Modifier::BOLD | Modifier::ITALIC)
.remove_modifier(Modifier::ITALIC);
assert!(style.has_modifier(Modifier::BOLD));
assert!(!style.has_modifier(Modifier::ITALIC));
// patching with a style that removes a modifier clears it
let style = Style::new().add_modifier(Modifier::BOLD | Modifier::ITALIC);
let patched = style.patch(Style::new().remove_modifier(Modifier::ITALIC));
assert!(patched.has_modifier(Modifier::BOLD));
assert!(!patched.has_modifier(Modifier::ITALIC));
}
#[rstest]
#[case(Style::new().black(), Color::Black)]
#[case(Style::new().red(), Color::Red)]
@@ -989,4 +1051,19 @@ mod tests {
let deserialized: Style = serde_json::from_str(&json_str).unwrap();
assert_eq!(deserialized, style);
}
#[cfg(feature = "serde")]
#[test]
fn deserialize_null_modifiers() {
let json_value = serde_json::json!({
"add_modifier": serde_json::Value::Null,
"sub_modifier": serde_json::Value::Null
});
let json_str = serde_json::to_string(&json_value).unwrap();
let style: Style = serde_json::from_str(&json_str).unwrap();
assert!(style.add_modifier.is_empty());
assert!(style.sub_modifier.is_empty());
}
}

View File

@@ -10,5 +10,6 @@ pub mod half_block;
pub mod line;
pub mod marker;
pub mod merge;
pub mod pixel;
pub mod scrollbar;
pub mod shade;

View File

@@ -1,7 +1,21 @@
pub const BLANK: u16 = 0x2800;
pub const DOTS: [[u16; 2]; 4] = [
[0x0001, 0x0008],
[0x0002, 0x0010],
[0x0004, 0x0020],
[0x0040, 0x0080],
//! Braille symbols.
//!
//! Note that the symbols are not listed according to their unicode codepoint but according to the
//! corresponding bit pattern in row-major order.
pub const BRAILLE: [char; 256] = [
'', '⠁', '⠈', '⠉', '⠂', '⠃', '⠊', '⠋', '⠐', '⠑', '⠘', '⠙', '⠒', '⠓', '⠚', '⠛', '⠄', '⠅', '⠌',
'⠍', '⠆', '⠇', '⠎', '⠏', '⠔', '⠕', '⠜', '⠝', '⠖', '⠗', '⠞', '⠟', '⠠', '⠡', '⠨', '⠩', '⠢', '⠣',
'⠪', '⠫', '⠰', '⠱', '⠸', '⠹', '⠲', '⠳', '⠺', '⠻', '⠤', '⠥', '⠬', '⠭', '⠦', '⠧', '⠮', '⠯', '⠴',
'⠵', '⠼', '⠽', '⠶', '⠷', '⠾', '⠿', '⡀', '⡁', '⡈', '⡉', '⡂', '⡃', '⡊', '⡋', '⡐', '⡑', '⡘', '⡙',
'⡒', '⡓', '⡚', '⡛', '⡄', '⡅', '⡌', '⡍', '⡆', '⡇', '⡎', '⡏', '⡔', '⡕', '⡜', '⡝', '⡖', '⡗', '⡞',
'⡟', '⡠', '⡡', '⡨', '⡩', '⡢', '⡣', '⡪', '⡫', '⡰', '⡱', '⡸', '⡹', '⡲', '⡳', '⡺', '⡻', '⡤', '⡥',
'⡬', '⡭', '⡦', '⡧', '⡮', '⡯', '⡴', '⡵', '⡼', '⡽', '⡶', '⡷', '⡾', '⡿', '⢀', '⢁', '⢈', '⢉', '⢂',
'⢃', '⢊', '⢋', '⢐', '⢑', '⢘', '⢙', '⢒', '⢓', '⢚', '⢛', '⢄', '⢅', '⢌', '⢍', '⢆', '⢇', '⢎', '⢏',
'⢔', '⢕', '⢜', '⢝', '⢖', '⢗', '⢞', '⢟', '⢠', '⢡', '⢨', '⢩', '⢢', '⢣', '⢪', '⢫', '⢰', '⢱', '⢸',
'⢹', '⢲', '⢳', '⢺', '⢻', '⢤', '⢥', '⢬', '⢭', '⢦', '⢧', '⢮', '⢯', '⢴', '⢵', '⢼', '⢽', '⢶', '⢷',
'⢾', '⢿', '⣀', '⣁', '⣈', '⣉', '⣂', '⣃', '⣊', '⣋', '⣐', '⣑', '⣘', '⣙', '⣒', '⣓', '⣚', '⣛', '⣄',
'⣅', '⣌', '⣍', '⣆', '⣇', '⣎', '⣏', '⣔', '⣕', '⣜', '⣝', '⣖', '⣗', '⣞', '⣟', '⣠', '⣡', '⣨', '⣩',
'⣢', '⣣', '⣪', '⣫', '⣰', '⣱', '⣸', '⣹', '⣲', '⣳', '⣺', '⣻', '⣤', '⣥', '⣬', '⣭', '⣦', '⣧', '⣮',
'⣯', '⣴', '⣵', '⣼', '⣽', '⣶', '⣷', '⣾', '⣿',
];

View File

@@ -4,6 +4,7 @@ pub const DOT: &str = "•";
/// Marker to use when plotting data points
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum Marker {
/// One point per cell in shape of dot (`•`)
#[default]
@@ -25,6 +26,33 @@ pub enum Marker {
/// a grid that is double the resolution of the terminal. Because each terminal cell is
/// generally about twice as tall as it is wide, this allows for a square grid of pixels.
HalfBlock,
/// Use quadrant characters to represent data points.
///
/// Quadrant characters display densely packed and regularly spaced pseudo-pixels with a 2x2
/// resolution per character, without visible bands between cells.
Quadrant,
/// Use sextant characters from the [Unicode Symbols for Legacy Computing
/// Supplement](https://en.wikipedia.org/wiki/Symbols_for_Legacy_Computing_Supplement) to
/// represent data points.
///
/// Sextant characters display densely packed and regularly spaced pseudo-pixels with a 2x3
/// resolution per character, without visible bands between cells.
///
/// Note: the Symbols for Legacy Computing Supplement block is a relatively recent addition to
/// unicode that is less broadly supported than Braille dots. If your terminal does not support
/// this, you will see unicode replacement characters (`<60>`) instead of sextants (`🬌`, `🬲`, `🬑`).
Sextant,
/// Use octant characters from the [Unicode Symbols for Legacy Computing
/// Supplement](https://en.wikipedia.org/wiki/Symbols_for_Legacy_Computing_Supplement) to
/// represent data points.
///
/// Octant characters have the same 2x4 resolution as Braille characters but display densely
/// packed and regularly spaced pseudo-pixels, without visible bands between cells.
///
/// Note: the Symbols for Legacy Computing Supplement block is a relatively recent addition to
/// unicode that is less broadly supported than Braille dots. If your terminal does not support
/// this, you will see unicode replacement characters (`<60>`) instead of octants (`𜴇`, `𜷀`, `𜴷`).
Octant,
}
#[cfg(test)]

View File

@@ -0,0 +1,30 @@
//! Pseudo-pixel symbols: quadrant, sextant and octant characters.
//!
//! Note that the symbols are not listed according to their unicode codepoint but according to the
//! corresponding bit pattern in row-major order.
pub const QUADRANTS: [char; 16] = [
' ', '▘', '▝', '▀', '▖', '▌', '▞', '▛', '▗', '▚', '▐', '▜', '▄', '▙', '▟', '█',
];
pub const SEXTANTS: [char; 64] = [
' ', '🬀', '🬁', '🬂', '🬃', '🬄', '🬅', '🬆', '🬇', '🬈', '🬉', '🬊', '🬋', '🬌', '🬍', '🬎', '🬏', '🬐', '🬑',
'🬒', '🬓', '▌', '🬔', '🬕', '🬖', '🬗', '🬘', '🬙', '🬚', '🬛', '🬜', '🬝', '🬞', '🬟', '🬠', '🬡', '🬢', '🬣',
'🬤', '🬥', '🬦', '🬧', '▐', '🬨', '🬩', '🬪', '🬫', '🬬', '🬭', '🬮', '🬯', '🬰', '🬱', '🬲', '🬳', '🬴', '🬵',
'🬶', '🬷', '🬸', '🬹', '🬺', '🬻', '█',
];
pub const OCTANTS: [char; 256] = [
' ', '𜺨', '𜺫', '🮂', '𜴀', '▘', '𜴁', '𜴂', '𜴃', '𜴄', '▝', '𜴅', '𜴆', '𜴇', '𜴈', '▀', '𜴉', '𜴊', '𜴋',
'𜴌', '🯦', '𜴍', '𜴎', '𜴏', '𜴐', '𜴑', '𜴒', '𜴓', '𜴔', '𜴕', '𜴖', '𜴗', '𜴘', '𜴙', '𜴚', '𜴛', '𜴜', '𜴝',
'𜴞', '𜴟', '🯧', '𜴠', '𜴡', '𜴢', '𜴣', '𜴤', '𜴥', '𜴦', '𜴧', '𜴨', '𜴩', '𜴪', '𜴫', '𜴬', '𜴭', '𜴮', '𜴯',
'𜴰', '𜴱', '𜴲', '𜴳', '𜴴', '𜴵', '🮅', '𜺣', '𜴶', '𜴷', '𜴸', '𜴹', '𜴺', '𜴻', '𜴼', '𜴽', '𜴾', '𜴿', '𜵀',
'𜵁', '𜵂', '𜵃', '𜵄', '▖', '𜵅', '𜵆', '𜵇', '𜵈', '▌', '𜵉', '𜵊', '𜵋', '𜵌', '▞', '𜵍', '𜵎', '𜵏', '𜵐',
'▛', '𜵑', '𜵒', '𜵓', '𜵔', '𜵕', '𜵖', '𜵗', '𜵘', '𜵙', '𜵚', '𜵛', '𜵜', '𜵝', '𜵞', '𜵟', '𜵠', '𜵡', '𜵢',
'𜵣', '𜵤', '𜵥', '𜵦', '𜵧', '𜵨', '𜵩', '𜵪', '𜵫', '𜵬', '𜵭', '𜵮', '𜵯', '𜵰', '𜺠', '𜵱', '𜵲', '𜵳', '𜵴',
'𜵵', '𜵶', '𜵷', '𜵸', '𜵹', '𜵺', '𜵻', '𜵼', '𜵽', '𜵾', '𜵿', '𜶀', '𜶁', '𜶂', '𜶃', '𜶄', '𜶅', '𜶆', '𜶇',
'𜶈', '𜶉', '𜶊', '𜶋', '𜶌', '𜶍', '𜶎', '𜶏', '▗', '𜶐', '𜶑', '𜶒', '𜶓', '▚', '𜶔', '𜶕', '𜶖', '𜶗', '▐',
'𜶘', '𜶙', '𜶚', '𜶛', '▜', '𜶜', '𜶝', '𜶞', '𜶟', '𜶠', '𜶡', '𜶢', '𜶣', '𜶤', '𜶥', '𜶦', '𜶧', '𜶨', '𜶩',
'𜶪', '𜶫', '▂', '𜶬', '𜶭', '𜶮', '𜶯', '𜶰', '𜶱', '𜶲', '𜶳', '𜶴', '𜶵', '𜶶', '𜶷', '𜶸', '𜶹', '𜶺', '𜶻',
'𜶼', '𜶽', '𜶾', '𜶿', '𜷀', '𜷁', '𜷂', '𜷃', '𜷄', '𜷅', '𜷆', '𜷇', '𜷈', '𜷉', '𜷊', '𜷋', '𜷌', '𜷍', '𜷎',
'𜷏', '𜷐', '𜷑', '𜷒', '𜷓', '𜷔', '𜷕', '𜷖', '𜷗', '𜷘', '𜷙', '𜷚', '▄', '𜷛', '𜷜', '𜷝', '𜷞', '▙', '𜷟',
'𜷠', '𜷡', '𜷢', '▟', '𜷣', '▆', '𜷤', '𜷥', '█',
];

View File

@@ -31,10 +31,381 @@
//! [`Backend`]: crate::backend::Backend
//! [`Buffer`]: crate::buffer::Buffer
mod backend;
mod buffers;
mod cursor;
mod frame;
mod terminal;
mod init;
mod inline;
mod render;
mod resize;
mod viewport;
pub use frame::{CompletedFrame, Frame};
pub use terminal::{Options as TerminalOptions, Terminal};
pub use viewport::Viewport;
use crate::backend::Backend;
use crate::buffer::Buffer;
use crate::layout::{Position, Rect};
/// An interface to interact and draw [`Frame`]s on the user's terminal.
///
/// This is the main entry point for Ratatui. It is responsible for drawing and maintaining the
/// state of the buffers, cursor and viewport.
///
/// If you're building a fullscreen application with the `ratatui` crate's default backend
/// ([Crossterm]), prefer [`ratatui::run`] (or [`ratatui::init`] + [`ratatui::restore`]) over
/// constructing `Terminal` directly. These helpers enable common terminal modes (raw mode +
/// alternate screen) and restore them on exit and on panic.
///
/// ```rust,ignore
/// ratatui::run(|terminal| {
/// let mut should_quit = false;
/// while !should_quit {
/// terminal.draw(|frame| {
/// frame.render_widget("Hello, World!", frame.area());
/// })?;
///
/// // Handle events, update application state, and set `should_quit = true` to exit.
/// }
/// Ok(())
/// })?;
/// ```
///
/// # Typical Usage
///
/// In a typical application, the flow is: set up a terminal, run an event loop, update state, and
/// draw each frame.
///
/// 1. Choose a setup path for a `Terminal`. Most apps call [`ratatui::run`], which passes a
/// preconfigured `Terminal` into your callback. If you need more control, use [`ratatui::init`]
/// and [`ratatui::restore`], or construct a `Terminal` manually via [`Terminal::new`]
/// (fullscreen) or [`Terminal::with_options`] (select a [`Viewport`]).
/// 2. Enter your application's event loop and call [`Terminal::draw`] (or [`Terminal::try_draw`])
/// to render the current UI state into a [`Frame`].
/// 3. Handle input and application state updates between draw calls.
/// 4. If the terminal is resized, call [`Terminal::draw`] again. Ratatui automatically resizes
/// fullscreen and inline viewports during `draw`; fixed viewports require an explicit call to
/// [`Terminal::resize`] if you want the region to change.
///
/// # Rendering Pipeline
///
/// A single call to [`Terminal::draw`] (or [`Terminal::try_draw`]) represents one render pass. In
/// broad strokes, Ratatui:
///
/// 1. Checks whether the underlying terminal size changed (see [`Terminal::autoresize`]).
/// 2. Creates a [`Frame`] backed by the current buffer (see [`Terminal::get_frame`]).
/// 3. Runs your render callback to populate that buffer.
/// 4. Diffs the current buffer against the previous buffer and writes the changes (see
/// [`Terminal::flush`]).
/// 5. Applies cursor visibility and position requested by the frame (see
/// [`Frame::set_cursor_position`]).
/// 6. Swaps the buffers to prepare for the next render pass (see [`Terminal::swap_buffers`]).
/// 7. Flushes the backend (see [`Backend::flush`]).
///
/// Each render pass starts with an empty buffer for the current viewport. Your render callback
/// should render everything that should be visible in [`Frame::area`], even if it is unchanged
/// from the previous frame. Ratatui diffs the current and previous buffers and only writes the
/// changes; anything you don't render is treated as empty and may clear previously drawn content.
///
/// If the viewport size changes between render passes (for example via [`Terminal::autoresize`] or
/// an explicit [`Terminal::resize`]), Ratatui clears the viewport and resets the previous buffer so
/// the next `draw` is treated as a full redraw.
///
/// Most applications should use [`Terminal::draw`] / [`Terminal::try_draw`]. For manual rendering
/// (primarily for tests), you can build a frame with [`Terminal::get_frame`], write diffs with
/// [`Terminal::flush`], then call [`Terminal::swap_buffers`]. If your backend buffers output, also
/// call [`Backend::flush`].
///
/// ```rust,no_run
/// # mod ratatui {
/// # pub use ratatui_core::backend;
/// # pub use ratatui_core::terminal::Terminal;
/// # }
/// use ratatui::Terminal;
/// use ratatui::backend::{Backend, TestBackend};
///
/// let backend = TestBackend::new(10, 10);
/// let mut terminal = Terminal::new(backend)?;
///
/// // Manual render pass (roughly what `Terminal::draw` does internally).
/// {
/// let mut frame = terminal.get_frame();
/// frame.render_widget("Hello World!", frame.area());
/// }
///
/// terminal.flush()?;
/// terminal.swap_buffers();
/// terminal.backend_mut().flush()?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// # Viewports
///
/// The viewport controls *where* Ratatui draws and therefore what [`Frame::area`] represents.
/// Most applications use [`Viewport::Fullscreen`], but Ratatui also supports [`Viewport::Inline`]
/// and [`Viewport::Fixed`].
///
/// Choose a viewport at initialization time with [`Terminal::with_options`] and
/// [`TerminalOptions`].
///
/// In [`Viewport::Fullscreen`], the viewport is the entire terminal and `Frame::area` starts at
/// (0, 0). Ratatui automatically resizes the internal buffers when the terminal size changes.
///
/// In [`Viewport::Fixed`], the viewport is a user-provided [`Rect`] in terminal coordinates.
/// `Frame::area` is that exact rectangle (including its `x`/`y` offset). Fixed viewports are not
/// automatically resized; if the region should change, call [`Terminal::resize`].
///
/// In [`Viewport::Inline`], Ratatui draws into a rectangle anchored to where the UI started. This
/// mode is described in more detail in the "Inline Viewport" section below.
///
/// ```rust,ignore
/// use ratatui::{layout::Rect, Terminal, TerminalOptions, Viewport};
/// use ratatui::backend::CrosstermBackend;
///
/// // Fullscreen (most common):
/// let fullscreen = Terminal::new(CrosstermBackend::new(std::io::stdout()))?;
///
/// // Fixed region (your app manages the coordinates):
/// let viewport = Viewport::Fixed(Rect::new(0, 0, 30, 10));
/// let fixed = Terminal::with_options(
/// CrosstermBackend::new(std::io::stdout()),
/// TerminalOptions { viewport },
/// )?;
/// ```
///
/// Applications should detect terminal resizes and call [`Terminal::draw`] to redraw the
/// application with the new size. This will automatically resize the internal buffers to match the
/// new size for inline and fullscreen viewports. Fixed viewports are not resized automatically.
///
/// # Inline Viewport
///
/// Inline mode is designed for applications that want to embed a UI into a larger CLI flow. In
/// [`Viewport::Inline`], Ratatui anchors the viewport to the backend cursor row at initialization
/// time and always starts drawing at column 0.
///
/// To reserve vertical space for the requested height, Ratatui may append lines. When the cursor is
/// near the bottom edge, terminals scroll; Ratatui accounts for that scrolling by shifting the
/// computed viewport origin upward so the viewport stays fully visible.
///
/// While running in inline mode, [`Terminal::insert_before`] can be used to print output above the
/// viewport without disturbing the UI.
/// When Ratatui is built with the `scrolling-regions` feature, `insert_before` can do this without
/// clearing and redrawing the viewport.
///
/// ```rust,ignore
/// use ratatui::{TerminalOptions, Viewport};
///
/// println!("Some output above the UI");
///
/// let options = TerminalOptions {
/// viewport: Viewport::Inline(10),
/// };
/// let mut terminal = ratatui::try_init_with_options(options)?;
///
/// terminal.insert_before(1, |buf| {
/// // Render a single line of output into `buf` before the UI.
/// // (For example: logs, status updates, or command output.)
/// })?;
/// ```
///
/// # More Information
///
/// - Choosing a viewport: [`Terminal::with_options`], [`TerminalOptions`], and [`Viewport`]
/// - The rendering pipeline: [`Terminal::draw`] and [`Terminal::try_draw`]
/// - Resize handling: [`Terminal::autoresize`] and [`Terminal::resize`]
/// - Manual rendering and testing: [`Terminal::get_frame`], [`Terminal::flush`], and
/// [`Terminal::swap_buffers`]
/// - Printing above an inline UI: [`Terminal::insert_before`]
///
/// # Initialization
///
/// Most interactive TUIs need process-wide terminal setup (for example: raw mode and an alternate
/// screen) and matching teardown on exit and on panic. In Ratatui, that setup lives in the
/// `ratatui` crate; `Terminal` itself focuses on rendering and does not implicitly change those
/// modes.
///
/// If you're using the `ratatui` crate with its default backend ([Crossterm]), there are three
/// common entry points:
///
/// - [`ratatui::run`]: recommended for most applications. Provides a [`ratatui::DefaultTerminal`],
/// runs your closure, and restores terminal state on exit and on panic.
/// - [`ratatui::init`] + [`ratatui::restore`]: like `run`, but you control the event loop and
/// decide when to restore.
/// - [`Terminal::new`] / [`Terminal::with_options`]: manual construction (for example: custom
/// backends such as [Termion] / [Termwiz], inline UIs, or fixed viewports). You are responsible
/// for terminal mode setup and teardown.
///
/// [`ratatui::run`] was introduced in Ratatui 0.30, so older tutorials may use `init`/`restore` or
/// manual construction.
///
/// Some applications install a custom panic hook to log a crash report, print a friendlier error,
/// or integrate with error reporting. If you do, install it before calling [`ratatui::init`] /
/// [`ratatui::run`]. Ratatui wraps the current hook so it can restore terminal state first (for
/// example: leaving the alternate screen and disabling raw mode) and then delegate to your hook.
///
/// Crossterm is cross-platform and is what most Ratatui applications use by default. Ratatui also
/// supports other backends such as [Termion] and [Termwiz], and third-party backends can integrate
/// by implementing [`Backend`].
///
/// # How it works
///
/// `Terminal` ties together a [`Backend`], a [`Viewport`], and a double-buffered diffing renderer.
/// The high-level flow is described in the "Rendering Pipeline" section above; this section focuses
/// on how that pipeline is implemented.
///
/// `Terminal` is generic over a [`Backend`] implementation and does not depend on a particular
/// terminal library. It relies on the backend to:
///
/// - report the current screen size (used by [`Terminal::autoresize`])
/// - draw cell updates (used by [`Terminal::flush`])
/// - clear regions (used by [`Terminal::clear`] and [`Terminal::resize`])
/// - move and show/hide the cursor (used by [`Terminal::try_draw`])
/// - optionally append lines (used by inline viewports and by [`Terminal::insert_before`])
///
/// ## Buffers and diffing
///
/// The `Terminal` maintains two [`Buffer`]s sized to the current viewport. During a render pass,
/// widgets draw into the "current" buffer via the [`Frame`] passed to your callback. At the end of
/// the pass, [`Terminal::flush`] diffs the current buffer against the previous buffer and sends
/// only the changed cells to the backend.
///
/// After flushing, [`Terminal::swap_buffers`] flips which buffer is considered "current" and resets
/// the next buffer. This is why each render pass starts from an empty buffer: your callback is
/// expected to fully redraw the viewport every time.
///
/// The [`CompletedFrame`] returned from [`Terminal::draw`] / [`Terminal::try_draw`] provides a
/// reference to the buffer that was just rendered, which can be useful for assertions in tests.
///
/// ## Viewport state and resizing
///
/// The active [`Viewport`] controls how the viewport area is computed:
///
/// - Fullscreen: `Frame::area` covers the full backend size.
/// - Fixed: `Frame::area` is the exact rectangle you provided in terminal coordinates.
/// - Inline: `Frame::area` is a rectangle anchored to the backend cursor row.
///
/// For fullscreen and inline viewports, [`Terminal::autoresize`] checks the backend size during
/// every render pass and calls [`Terminal::resize`] when it changes. Resizing updates the internal
/// buffer sizes and clears the affected region; it also resets the previous buffer so the next draw
/// is treated as a full redraw.
///
/// ## Cursor tracking
///
/// The cursor position requested by [`Frame::set_cursor_position`] is applied after
/// [`Terminal::flush`] so the cursor ends up on top of the rendered UI. `Terminal` also tracks a
/// "last known cursor position" as a best-effort record of where it last wrote, and uses that
/// information when recomputing inline viewports on resize.
///
/// ## Inline-specific behavior
///
/// Inline viewports reserve vertical space by calling [`Backend::append_lines`]. If the cursor is
/// close enough to the bottom edge, terminals scroll as lines are appended. Ratatui accounts for
/// that scrolling by shifting the computed viewport origin upward so the viewport remains fully
/// visible. On resize, Ratatui recomputes the inline origin while trying to keep the cursor at the
/// same relative row inside the viewport.
///
/// When Ratatui is built with the `scrolling-regions` feature, [`Terminal::insert_before`] uses
/// terminal scrolling regions to insert content above an inline viewport without clearing and
/// redrawing it.
///
/// [Crossterm]: https://crates.io/crates/crossterm
/// [Termion]: https://crates.io/crates/termion
/// [Termwiz]: https://crates.io/crates/termwiz
/// [`backend`]: crate::backend
/// [`Backend`]: crate::backend::Backend
/// [`Backend::flush`]: crate::backend::Backend::flush
/// [`Buffer`]: crate::buffer::Buffer
/// [`ratatui::DefaultTerminal`]: https://docs.rs/ratatui/latest/ratatui/type.DefaultTerminal.html
/// [`ratatui::init`]: https://docs.rs/ratatui/latest/ratatui/fn.init.html
/// [`ratatui::restore`]: https://docs.rs/ratatui/latest/ratatui/fn.restore.html
/// [`ratatui::run`]: https://docs.rs/ratatui/latest/ratatui/fn.run.html
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Terminal<B>
where
B: Backend,
{
/// The backend used to write updates to the terminal.
///
/// Most application code does not need to interact with the backend directly; see
/// [`Terminal::draw`]. Accessing the backend can be useful for backend-specific testing and
/// inspection (see [`Terminal::backend`]).
backend: B,
/// Double-buffered render state.
///
/// [`Terminal::flush`] diffs `buffers[current]` against the other buffer to compute a minimal
/// set of updates to send to the backend.
buffers: [Buffer; 2],
/// Index of the "current" buffer in [`Terminal::buffers`].
///
/// This toggles between 0 and 1 and is updated by [`Terminal::swap_buffers`].
current: usize,
/// Whether Ratatui believes it has hidden the cursor.
///
/// This is tracked so [`Drop`] can attempt to restore cursor visibility.
hidden_cursor: bool,
/// The configured [`Viewport`] mode.
///
/// This determines how the initial viewport area is computed during construction, whether
/// [`Terminal::autoresize`] runs, how [`Terminal::clear`] behaves, and whether operations like
/// [`Terminal::insert_before`] have any effect.
viewport: Viewport,
/// The current viewport rectangle in terminal coordinates.
///
/// This is the area returned by [`Frame::area`] and the size of the internal buffers. It is
/// set during construction and updated by [`Terminal::resize`]. In inline mode, calls to
/// [`Terminal::insert_before`] can also move the viewport vertically.
viewport_area: Rect,
/// Last known renderable "screen" area.
///
/// For fullscreen and inline viewports this tracks the backend-reported terminal size. For
/// fixed viewports, this tracks the user-provided fixed area.
///
/// This is used by [`Terminal::autoresize`] and is reported via [`CompletedFrame::area`].
last_known_area: Rect,
/// Last known cursor position in terminal coordinates.
///
/// This is updated when:
///
/// - [`Terminal::set_cursor_position`] is called directly.
/// - [`Frame::set_cursor_position`] is used during [`Terminal::draw`].
/// - [`Terminal::flush`] observes a diff update (used as a proxy for the "last written" cell).
///
/// Inline viewports use this during [`Terminal::resize`] to preserve the cursor's relative
/// position within the viewport.
last_known_cursor_pos: Position,
/// Number of frames rendered so far.
///
/// This increments after each successful [`Terminal::draw`] / [`Terminal::try_draw`] and wraps
/// at `usize::MAX`.
frame_count: usize,
}
/// Options to pass to [`Terminal::with_options`]
///
/// Most applications can use [`Terminal::new`]. Use `TerminalOptions` when you need to configure a
/// non-default [`Viewport`] at initialization time (see [`Terminal`] for an overview).
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct TerminalOptions {
/// Viewport used to draw to the terminal.
///
/// See [`Terminal`] for a higher-level overview, and [`Viewport`] for the per-variant
/// definition.
pub viewport: Viewport,
}
impl<B> Drop for Terminal<B>
where
B: Backend,
{
fn drop(&mut self) {
// Attempt to restore the cursor state
if self.hidden_cursor {
#[allow(unused_variables)]
if let Err(err) = self.show_cursor() {
#[cfg(feature = "std")]
std::eprintln!("Failed to show the cursor: {err}");
}
}
}
}

View File

@@ -0,0 +1,75 @@
use crate::backend::Backend;
use crate::layout::Size;
use crate::terminal::Terminal;
impl<B: Backend> Terminal<B> {
/// Returns a shared reference to the backend.
///
/// This is primarily useful for backend-specific inspection in tests (e.g. reading
/// [`TestBackend`]'s buffer). Most applications should interact with the terminal via
/// [`Terminal::draw`] rather than calling backend methods directly.
///
/// [`TestBackend`]: crate::backend::TestBackend
pub const fn backend(&self) -> &B {
&self.backend
}
/// Returns a mutable reference to the backend.
///
/// This is an advanced escape hatch. Mutating the backend directly can desynchronize Ratatui's
/// internal buffers from what's on-screen; if you do this, you may need to call
/// [`Terminal::clear`] to force a full redraw.
pub const fn backend_mut(&mut self) -> &mut B {
&mut self.backend
}
/// Queries the real size of the backend.
///
/// This returns the size of the underlying terminal. The current renderable area depends on
/// the configured [`Viewport`]; use [`Frame::area`] inside [`Terminal::draw`] if you want the
/// area you should render into.
///
/// [`Frame::area`]: crate::terminal::Frame::area
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
/// [`Viewport`]: crate::terminal::Viewport
pub fn size(&self) -> Result<Size, B::Error> {
self.backend.size()
}
}
#[cfg(test)]
mod tests {
use crate::backend::TestBackend;
use crate::layout::{Position, Size};
use crate::terminal::Terminal;
#[test]
fn backend_returns_shared_reference() {
let backend = TestBackend::new(3, 2);
let terminal = Terminal::new(backend).unwrap();
assert_eq!(terminal.backend().cursor_position(), Position::ORIGIN);
}
#[test]
fn backend_mut_allows_mutating_backend_state() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.backend_mut().resize(4, 3);
assert_eq!(terminal.size().unwrap(), Size::new(4, 3));
terminal
.backend()
.assert_buffer_lines([" ", " ", " "]);
}
#[test]
fn size_queries_underlying_backend_size() {
let mut backend = TestBackend::new(3, 2);
backend.resize(4, 3);
let terminal = Terminal::new(backend).unwrap();
assert_eq!(terminal.size().unwrap(), Size::new(4, 3));
}
}

View File

@@ -0,0 +1,380 @@
use crate::backend::{Backend, ClearType};
use crate::buffer::{Buffer, Cell};
use crate::layout::{Position, Rect};
use crate::terminal::{Frame, Terminal, Viewport};
impl<B: Backend> Terminal<B> {
/// Returns a [`Frame`] for manual rendering.
///
/// Most applications should render via [`Terminal::draw`] / [`Terminal::try_draw`]. This method
/// exposes the frame construction step used by [`Terminal::try_draw`] so tests and advanced
/// callers can render without running the full draw pipeline.
///
/// Unlike `draw` / `try_draw`, this does not call [`Terminal::autoresize`], does not write
/// updates to the backend, and does not apply any cursor changes. After rendering, you
/// typically call [`Terminal::flush`], [`Terminal::swap_buffers`], and [`Backend::flush`].
///
/// The returned `Frame` mutably borrows the current buffer, so it must be dropped before you
/// can call methods like [`Terminal::flush`]. The example below uses a scope to make that
/// explicit.
///
/// # Example
///
/// ```rust,no_run
/// # mod ratatui {
/// # pub use ratatui_core::backend;
/// # pub use ratatui_core::terminal::Terminal;
/// # }
/// use ratatui::Terminal;
/// use ratatui::backend::{Backend, TestBackend};
///
/// let backend = TestBackend::new(30, 5);
/// let mut terminal = Terminal::new(backend)?;
/// {
/// let mut frame = terminal.get_frame();
/// frame.render_widget("Hello", frame.area());
/// }
/// // When not using `draw`, present the buffer manually:
/// terminal.flush()?;
/// terminal.swap_buffers();
/// terminal.backend_mut().flush()?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// [`Backend::flush`]: crate::backend::Backend::flush
pub const fn get_frame(&mut self) -> Frame<'_> {
let count = self.frame_count;
Frame {
cursor_position: None,
viewport_area: self.viewport_area,
buffer: self.current_buffer_mut(),
count,
}
}
/// Gets the current buffer as a mutable reference.
///
/// This is the buffer that the next [`Frame`] will render into (see [`Terminal::get_frame`]).
/// Most applications should render inside [`Terminal::draw`] and access the buffer via
/// [`Frame::buffer_mut`] instead.
pub const fn current_buffer_mut(&mut self) -> &mut Buffer {
&mut self.buffers[self.current]
}
/// Writes the current buffer to the backend using a diff against the previous buffer.
///
/// This is one of the building blocks used by [`Terminal::draw`] / [`Terminal::try_draw`]. It
/// does not swap buffers or flush the backend; see [`Terminal::swap_buffers`] and
/// [`Backend::flush`].
///
/// Implementation note: when there are updates, Ratatui records the position of the last
/// updated cell as the "last known cursor position". Inline viewports use this to preserve the
/// cursor's relative position within the viewport across resizes.
///
/// [`Backend::flush`]: crate::backend::Backend::flush
pub fn flush(&mut self) -> Result<(), B::Error> {
let previous_buffer = &self.buffers[1 - self.current];
let current_buffer = &self.buffers[self.current];
let updates = previous_buffer.diff(current_buffer);
if let Some((col, row, _)) = updates.last() {
self.last_known_cursor_pos = Position { x: *col, y: *row };
}
self.backend.draw(updates.into_iter())
}
/// Clears the inactive buffer and swaps it with the current buffer.
///
/// This is part of the standard rendering flow (see [`Terminal::try_draw`]). If you render
/// manually using [`Terminal::get_frame`] and [`Terminal::flush`], call this afterward so the
/// next flush can compute diffs against the correct "previous" buffer.
pub fn swap_buffers(&mut self) {
self.buffers[1 - self.current].reset();
self.current = 1 - self.current;
}
/// Clear the terminal and force a full redraw on the next draw call.
///
/// What gets cleared depends on the active [`Viewport`]:
///
/// - [`Viewport::Fullscreen`]: clears the entire terminal.
/// - [`Viewport::Fixed`]: clears only the viewport region.
/// - [`Viewport::Inline`]: clears after the viewport's origin, leaving any content above the
/// viewport untouched.
///
/// Current behavior: for [`Viewport::Inline`], clearing runs from the viewport origin through
/// the end of the visible display area, not just the viewport's rectangle. This is an
/// implementation detail rather than a contract; do not rely on it.
///
/// This preserves the cursor position.
///
/// This also resets the "previous" buffer so the next [`Terminal::flush`] redraws the full
/// viewport. [`Terminal::resize`] calls this internally.
///
/// Implementation note: this uses [`ClearType::AfterCursor`] starting at the viewport origin.
pub fn clear(&mut self) -> Result<(), B::Error> {
let original_cursor = self.backend.get_cursor_position()?;
match self.viewport {
Viewport::Fullscreen => self.backend.clear_region(ClearType::All)?,
Viewport::Inline(_) => {
self.backend
.set_cursor_position(self.viewport_area.as_position())?;
self.backend.clear_region(ClearType::AfterCursor)?;
}
Viewport::Fixed(_) => {
let area = self.viewport_area;
self.clear_fixed_viewport(area)?;
}
}
self.backend.set_cursor_position(original_cursor)?;
// Reset the back buffer to make sure the next update will redraw everything.
self.buffers[1 - self.current].reset();
Ok(())
}
/// Clears a fixed viewport using terminal clear commands when possible.
///
/// Terminal clear commands can be faster than per-cell updates.
fn clear_fixed_viewport(&mut self, area: Rect) -> Result<(), B::Error> {
if area.is_empty() {
return Ok(());
}
let size = self.backend.size()?;
let is_full_width = area.x == 0 && area.width == size.width;
let ends_at_bottom = area.bottom() == size.height;
if is_full_width && ends_at_bottom {
self.backend.set_cursor_position(area.as_position())?;
self.backend.clear_region(ClearType::AfterCursor)?;
} else if is_full_width {
self.clear_full_width_rows(area)?;
} else {
self.clear_region_cells(area)?;
}
Ok(())
}
/// Clears full-width rows using line clear commands.
///
/// This avoids per-cell writes when the viewport spans the full width.
fn clear_full_width_rows(&mut self, area: Rect) -> Result<(), B::Error> {
for y in area.top()..area.bottom() {
self.backend.set_cursor_position(Position { x: 0, y })?;
self.backend.clear_region(ClearType::CurrentLine)?;
}
Ok(())
}
/// Clears a non-full-width region by writing empty cells directly.
///
/// This is used when line-based clears would affect cells outside the viewport.
fn clear_region_cells(&mut self, area: Rect) -> Result<(), B::Error> {
let clear_cell = Cell::default();
let updates = area.positions().map(|pos| (pos.x, pos.y, &clear_cell));
self.backend.draw(updates)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::backend::{Backend, TestBackend};
use crate::buffer::{Buffer, Cell};
use crate::layout::{Position, Rect};
use crate::terminal::{Terminal, TerminalOptions, Viewport};
#[test]
fn get_frame_uses_current_viewport_and_frame_count() {
let backend = TestBackend::new(5, 3);
let mut terminal = Terminal::new(backend).unwrap();
let frame = terminal.get_frame();
assert_eq!(frame.count, 0);
assert_eq!(frame.area().width, 5);
assert_eq!(frame.area().height, 3);
assert_eq!(frame.buffer.area, frame.area());
}
#[test]
fn flush_writes_updates_and_tracks_last_updated_cell() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
{
let frame = terminal.get_frame();
frame.buffer[(1, 0)].set_symbol("x");
}
terminal.flush().unwrap();
terminal.backend().assert_buffer_lines([" x ", " "]);
assert_eq!(terminal.last_known_cursor_pos, Position { x: 1, y: 0 });
}
#[test]
fn flush_with_no_updates_does_not_change_last_known_cursor_pos() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.set_cursor_position((2, 1)).unwrap();
terminal.flush().unwrap();
assert_eq!(terminal.last_known_cursor_pos, Position { x: 2, y: 1 });
}
#[test]
fn swap_buffers_resets_new_current_buffer() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.buffers[1][(0, 0)].set_symbol("x");
terminal.swap_buffers();
assert_eq!(terminal.current, 1);
assert_eq!(
terminal.buffers[terminal.current],
Buffer::empty(terminal.viewport_area)
);
}
#[test]
fn clear_fullscreen_clears_backend_and_resets_back_buffer() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
{
let frame = terminal.get_frame();
frame.buffer[(0, 0)] = Cell::new("x");
}
terminal.flush().unwrap();
terminal.backend().assert_buffer_lines(["x ", " "]);
terminal.buffers[1][(2, 1)] = Cell::new("y");
terminal.clear().unwrap();
terminal.backend().assert_buffer_lines([" ", " "]);
assert_eq!(
terminal.buffers[1 - terminal.current],
Buffer::empty(terminal.viewport_area)
);
}
#[test]
fn clear_inline_clears_after_viewport_origin_and_resets_back_buffer() {
// Inline clear is implemented as:
// 1) move the backend cursor to the viewport origin
// 2) call ClearType::AfterCursor once
let mut backend = TestBackend::with_lines([
"before 1 ",
"before 2 ",
"viewport 1",
"viewport 2",
"after 1 ",
"after 2 ",
]);
backend
.set_cursor_position(Position { x: 2, y: 2 })
.unwrap();
let options = TerminalOptions {
viewport: Viewport::Inline(2),
};
let mut terminal = Terminal::with_options(backend, options).unwrap();
terminal
.backend_mut()
.set_cursor_position(Position { x: 2, y: 2 })
.unwrap();
terminal.buffers[1][(2, 2)] = Cell::new("x");
terminal.clear().unwrap();
// Inline viewport is anchored to the cursor row (y = 2) with height 2. Clear runs from
// the viewport origin through the end of the display, including the rows after it.
terminal.backend().assert_buffer_lines([
"before 1 ",
"before 2 ",
" ",
" ",
" ",
" ",
]);
assert_eq!(
terminal.buffers[1 - terminal.current],
Buffer::empty(terminal.viewport_area)
);
assert_eq!(
terminal.backend().cursor_position(),
Position { x: 2, y: 2 }
);
}
#[test]
fn clear_fixed_clears_viewport_rows_and_resets_back_buffer() {
// For full-width fixed viewports that reach the terminal bottom, clear uses
// ClearType::AfterCursor starting at the viewport origin.
let mut backend = TestBackend::with_lines(["before 1 ", "viewport 1", "viewport 2"]);
backend.set_cursor_position((2, 0)).unwrap();
let options = TerminalOptions {
viewport: Viewport::Fixed(Rect::new(0, 1, 10, 2)),
};
let mut terminal = Terminal::with_options(backend, options).unwrap();
terminal.clear().unwrap();
terminal
.backend()
.assert_buffer_lines(["before 1 ", " ", " "]);
assert_eq!(
terminal.buffers[1 - terminal.current],
Buffer::empty(terminal.viewport_area)
);
assert_eq!(
terminal.backend().cursor_position(),
Position { x: 2, y: 0 }
);
}
#[test]
fn clear_fixed_full_width_not_at_bottom() {
let mut backend =
TestBackend::with_lines(["before 1 ", "viewport 1", "viewport 2", "after 1 "]);
backend.set_cursor_position((1, 0)).unwrap();
let options = TerminalOptions {
viewport: Viewport::Fixed(Rect::new(0, 1, 10, 2)),
};
let mut terminal = Terminal::with_options(backend, options).unwrap();
terminal.clear().unwrap();
terminal.backend().assert_buffer_lines([
"before 1 ",
" ",
" ",
"after 1 ",
]);
assert_eq!(
terminal.backend().cursor_position(),
Position { x: 1, y: 0 }
);
}
#[test]
fn clear_fixed_respects_non_full_width_viewport() {
let mut backend =
TestBackend::with_lines(["before 1 ", "viewport 1", "viewport 2", "after 1 "]);
backend.set_cursor_position((3, 0)).unwrap();
let options = TerminalOptions {
viewport: Viewport::Fixed(Rect::new(1, 1, 3, 2)),
};
let mut terminal = Terminal::with_options(backend, options).unwrap();
terminal.clear().unwrap();
terminal.backend().assert_buffer_lines([
"before 1 ",
"v port 1",
"v port 2",
"after 1 ",
]);
assert_eq!(
terminal.backend().cursor_position(),
Position { x: 3, y: 0 }
);
}
}

View File

@@ -0,0 +1,151 @@
use crate::backend::Backend;
use crate::layout::Position;
use crate::terminal::Terminal;
impl<B: Backend> Terminal<B> {
/// Hides the cursor.
///
/// When using [`Terminal::draw`], prefer controlling the cursor with
/// [`Frame::set_cursor_position`]. Mixing the APIs can lead to surprising results.
///
/// [`Frame::set_cursor_position`]: crate::terminal::Frame::set_cursor_position
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
pub fn hide_cursor(&mut self) -> Result<(), B::Error> {
self.backend.hide_cursor()?;
self.hidden_cursor = true;
Ok(())
}
/// Shows the cursor.
///
/// When using [`Terminal::draw`], prefer controlling the cursor with
/// [`Frame::set_cursor_position`]. Mixing the APIs can lead to surprising results.
///
/// [`Frame::set_cursor_position`]: crate::terminal::Frame::set_cursor_position
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
pub fn show_cursor(&mut self) -> Result<(), B::Error> {
self.backend.show_cursor()?;
self.hidden_cursor = false;
Ok(())
}
/// Gets the current cursor position.
///
/// This is the position of the cursor after the last draw call and is returned as a tuple of
/// `(x, y)` coordinates.
#[deprecated = "use `get_cursor_position()` instead which returns `Result<Position>`"]
pub fn get_cursor(&mut self) -> Result<(u16, u16), B::Error> {
let Position { x, y } = self.get_cursor_position()?;
Ok((x, y))
}
/// Sets the cursor position.
#[deprecated = "use `set_cursor_position((x, y))` instead which takes `impl Into<Position>`"]
pub fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), B::Error> {
self.set_cursor_position(Position { x, y })
}
/// Gets the current cursor position.
///
/// This queries the backend for the current cursor position.
///
/// When using [`Terminal::draw`], prefer controlling the cursor with
/// [`Frame::set_cursor_position`]. For direct control, see [`Terminal::set_cursor_position`].
///
/// [`Frame::set_cursor_position`]: crate::terminal::Frame::set_cursor_position
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
pub fn get_cursor_position(&mut self) -> Result<Position, B::Error> {
self.backend.get_cursor_position()
}
/// Sets the cursor position.
///
/// This updates the backend cursor and Ratatui's internal cursor tracking. Inline viewports
/// use that tracking when recomputing the viewport on resize.
///
/// When using [`Terminal::draw`], consider using [`Frame::set_cursor_position`] instead so the
/// cursor is updated as part of the normal rendering flow.
///
/// [`Frame::set_cursor_position`]: crate::terminal::Frame::set_cursor_position
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
pub fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> Result<(), B::Error> {
let position = position.into();
self.backend.set_cursor_position(position)?;
self.last_known_cursor_pos = position;
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::backend::{Backend, TestBackend};
use crate::layout::Position;
use crate::terminal::Terminal;
#[test]
fn hide_cursor_updates_terminal_state() {
let backend = TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
terminal.hide_cursor().unwrap();
assert!(terminal.hidden_cursor);
assert!(!terminal.backend().cursor_visible());
}
#[test]
fn show_cursor_updates_terminal_state() {
let backend = TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
terminal.hide_cursor().unwrap();
terminal.show_cursor().unwrap();
assert!(!terminal.hidden_cursor);
assert!(terminal.backend().cursor_visible());
}
#[test]
fn set_cursor_position_updates_backend_and_tracking() {
let backend = TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
terminal.set_cursor_position((3, 4)).unwrap();
assert_eq!(terminal.last_known_cursor_pos, Position { x: 3, y: 4 });
terminal
.backend_mut()
.assert_cursor_position(Position { x: 3, y: 4 });
}
#[test]
fn get_cursor_position_queries_backend() {
let backend = TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.backend_mut()
.set_cursor_position(Position { x: 7, y: 2 })
.unwrap();
assert_eq!(
terminal.get_cursor_position().unwrap(),
Position { x: 7, y: 2 }
);
}
#[test]
#[allow(deprecated)]
fn deprecated_cursor_wrappers_delegate_to_position_apis() {
let backend = TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
terminal.set_cursor(4, 1).unwrap();
assert_eq!(terminal.get_cursor().unwrap(), (4, 1));
assert_eq!(terminal.last_known_cursor_pos, Position { x: 4, y: 1 });
terminal
.backend_mut()
.assert_cursor_position(Position { x: 4, y: 1 });
}
}

View File

@@ -0,0 +1,236 @@
use crate::backend::Backend;
use crate::buffer::Buffer;
use crate::layout::Position;
use crate::terminal::inline::compute_inline_size;
use crate::terminal::{Terminal, TerminalOptions, Viewport};
impl<B: Backend> Terminal<B> {
/// Creates a new [`Terminal`] with the given [`Backend`] with a full screen viewport.
///
/// This is a convenience for [`Terminal::with_options`] with [`Viewport::Fullscreen`].
///
/// After creating a terminal, call [`Terminal::draw`] (or [`Terminal::try_draw`]) in a loop to
/// render your UI.
///
/// Note that unlike [`ratatui::init`], this does not install a panic hook, so it is
/// recommended to do that manually when using this function, otherwise any panic messages will
/// be printed to the alternate screen and the terminal may be left in an unusable state.
///
/// See [how to set up panic hooks](https://ratatui.rs/recipes/apps/panic-hooks/) and
/// [`better-panic` example](https://ratatui.rs/recipes/apps/better-panic/) for more
/// information.
///
/// # Example
///
/// ```rust,no_run
/// # #![allow(unexpected_cfgs)]
/// # #[cfg(feature = "crossterm")]
/// # {
/// use std::io::stdout;
///
/// use ratatui::Terminal;
/// use ratatui::backend::CrosstermBackend;
///
/// let backend = CrosstermBackend::new(stdout());
/// let _terminal = Terminal::new(backend)?;
///
/// // Optionally set up a panic hook to restore the terminal on panic.
/// let old_hook = std::panic::take_hook();
/// std::panic::set_hook(Box::new(move |info| {
/// ratatui::restore();
/// old_hook(info);
/// }));
/// # }
/// # #[cfg(not(feature = "crossterm"))]
/// # {
/// # use ratatui_core::{backend::TestBackend, terminal::Terminal};
/// # let backend = TestBackend::new(10, 10);
/// # let _terminal = Terminal::new(backend)?;
/// # }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// [`ratatui::init`]: https://docs.rs/ratatui/latest/ratatui/fn.init.html
pub fn new(backend: B) -> Result<Self, B::Error> {
Self::with_options(
backend,
TerminalOptions {
viewport: Viewport::Fullscreen,
},
)
}
/// Creates a new [`Terminal`] with the given [`Backend`] and [`TerminalOptions`].
///
/// The viewport determines what area is exposed to widgets via [`Frame::area`]. See
/// [`Viewport`] for an overview of the available modes.
///
/// [`Frame::area`]: crate::terminal::Frame::area
///
/// After creating a terminal, call [`Terminal::draw`] (or [`Terminal::try_draw`]) in a loop to
/// render your UI.
///
/// Resize behavior depends on the selected viewport:
///
/// - [`Viewport::Fullscreen`] and [`Viewport::Inline`] are automatically resized during
/// [`Terminal::draw`] (via [`Terminal::autoresize`]).
/// - [`Viewport::Fixed`] is not automatically resized; call [`Terminal::resize`] if the region
/// should change.
///
/// # Example
///
/// ```rust,no_run
/// # #![allow(unexpected_cfgs)]
/// # #[cfg(feature = "crossterm")]
/// # {
/// use std::io::stdout;
///
/// use ratatui::backend::CrosstermBackend;
/// use ratatui::layout::Rect;
/// use ratatui::{Terminal, TerminalOptions, Viewport};
///
/// let backend = CrosstermBackend::new(stdout());
/// let viewport = Viewport::Fixed(Rect::new(0, 0, 10, 10));
/// let _terminal = Terminal::with_options(backend, TerminalOptions { viewport })?;
/// # }
/// # #[cfg(not(feature = "crossterm"))]
/// # {
/// # use ratatui_core::{
/// # backend::TestBackend,
/// # layout::Rect,
/// # terminal::{Terminal, TerminalOptions, Viewport},
/// # };
/// # let backend = TestBackend::new(10, 10);
/// # let viewport = Viewport::Fixed(Rect::new(0, 0, 10, 10));
/// # let _terminal = Terminal::with_options(backend, TerminalOptions { viewport })?;
/// # }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// When the viewport is [`Viewport::Inline`], Ratatui anchors the viewport to the current
/// cursor row at initialization time (always starting at column 0). Ratatui may scroll the
/// terminal to make enough room for the requested height so the viewport stays fully visible.
pub fn with_options(mut backend: B, options: TerminalOptions) -> Result<Self, B::Error> {
let area = match options.viewport {
Viewport::Fullscreen | Viewport::Inline(_) => backend.size()?.into(),
Viewport::Fixed(area) => area,
};
let (viewport_area, cursor_pos) = match options.viewport {
Viewport::Fullscreen => (area, Position::ORIGIN),
Viewport::Inline(height) => {
compute_inline_size(&mut backend, height, area.as_size(), 0)?
}
Viewport::Fixed(area) => (area, area.as_position()),
};
Ok(Self {
backend,
buffers: [Buffer::empty(viewport_area), Buffer::empty(viewport_area)],
current: 0,
hidden_cursor: false,
viewport: options.viewport,
viewport_area,
last_known_area: area,
last_known_cursor_pos: cursor_pos,
frame_count: 0,
})
}
}
#[cfg(test)]
mod tests {
use crate::backend::{Backend, TestBackend};
use crate::layout::{Position, Rect};
use crate::terminal::{Terminal, TerminalOptions, Viewport};
#[test]
fn new_fullscreen_initializes_state() {
let backend = TestBackend::new(10, 5);
let terminal = Terminal::new(backend).unwrap();
assert_eq!(terminal.viewport, Viewport::Fullscreen);
assert_eq!(terminal.viewport_area, Rect::new(0, 0, 10, 5));
assert_eq!(terminal.last_known_area, Rect::new(0, 0, 10, 5));
assert_eq!(terminal.last_known_cursor_pos, Position::ORIGIN);
assert_eq!(terminal.current, 0);
assert!(!terminal.hidden_cursor);
assert_eq!(terminal.frame_count, 0);
assert_eq!(terminal.buffers[0].area, terminal.viewport_area);
assert_eq!(terminal.buffers[1].area, terminal.viewport_area);
}
#[test]
fn with_options_fixed_uses_fixed_area() {
let backend = TestBackend::new(10, 10);
let viewport = Viewport::Fixed(Rect::new(2, 3, 5, 4));
let terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: viewport.clone(),
},
)
.unwrap();
assert_eq!(terminal.viewport, viewport);
assert_eq!(terminal.viewport_area, Rect::new(2, 3, 5, 4));
assert_eq!(terminal.last_known_area, Rect::new(2, 3, 5, 4));
assert_eq!(terminal.last_known_cursor_pos, Position { x: 2, y: 3 });
assert_eq!(terminal.buffers[0].area, terminal.viewport_area);
assert_eq!(terminal.buffers[1].area, terminal.viewport_area);
}
#[test]
fn with_options_inline_anchors_to_cursor_when_space_available() {
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 3 })
.unwrap();
let terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 3, 10, 4));
assert_eq!(terminal.last_known_cursor_pos, Position { x: 0, y: 3 });
}
#[test]
fn with_options_inline_shifts_up_when_near_bottom() {
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 8 })
.unwrap();
let terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 6, 10, 4));
assert_eq!(terminal.last_known_cursor_pos, Position { x: 0, y: 8 });
}
#[test]
fn with_options_inline_clamps_height_to_terminal() {
let mut backend = TestBackend::new(10, 3);
backend
.set_cursor_position(Position { x: 0, y: 0 })
.unwrap();
let terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(10),
},
)
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 0, 10, 3));
}
}

View File

@@ -0,0 +1,927 @@
use crate::backend::Backend;
use crate::buffer::{Buffer, Cell};
use crate::layout::{Position, Rect, Size};
use crate::terminal::{Terminal, Viewport};
impl<B: Backend> Terminal<B> {
/// Insert some content before the current inline viewport. This has no effect when the
/// viewport is not inline.
///
/// This is intended for inline UIs that want to print output (e.g. logs or status messages)
/// above the UI without breaking it. See [`Viewport::Inline`] for how inline viewports are
/// anchored.
///
/// The `draw_fn` closure will be called to draw into a writable `Buffer` that is `height`
/// lines tall. The content of that `Buffer` will then be inserted before the viewport.
///
/// When Ratatui is built with the `scrolling-regions` feature, this can be done without
/// clearing and redrawing the viewport. Without `scrolling-regions`, Ratatui falls back to a
/// more portable approach and clears the viewport so the next [`Terminal::draw`] repaints it.
///
/// If the viewport isn't yet at the bottom of the screen, inserted lines will push it towards
/// the bottom. Once the viewport is at the bottom of the screen, inserted lines will scroll
/// the area of the screen above the viewport upwards.
///
/// Before:
/// ```text
/// +---------------------+
/// | pre-existing line 1 |
/// | pre-existing line 2 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// | |
/// | |
/// +---------------------+
/// ```
///
/// After inserting 2 lines:
/// ```text
/// +---------------------+
/// | pre-existing line 1 |
/// | pre-existing line 2 |
/// | inserted line 1 |
/// | inserted line 2 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// +---------------------+
/// ```
///
/// After inserting 2 more lines:
/// ```text
/// +---------------------+
/// | pre-existing line 2 |
/// | inserted line 1 |
/// | inserted line 2 |
/// | inserted line 3 |
/// | inserted line 4 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// ```
///
/// If more lines are inserted than there is space on the screen, then the top lines will go
/// directly into the terminal's scrollback buffer. At the limit, if the viewport takes up the
/// whole screen, all lines will be inserted directly into the scrollback buffer.
///
/// # Examples
///
/// ## Insert a single line before the current viewport
///
/// ```rust,no_run
/// # mod ratatui {
/// # pub use ratatui_core::backend;
/// # pub use ratatui_core::layout;
/// # pub use ratatui_core::style;
/// # pub use ratatui_core::terminal::{Terminal, TerminalOptions, Viewport};
/// # pub use ratatui_core::text;
/// # pub use ratatui_core::widgets;
/// # }
/// use ratatui::backend::{Backend, TestBackend};
/// use ratatui::layout::Position;
/// use ratatui::style::{Color, Style};
/// use ratatui::text::{Line, Span};
/// use ratatui::widgets::Widget;
/// use ratatui::{Terminal, TerminalOptions, Viewport};
///
/// let mut backend = TestBackend::new(10, 10);
/// // Simulate existing output above the inline UI.
/// backend.set_cursor_position(Position::new(0, 3))?;
/// let mut terminal = Terminal::with_options(
/// backend,
/// TerminalOptions {
/// viewport: Viewport::Inline(4),
/// },
/// )?;
///
/// terminal.insert_before(1, |buf| {
/// Line::from(vec![
/// Span::raw("This line will be added "),
/// Span::styled("before", Style::default().fg(Color::Blue)),
/// Span::raw(" the current viewport"),
/// ])
/// .render(buf.area, buf);
/// })?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn insert_before<F>(&mut self, height: u16, draw_fn: F) -> Result<(), B::Error>
where
F: FnOnce(&mut Buffer),
{
match self.viewport {
#[cfg(feature = "scrolling-regions")]
Viewport::Inline(_) => self.insert_before_scrolling_regions(height, draw_fn),
#[cfg(not(feature = "scrolling-regions"))]
Viewport::Inline(_) => self.insert_before_no_scrolling_regions(height, draw_fn),
_ => Ok(()),
}
}
/// Implement `Self::insert_before` using standard backend capabilities.
///
/// This is the fallback implementation when the `scrolling-regions` feature is disabled. It
/// renders the inserted lines into a temporary [`Buffer`], then draws them directly to the
/// backend in chunks, scrolling the terminal as needed.
///
/// See [`Terminal::insert_before`] for the public API contract.
#[cfg(not(feature = "scrolling-regions"))]
fn insert_before_no_scrolling_regions(
&mut self,
height: u16,
draw_fn: impl FnOnce(&mut Buffer),
) -> Result<(), B::Error> {
let area = Rect {
x: 0,
y: 0,
width: self.viewport_area.width,
height,
};
let mut buffer = Buffer::empty(area);
draw_fn(&mut buffer);
let mut buffer = buffer.content.as_slice();
// Use i32 variables so we don't have worry about overflowed u16s when adding, or about
// negative results when subtracting.
let mut drawn_height: i32 = self.viewport_area.top().into();
let mut buffer_height: i32 = height.into();
let viewport_height: i32 = self.viewport_area.height.into();
let screen_height: i32 = self.last_known_area.height.into();
// The algorithm here is to loop, drawing large chunks of text (up to a screen-full at a
// time), until the remainder of the buffer plus the viewport fits on the screen. We choose
// this loop condition because it guarantees that we can write the remainder of the buffer
// with just one call to Self::draw_lines().
while buffer_height + viewport_height > screen_height {
// We will draw as much of the buffer as possible on this iteration in order to make
// forward progress. So we have:
//
// to_draw = min(buffer_height, screen_height)
//
// We may need to scroll the screen up to make room to draw. We choose the minimal
// possible scroll amount so we don't end up with the viewport sitting in the middle of
// the screen when this function is done. The amount to scroll by is:
//
// scroll_up = max(0, drawn_height + to_draw - screen_height)
//
// We want `scroll_up` to be enough so that, after drawing, we have used the whole
// screen (drawn_height - scroll_up + to_draw = screen_height). However, there might
// already be enough room on the screen to draw without scrolling (drawn_height +
// to_draw <= screen_height). In this case, we just don't scroll at all.
let to_draw = buffer_height.min(screen_height);
let scroll_up = 0.max(drawn_height + to_draw - screen_height);
self.scroll_up(scroll_up as u16)?;
buffer = self.draw_lines((drawn_height - scroll_up) as u16, to_draw as u16, buffer)?;
drawn_height += to_draw - scroll_up;
buffer_height -= to_draw;
}
// There is now enough room on the screen for the remaining buffer plus the viewport,
// though we may still need to scroll up some of the existing text first. It's possible
// that by this point we've drained the buffer, but we may still need to scroll up to make
// room for the viewport.
//
// We want to scroll up the exact amount that will leave us completely filling the screen.
// However, it's possible that the viewport didn't start on the bottom of the screen and
// the added lines weren't enough to push it all the way to the bottom. We deal with this
// case by just ensuring that our scroll amount is non-negative.
//
// We want:
// screen_height = drawn_height - scroll_up + buffer_height + viewport_height
// Or, equivalently:
// scroll_up = drawn_height + buffer_height + viewport_height - screen_height
let scroll_up = 0.max(drawn_height + buffer_height + viewport_height - screen_height);
self.scroll_up(scroll_up as u16)?;
self.draw_lines(
(drawn_height - scroll_up) as u16,
buffer_height as u16,
buffer,
)?;
drawn_height += buffer_height - scroll_up;
self.set_viewport_area(Rect {
y: drawn_height as u16,
..self.viewport_area
});
// Clear the viewport off the screen. We didn't clear earlier for two reasons. First, it
// wasn't necessary because the buffer we drew out of isn't sparse, so it overwrote
// whatever was on the screen. Second, there is a weird bug with tmux where a full screen
// clear plus immediate scrolling causes some garbage to go into the scrollback.
self.clear()?;
Ok(())
}
/// Implement `Self::insert_before` using scrolling regions.
///
/// If a terminal supports scrolling regions, it means that we can define a subset of rows of
/// the screen, and then tell the terminal to scroll up or down just within that region. The
/// rows outside of the region are not affected.
///
/// This function utilizes this feature to avoid having to redraw the viewport. This is done
/// either by splitting the screen at the top of the viewport, and then creating a gap by
/// either scrolling the viewport down, or scrolling the area above it up. The lines to insert
/// are then drawn into the gap created.
#[cfg(feature = "scrolling-regions")]
fn insert_before_scrolling_regions(
&mut self,
mut height: u16,
draw_fn: impl FnOnce(&mut Buffer),
) -> Result<(), B::Error> {
let area = Rect {
x: 0,
y: 0,
width: self.viewport_area.width,
height,
};
let mut buffer = Buffer::empty(area);
draw_fn(&mut buffer);
let mut buffer = buffer.content.as_slice();
// Handle the special case where the viewport takes up the whole screen.
if self.viewport_area.height == self.last_known_area.height {
// "Borrow" the top line of the viewport. Draw over it, then immediately scroll it into
// scrollback. Do this repeatedly until the whole buffer has been put into scrollback.
let mut first = true;
while !buffer.is_empty() {
buffer = if first {
self.draw_lines(0, 1, buffer)?
} else {
self.draw_lines_over_cleared(0, 1, buffer)?
};
first = false;
self.backend.scroll_region_up(0..1, 1)?;
}
// Redraw the top line of the viewport.
let width = self.viewport_area.width as usize;
let top_line = self.buffers[1 - self.current].content[0..width].to_vec();
self.draw_lines_over_cleared(0, 1, &top_line)?;
return Ok(());
}
// Handle the case where the viewport isn't yet at the bottom of the screen.
{
let viewport_top = self.viewport_area.top();
let viewport_bottom = self.viewport_area.bottom();
let screen_bottom = self.last_known_area.bottom();
if viewport_bottom < screen_bottom {
let to_draw = height.min(screen_bottom - viewport_bottom);
self.backend
.scroll_region_down(viewport_top..viewport_bottom + to_draw, to_draw)?;
buffer = self.draw_lines_over_cleared(viewport_top, to_draw, buffer)?;
self.set_viewport_area(Rect {
y: viewport_top + to_draw,
..self.viewport_area
});
height -= to_draw;
}
}
let viewport_top = self.viewport_area.top();
while height > 0 {
let to_draw = height.min(viewport_top);
self.backend.scroll_region_up(0..viewport_top, to_draw)?;
buffer = self.draw_lines_over_cleared(viewport_top - to_draw, to_draw, buffer)?;
height -= to_draw;
}
Ok(())
}
/// Draw lines at the given vertical offset. The slice of cells must contain enough cells
/// for the requested lines. A slice of the unused cells are returned.
///
/// This is a small internal helper used by [`Terminal::insert_before`]. It writes cells
/// directly to the backend in terminal coordinates (not viewport coordinates).
fn draw_lines<'a>(
&mut self,
y_offset: u16,
lines_to_draw: u16,
cells: &'a [Cell],
) -> Result<&'a [Cell], B::Error> {
let width: usize = self.last_known_area.width.into();
let (to_draw, remainder) = cells.split_at(width * lines_to_draw as usize);
if lines_to_draw > 0 {
let iter = to_draw
.iter()
.enumerate()
.map(|(i, c)| ((i % width) as u16, y_offset + (i / width) as u16, c));
self.backend.draw(iter)?;
self.backend.flush()?;
}
Ok(remainder)
}
/// Draw lines at the given vertical offset, assuming that the lines they are replacing on the
/// screen are cleared. The slice of cells must contain enough cells for the requested lines. A
/// slice of the unused cells are returned.
///
/// This is used by the `scrolling-regions` implementation of [`Terminal::insert_before`] to
/// avoid relying on a full-screen clear while updating only part of the terminal.
#[cfg(feature = "scrolling-regions")]
fn draw_lines_over_cleared<'a>(
&mut self,
y_offset: u16,
lines_to_draw: u16,
cells: &'a [Cell],
) -> Result<&'a [Cell], B::Error> {
let width: usize = self.last_known_area.width.into();
let (to_draw, remainder) = cells.split_at(width * lines_to_draw as usize);
if lines_to_draw > 0 {
let area = Rect::new(0, y_offset, width as u16, y_offset + lines_to_draw);
let old = Buffer::empty(area);
let new = Buffer {
area,
content: to_draw.to_vec(),
};
self.backend.draw(old.diff(&new).into_iter())?;
self.backend.flush()?;
}
Ok(remainder)
}
/// Scroll the whole screen up by the given number of lines.
///
/// This is used by [`Terminal::insert_before`] when the `scrolling-regions` feature is
/// disabled.
/// It scrolls by moving the cursor to the last row and calling [`Backend::append_lines`].
#[cfg(not(feature = "scrolling-regions"))]
fn scroll_up(&mut self, lines_to_scroll: u16) -> Result<(), B::Error> {
if lines_to_scroll > 0 {
self.set_cursor_position(Position::new(
0,
self.last_known_area.height.saturating_sub(1),
))?;
self.backend.append_lines(lines_to_scroll)?;
}
Ok(())
}
}
/// Compute the on-screen area for an inline viewport.
///
/// This helper is used by [`Terminal::with_options`] (initialization) and [`Terminal::resize`]
/// (after a terminal resize) to translate `Viewport::Inline(height)` into a concrete [`Rect`].
///
/// This returns the computed viewport area and the cursor position observed at the start of the
/// call.
///
/// Inline viewports always start at column 0, span the full terminal width, and are anchored to the
/// backend cursor row at the time of the call. The requested height is clamped to the current
/// terminal height.
///
/// Ratatui reserves vertical space for the requested height by calling [`Backend::append_lines`].
/// If the cursor is close enough to the bottom that appending would run past the last row,
/// terminals scroll; in that case we shift the computed `y` upward by the number of rows scrolled
/// so the viewport remains fully visible.
///
/// `offset_in_previous_viewport` is used by [`Terminal::resize`] to keep the cursor at the same
/// relative row within the viewport across resizes.
///
/// Related viewport code lives in:
///
/// - [`Terminal::with_options`] (selects the viewport and computes the initial area)
/// - [`Terminal::autoresize`] (detects backend size changes during [`Terminal::draw`])
/// - [`Terminal::resize`] (recomputes the viewport and clears before the next draw)
pub(crate) fn compute_inline_size<B: Backend>(
backend: &mut B,
height: u16,
size: Size,
offset_in_previous_viewport: u16,
) -> Result<(Rect, Position), B::Error> {
let pos = backend.get_cursor_position()?;
let mut row = pos.y;
let max_height = size.height.min(height);
let lines_after_cursor = height
.saturating_sub(offset_in_previous_viewport)
.saturating_sub(1);
backend.append_lines(lines_after_cursor)?;
let available_lines = size.height.saturating_sub(row).saturating_sub(1);
let missing_lines = lines_after_cursor.saturating_sub(available_lines);
if missing_lines > 0 {
row = row.saturating_sub(missing_lines);
}
row = row.saturating_sub(offset_in_previous_viewport);
Ok((
Rect {
x: 0,
y: row,
width: size.width,
height: max_height,
},
pos,
))
}
#[cfg(test)]
mod tests {
use crate::backend::{Backend, TestBackend};
use crate::layout::{Position, Rect, Size};
use crate::style::Style;
use crate::terminal::inline::compute_inline_size;
use crate::terminal::{Terminal, TerminalOptions, Viewport};
#[test]
fn compute_inline_size_uses_cursor_offset_when_space_available() {
// Diagram (terminal height = 10, requested viewport height = 4):
//
// Cursor at y=6, previous cursor offset within viewport = 1.
//
// Before (conceptually):
// 0
// 1
// 2
// 3
// 4
// 5 <- viewport top (expected)
// 6 <- cursor row (observed_pos.y)
// 7
// 8
// 9
//
// After: viewport top y = 5 (6 - 1), height = 4 => rows 5..9 (exclusive).
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 6 })
.unwrap();
let (area, observed_pos) =
compute_inline_size(&mut backend, 4, Size::new(10, 10), 1).unwrap();
assert_eq!(observed_pos, Position { x: 0, y: 6 });
assert_eq!(area, Rect::new(0, 5, 10, 4));
}
#[test]
fn compute_inline_size_saturates_when_offset_exceeds_cursor_row() {
// Diagram (terminal height = 10, requested viewport height = 4):
//
// Cursor at y=0, previous cursor offset within viewport = 5 (nonsensical but possible if
// callers pass a stale/oversized offset).
//
// We saturate so the computed viewport top cannot go negative:
// top = cursor_y.saturating_sub(offset) = 0.saturating_sub(5) = 0
//
// Expected viewport area:
// y=0..4 (fully pinned to the top)
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 0 })
.unwrap();
let (area, _observed_pos) =
compute_inline_size(&mut backend, 4, Size::new(10, 10), 5).unwrap();
assert_eq!(area, Rect::new(0, 0, 10, 4));
}
#[cfg(not(feature = "scrolling-regions"))]
mod no_scrolling_regions {
use super::*;
#[test]
fn insert_before_is_noop_for_non_inline_viewports() {
// Diagram:
//
// Viewport is fullscreen (not inline), so insert_before() is a no-op.
//
// Screen before:
// x..
// ...
//
// Screen after:
// x..
// ...
let mut terminal = Terminal::new(TestBackend::new(3, 2)).unwrap();
{
let frame = terminal.get_frame();
frame.buffer[(0, 0)].set_symbol("x");
}
terminal.flush().unwrap();
let viewport_area = terminal.viewport_area;
terminal
.insert_before(1, |buf| {
buf.set_string(0, 0, "zzz", Style::default());
})
.unwrap();
assert_eq!(terminal.viewport_area, viewport_area);
terminal.backend().assert_buffer_lines(["x ", " "]);
}
#[test]
fn insert_before_pushes_viewport_down_when_space_available() {
// Diagram (screen height = 10, viewport height = 4, cursor row = 3):
//
// Before:
// 0: 0000000000
// 1: 1111111111
// 2: 2222222222
// 3: [viewport top] 3333333333
// 4: 4444444444
// 5: 5555555555
// 6: 6666666666
// 7: 7777777777
// 8: 8888888888
// 9: 9999999999
//
// After inserting 1 line above an inline viewport (no scrolling regions):
// - A line is drawn at the old viewport top (y=3)
// - The viewport moves down by 1 row (new top y=4)
// - The viewport is cleared so it will be redrawn on the next draw()
let mut backend = TestBackend::with_lines([
"0000000000",
"1111111111",
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"6666666666",
"7777777777",
"8888888888",
"9999999999",
]);
backend
.set_cursor_position(Position { x: 0, y: 3 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.insert_before(1, |buf| {
buf.set_string(0, 0, "INSERTLINE", Style::default());
})
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 4, 10, 4));
terminal.backend().assert_buffer_lines([
"0000000000",
"1111111111",
"2222222222",
"INSERTLINE",
" ",
" ",
" ",
" ",
" ",
" ",
]);
}
#[test]
fn insert_before_scrolls_when_viewport_is_at_bottom() {
// Diagram (screen height = 10, viewport height = 4, cursor row = 6):
//
// Before:
// 0: 0000000000
// 1: 1111111111
// 2: 2222222222
// 3: 3333333333
// 4: 4444444444
// 5: 5555555555
// 6: [viewport top] 6666666666
// 7: 7777777777
// 8: 8888888888
// 9: 9999999999
//
// After inserting 2 lines:
// - The area above the viewport scrolls up to make room
// - Inserted lines appear immediately above the viewport
// - The viewport is cleared so it will be redrawn on the next draw()
let mut backend = TestBackend::with_lines([
"0000000000",
"1111111111",
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"6666666666",
"7777777777",
"8888888888",
"9999999999",
]);
backend
.set_cursor_position(Position { x: 0, y: 6 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.insert_before(2, |buf| {
buf.set_string(0, 0, "INSERTED1", Style::default());
buf.set_string(0, 1, "INSERTED2", Style::default());
})
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 6, 10, 4));
terminal.backend().assert_buffer_lines([
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"INSERTED1 ",
"INSERTED2 ",
" ",
" ",
" ",
" ",
]);
}
#[test]
fn insert_before_then_draw_repaints_cleared_viewport() {
// Diagram (screen height = 10, viewport height = 4, cursor row = 6):
//
// 1) Draw a frame into the inline viewport at the bottom:
// 6..9: AAAAAAAAAA
//
// 2) Insert 2 lines above the viewport:
// - Inserts appear at rows 4..5
// - Viewport is cleared (so it is blank on-screen until the next draw)
//
// 3) Draw again:
// 6..9: BBBBBBBBBB
//
// Expected final screen:
// 4: INSERTED00
// 5: INSERTED01
// 6..9: BBBBBBBBBB
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 6 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
for y in area.top()..area.bottom() {
frame
.buffer
.set_string(area.x, y, "AAAAAAAAAA", Style::default());
}
})
.unwrap();
terminal
.insert_before(2, |buf| {
buf.set_string(0, 0, "INSERTED00", Style::default());
buf.set_string(0, 1, "INSERTED01", Style::default());
})
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
for y in area.top()..area.bottom() {
frame
.buffer
.set_string(area.x, y, "BBBBBBBBBB", Style::default());
}
})
.unwrap();
terminal.backend().assert_buffer_lines([
" ",
" ",
" ",
" ",
"INSERTED00",
"INSERTED01",
"BBBBBBBBBB",
"BBBBBBBBBB",
"BBBBBBBBBB",
"BBBBBBBBBB",
]);
}
}
#[cfg(feature = "scrolling-regions")]
mod scrolling_regions {
use super::*;
#[test]
fn insert_before_moves_viewport_down_without_clearing() {
// Diagram (screen height = 10, viewport height = 4, cursor row = 3):
//
// With scrolling regions enabled, we can create a gap and draw the inserted line
// without clearing the viewport content.
//
// Before:
// 2: 2222222222
// 3: [viewport top] 3333333333
// 4: 4444444444
//
// After:
// 3: INSERTLINE
// 4: 3333333333 (viewport content preserved)
let mut backend = TestBackend::with_lines([
"0000000000",
"1111111111",
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"6666666666",
"7777777777",
"8888888888",
"9999999999",
]);
backend
.set_cursor_position(Position { x: 0, y: 3 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.insert_before(1, |buf| {
buf.set_string(0, 0, "INSERTLINE", Style::default());
})
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 4, 10, 4));
terminal.backend().assert_buffer_lines([
"0000000000",
"1111111111",
"2222222222",
"INSERTLINE",
"3333333333",
"4444444444",
"5555555555",
"6666666666",
"8888888888",
"9999999999",
]);
}
#[test]
fn insert_before_when_viewport_is_at_bottom_preserves_viewport() {
// Diagram (screen height = 10, viewport height = 4, viewport top = 6):
//
// With scrolling regions enabled and the viewport already at the bottom:
// - The region above the viewport (rows 0..6) scrolls up to make room.
// - Inserted lines are drawn into the cleared space immediately above the viewport.
// - The viewport itself is not cleared and stays on-screen.
//
// Before (after drawing V into the viewport):
// 0: 0000000000
// 1: 1111111111
// 2: 2222222222
// 3: 3333333333
// 4: 4444444444
// 5: 5555555555
// 6..9: VVVVVVVVVV
//
// After inserting 2 lines:
// 0..3: previous 2..5
// 4: AAAAAAAAAA
// 5: BBBBBBBBBB
// 6..9: VVVVVVVVVV
//
// The scrolled-off lines are appended to scrollback (previous 0 and 1).
let mut backend = TestBackend::with_lines([
"0000000000",
"1111111111",
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"6666666666",
"7777777777",
"8888888888",
"9999999999",
]);
backend
.set_cursor_position(Position { x: 0, y: 6 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
for y in area.top()..area.bottom() {
frame
.buffer
.set_string(area.x, y, "VVVVVVVVVV", Style::default());
}
})
.unwrap();
terminal
.insert_before(2, |buf| {
buf.set_string(0, 0, "AAAAAAAAAA", Style::default());
buf.set_string(0, 1, "BBBBBBBBBB", Style::default());
})
.unwrap();
terminal.backend().assert_buffer_lines([
"2222222222",
"3333333333",
"4444444444",
"5555555555",
"AAAAAAAAAA",
"BBBBBBBBBB",
"VVVVVVVVVV",
"VVVVVVVVVV",
"VVVVVVVVVV",
"VVVVVVVVVV",
]);
terminal
.backend()
.assert_scrollback_lines(["0000000000", "1111111111"]);
}
#[test]
fn insert_before_when_viewport_is_fullscreen_appends_to_scrollback() {
// Diagram (screen height = 4, viewport height = 4):
//
// When the viewport takes the whole screen, there is no visible "area above" it.
// The scrolling-regions implementation handles this by repeatedly:
// - drawing one line over the top row
// - immediately scrolling that row into scrollback
//
// The viewport content stays on-screen; inserted lines end up in scrollback.
let mut backend = TestBackend::new(10, 4);
backend
.set_cursor_position(Position { x: 0, y: 0 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
frame
.buffer
.set_string(area.x, area.y, "VIEWLINE00", Style::default());
frame
.buffer
.set_string(area.x, area.y + 1, "VIEWLINE01", Style::default());
frame
.buffer
.set_string(area.x, area.y + 2, "VIEWLINE02", Style::default());
frame
.buffer
.set_string(area.x, area.y + 3, "VIEWLINE03", Style::default());
})
.unwrap();
terminal
.insert_before(2, |buf| {
buf.set_string(0, 0, "INSERTED00", Style::default());
buf.set_string(0, 1, "INSERTED01", Style::default());
})
.unwrap();
terminal.backend().assert_buffer_lines([
"VIEWLINE00",
"VIEWLINE01",
"VIEWLINE02",
"VIEWLINE03",
]);
terminal
.backend()
.assert_scrollback_lines(["INSERTED00", "INSERTED01"]);
}
}
}

View File

@@ -0,0 +1,737 @@
use crate::backend::Backend;
use crate::terminal::{CompletedFrame, Frame, Terminal};
impl<B: Backend> Terminal<B> {
/// Draws a single frame to the terminal.
///
/// Returns a [`CompletedFrame`] if successful, otherwise a backend error (`B::Error`).
///
/// If the render callback passed to this method can fail, use [`try_draw`] instead.
///
/// Applications should call `draw` or [`try_draw`] in a loop to continuously render the
/// terminal. These methods are the main entry points for drawing to the terminal.
///
/// [`try_draw`]: Terminal::try_draw
///
/// The [`Frame`] passed to the render callback represents the currently configured
/// [`Viewport`] (see [`Frame::area`] and [`Terminal::with_options`]).
///
/// Build layout relative to the [`Rect`] returned by [`Frame::area`] rather than assuming the
/// origin is `(0, 0)`, so the same rendering code works for fixed and inline viewports.
///
/// [`Frame::area`]: crate::terminal::Frame::area
/// [`Rect`]: crate::layout::Rect
/// [`Viewport`]: crate::terminal::Viewport
///
/// This method will:
///
/// - call [`Terminal::autoresize`] if necessary
/// - call the render callback, passing it a [`Frame`] reference to render to
/// - call [`Terminal::flush`] to write changes to the backend
/// - show/hide the cursor based on [`Frame::set_cursor_position`]
/// - call [`Terminal::swap_buffers`] to prepare for the next render pass
/// - call [`Backend::flush`]
/// - return a [`CompletedFrame`] with the current buffer and the area used for rendering
///
/// The [`CompletedFrame`] returned by this method can be useful for debugging or testing
/// purposes, but it is often not used in regular applications.
///
/// The render callback should fully render the entire frame when called, including areas that
/// are unchanged from the previous frame. This is because each frame is compared to the
/// previous frame to determine what has changed, and only the changes are written to the
/// terminal. If the render callback does not fully render the frame, the terminal will not be
/// in a consistent state.
///
/// # Examples
///
/// ```rust,no_run
/// # mod ratatui {
/// # pub use ratatui_core::backend;
/// # pub use ratatui_core::layout;
/// # pub use ratatui_core::terminal::{Frame, Terminal};
/// # }
/// use ratatui::backend::TestBackend;
/// use ratatui::layout::Position;
/// use ratatui::{Frame, Terminal};
///
/// let backend = TestBackend::new(10, 10);
/// let mut terminal = Terminal::new(backend)?;
///
/// // With a closure.
/// terminal.draw(|frame| {
/// let area = frame.area();
/// frame.render_widget("Hello World!", area);
/// frame.set_cursor_position(Position { x: 0, y: 0 });
/// })?;
///
/// // Or with a function.
/// terminal.draw(render)?;
///
/// fn render(frame: &mut Frame<'_>) {
/// frame.render_widget("Hello World!", frame.area());
/// }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// [`Backend::flush`]: crate::backend::Backend::flush
pub fn draw<F>(&mut self, render_callback: F) -> Result<CompletedFrame<'_>, B::Error>
where
F: FnOnce(&mut Frame),
{
self.try_draw(|frame| {
render_callback(frame);
Ok::<(), B::Error>(())
})
}
/// Tries to draw a single frame to the terminal.
///
/// Returns [`Result::Ok`] containing a [`CompletedFrame`] if successful, otherwise
/// [`Result::Err`] containing the backend error (`B::Error`) that caused the failure.
///
/// This is the equivalent of [`Terminal::draw`] but the render callback is a function or
/// closure that returns a `Result` instead of nothing.
///
/// Applications should call `try_draw` or [`draw`] in a loop to continuously render the
/// terminal. These methods are the main entry points for drawing to the terminal.
///
/// [`draw`]: Terminal::draw
///
/// The [`Frame`] passed to the render callback represents the currently configured
/// [`Viewport`] (see [`Frame::area`] and [`Terminal::with_options`]).
///
/// Build layout relative to the [`Rect`] returned by [`Frame::area`] rather than assuming the
/// origin is `(0, 0)`, so the same rendering code works for fixed and inline viewports.
///
/// [`Frame::area`]: crate::terminal::Frame::area
/// [`Rect`]: crate::layout::Rect
/// [`Viewport`]: crate::terminal::Viewport
///
/// This method will:
///
/// - call [`Terminal::autoresize`] if necessary
/// - call the render callback, passing it a [`Frame`] reference to render to
/// - call [`Terminal::flush`] to write changes to the backend
/// - show/hide the cursor based on [`Frame::set_cursor_position`]
/// - call [`Terminal::swap_buffers`] to prepare for the next render pass
/// - call [`Backend::flush`]
/// - return a [`CompletedFrame`] with the current buffer and the area used for rendering
///
/// The render callback passed to `try_draw` can return any [`Result`] with an error type that
/// can be converted into `B::Error` using the [`Into`] trait. This makes it possible to use the
/// `?` operator to propagate errors that occur during rendering. If the render callback returns
/// an error, the error will be returned from `try_draw` and the terminal will not be updated.
///
/// The [`CompletedFrame`] returned by this method can be useful for debugging or testing
/// purposes, but it is often not used in regular applications.
///
/// The render callback should fully render the entire frame when called, including areas that
/// are unchanged from the previous frame. This is because each frame is compared to the
/// previous frame to determine what has changed, and only the changes are written to the
/// terminal. If the render function does not fully render the frame, the terminal will not be
/// in a consistent state.
///
/// # Examples
///
/// ```rust,no_run
/// # #![allow(unexpected_cfgs)]
/// # #[cfg(feature = "crossterm")]
/// # {
/// use std::io;
///
/// use ratatui::backend::CrosstermBackend;
/// use ratatui::layout::Position;
/// use ratatui::{Frame, Terminal};
///
/// let backend = CrosstermBackend::new(std::io::stdout());
/// let mut terminal = Terminal::new(backend)?;
///
/// // With a closure that returns `Result`.
/// terminal.try_draw(|frame| -> io::Result<()> {
/// let _value: u8 = "42".parse().map_err(io::Error::other)?;
/// let area = frame.area();
/// frame.render_widget("Hello World!", area);
/// frame.set_cursor_position(Position { x: 0, y: 0 });
/// Ok(())
/// })?;
///
/// // Or with a function.
/// terminal.try_draw(render)?;
///
/// fn render(frame: &mut Frame<'_>) -> io::Result<()> {
/// frame.render_widget("Hello World!", frame.area());
/// Ok(())
/// }
/// # }
/// # #[cfg(not(feature = "crossterm"))]
/// # {
/// # use ratatui_core::{backend::TestBackend, terminal::Terminal};
/// # let backend = TestBackend::new(10, 10);
/// # let mut terminal = Terminal::new(backend)?;
/// # terminal
/// # .try_draw(|frame| {
/// # frame.render_widget("Hello World!", frame.area());
/// # Ok::<(), core::convert::Infallible>(())
/// # })
/// # ?;
/// # }
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
///
/// [`Backend::flush`]: crate::backend::Backend::flush
pub fn try_draw<F, E>(&mut self, render_callback: F) -> Result<CompletedFrame<'_>, B::Error>
where
F: FnOnce(&mut Frame) -> Result<(), E>,
E: Into<B::Error>,
{
// Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
// and the terminal (if growing), which may OOB.
self.autoresize()?;
let mut frame = self.get_frame();
render_callback(&mut frame).map_err(Into::into)?;
// We can't change the cursor position right away because we have to flush the frame to
// stdout first. But we also can't keep the frame around, since it holds a &mut to
// Buffer. Thus, we're taking the important data out of the Frame and dropping it.
let cursor_position = frame.cursor_position;
// Apply the buffer diff to the backend (this is the terminal's "flush" step, distinct
// from `Backend::flush` below which flushes the backend's output).
self.flush()?;
match cursor_position {
None => self.hide_cursor()?,
Some(position) => {
self.show_cursor()?;
self.set_cursor_position(position)?;
}
}
self.swap_buffers();
// Flush any buffered backend output.
self.backend.flush()?;
let completed_frame = CompletedFrame {
buffer: &self.buffers[1 - self.current],
area: self.last_known_area,
count: self.frame_count,
};
// increment frame count before returning from draw
self.frame_count = self.frame_count.wrapping_add(1);
Ok(completed_frame)
}
}
#[cfg(test)]
mod tests {
use core::fmt;
use crate::backend::{Backend, ClearType, TestBackend, WindowSize};
use crate::buffer::{Buffer, Cell};
use crate::layout::{Position, Rect};
use crate::terminal::{Terminal, TerminalOptions, Viewport};
#[derive(Debug, Clone, Eq, PartialEq)]
struct TestError(&'static str);
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl core::error::Error for TestError {}
/// A thin wrapper around [`TestBackend`] with a fallible error type.
///
/// [`TestBackend`] uses [`core::convert::Infallible`] as its associated `Backend::Error`, which
/// is ideal for most tests but makes it impossible to write a `try_draw` callback that returns
/// an error (because `E: Into<B::Error>` would require converting a real error into
/// `Infallible`). This wrapper keeps the same observable backend behavior (buffer + cursor)
/// while allowing tests to exercise `Terminal::try_draw`'s error path.
#[derive(Debug, Clone, Eq, PartialEq)]
struct FallibleTestBackend {
inner: TestBackend,
}
impl FallibleTestBackend {
fn new(inner: TestBackend) -> Self {
Self { inner }
}
}
impl Backend for FallibleTestBackend {
type Error = TestError;
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where
I: Iterator<Item = (u16, u16, &'a crate::buffer::Cell)>,
{
self.inner.draw(content).map_err(|err| match err {})
}
fn append_lines(&mut self, n: u16) -> Result<(), Self::Error> {
self.inner.append_lines(n).map_err(|err| match err {})
}
fn hide_cursor(&mut self) -> Result<(), Self::Error> {
self.inner.hide_cursor().map_err(|err| match err {})
}
fn show_cursor(&mut self) -> Result<(), Self::Error> {
self.inner.show_cursor().map_err(|err| match err {})
}
fn get_cursor_position(&mut self) -> Result<Position, Self::Error> {
self.inner.get_cursor_position().map_err(|err| match err {})
}
fn set_cursor_position<P: Into<Position>>(
&mut self,
position: P,
) -> Result<(), Self::Error> {
self.inner
.set_cursor_position(position)
.map_err(|err| match err {})
}
fn clear(&mut self) -> Result<(), Self::Error> {
self.inner.clear().map_err(|err| match err {})
}
fn clear_region(&mut self, clear_type: ClearType) -> Result<(), Self::Error> {
self.inner
.clear_region(clear_type)
.map_err(|err| match err {})
}
fn size(&self) -> Result<crate::layout::Size, Self::Error> {
self.inner.size().map_err(|err| match err {})
}
fn window_size(&mut self) -> Result<WindowSize, Self::Error> {
self.inner.window_size().map_err(|err| match err {})
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.inner.flush().map_err(|err| match err {})
}
#[cfg(feature = "scrolling-regions")]
fn scroll_region_up(
&mut self,
region: core::ops::Range<u16>,
line_count: u16,
) -> Result<(), Self::Error> {
self.inner
.scroll_region_up(region, line_count)
.map_err(|err| match err {})
}
#[cfg(feature = "scrolling-regions")]
fn scroll_region_down(
&mut self,
region: core::ops::Range<u16>,
line_count: u16,
) -> Result<(), Self::Error> {
self.inner
.scroll_region_down(region, line_count)
.map_err(|err| match err {})
}
}
/// `draw` hides the cursor when the frame does not request a cursor position.
///
/// This asserts the end-to-end effect on the backend (buffer contents + cursor state) as well
/// as internal frame counting.
#[test]
fn draw_hides_cursor_when_frame_cursor_is_not_set() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.show_cursor().unwrap();
let completed = terminal
.draw(|frame| {
// Ensure the frame produces updates so `Terminal::flush` writes to the backend.
frame.buffer_mut()[(0, 0)] = Cell::new("x");
})
.unwrap();
assert_eq!(completed.count, 0, "first draw returns count 0");
assert_eq!(
completed.area,
Rect::new(0, 0, 3, 2),
"completed area matches terminal size in fullscreen mode"
);
assert_eq!(
completed.buffer,
&Buffer::with_lines(["x ", " "]),
"completed buffer contains the rendered content"
);
assert!(terminal.hidden_cursor);
assert!(!terminal.backend().cursor_visible());
assert_eq!(
terminal.frame_count, 1,
"successful draw increments frame_count"
);
}
/// `draw` applies the cursor requested by `Frame::set_cursor_position`.
///
/// The cursor is updated after rendering has been flushed, so it appears on top of the drawn
/// UI.
#[test]
fn draw_shows_and_positions_cursor_when_frame_cursor_is_set() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.hide_cursor().unwrap();
terminal
.draw(|frame| {
// The cursor is applied after the frame is flushed.
frame.set_cursor_position(Position { x: 2, y: 1 });
frame.buffer_mut()[(1, 0)] = Cell::new("y");
})
.unwrap();
assert!(!terminal.hidden_cursor);
assert!(terminal.backend().cursor_visible());
assert_eq!(
terminal.backend().cursor_position(),
Position { x: 2, y: 1 },
"backend cursor is positioned after flushing"
);
assert_eq!(
terminal.last_known_cursor_pos,
Position { x: 2, y: 1 },
"terminal cursor tracking matches the final cursor position"
);
}
/// When the render callback returns an error, `try_draw` does not update the terminal.
///
/// This is a characterization of the "no partial updates" behavior: backend contents and
/// cursor state are unchanged and `frame_count` does not advance.
#[test]
fn try_draw_propagates_render_errors_without_updating_backend() {
let backend = FallibleTestBackend::new(TestBackend::with_lines(["aaa", "bbb"]));
let mut terminal = Terminal::new(backend).unwrap();
terminal.show_cursor().unwrap();
let was_hidden = terminal.hidden_cursor;
let cursor_visible = terminal.backend().inner.cursor_visible();
let cursor_position = terminal.backend().inner.cursor_position();
let result = terminal.try_draw(|_frame| Err::<(), _>(TestError("render failed")));
assert_eq!(
result.unwrap_err(),
TestError("render failed"),
"try_draw returns the render callback error"
);
assert_eq!(terminal.frame_count, 0, "frame_count is unchanged on error");
assert_eq!(
terminal.backend().inner.buffer(),
&Buffer::with_lines(["aaa", "bbb"]),
"backend buffer is unchanged on error"
);
assert_eq!(
terminal.hidden_cursor, was_hidden,
"terminal cursor state is unchanged on error"
);
assert_eq!(
terminal.backend().inner.cursor_visible(),
cursor_visible,
"backend cursor visibility is unchanged on error"
);
assert_eq!(
terminal.backend().inner.cursor_position(),
cursor_position,
"backend cursor position is unchanged on error"
);
}
/// `draw` autoresizes fullscreen terminals and clears before rendering.
///
/// This simulates the backend resizing between draw calls; `draw` runs `autoresize()` first
/// (which calls `resize()` and clears) so the frame renders into a fresh, correctly-sized
/// region.
#[test]
fn draw_clears_on_fullscreen_resize_before_rendering() {
let backend = TestBackend::with_lines(["xxx", "yyy"]);
let mut terminal = Terminal::new(backend).unwrap();
terminal.backend_mut().resize(4, 3);
terminal
.draw(|frame| {
// Render a marker to show we rendered after the clear.
frame.buffer_mut()[(0, 0)] = Cell::new("x");
})
.unwrap();
assert_eq!(
terminal.viewport_area,
Rect::new(0, 0, 4, 3),
"viewport area tracks the resized terminal size"
);
assert_eq!(
terminal.last_known_area,
Rect::new(0, 0, 4, 3),
"last_known_area tracks the resized terminal size"
);
terminal
.backend()
.assert_buffer_lines(["x ", " ", " "]);
}
/// In fixed viewports, `Frame::area` is an absolute terminal rectangle.
///
/// This asserts that rendering at `frame.area().x/y` updates the backend at that absolute
/// position.
#[test]
fn draw_uses_fixed_viewport_coordinates() {
let backend = TestBackend::new(5, 3);
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Fixed(Rect::new(2, 1, 2, 1)),
},
)
.unwrap();
terminal
.draw(|frame| {
assert_eq!(
frame.area(),
Rect::new(2, 1, 2, 1),
"frame area matches the configured fixed viewport"
);
let area = frame.area();
frame.buffer_mut()[(area.x, area.y)] = Cell::new("z");
})
.unwrap();
terminal
.backend()
.assert_buffer_lines([" ", " z ", " "]);
}
/// Inline viewports render into a sub-rectangle, but `CompletedFrame::area` reports terminal
/// size.
///
/// This asserts that the `CompletedFrame` returned from `draw` reports the full terminal
/// size while its buffer is sized to the inline viewport, and that rendering uses the inline
/// viewport's absolute origin.
#[test]
fn draw_inline_completed_frame_reports_terminal_size() {
let mut inner = TestBackend::new(6, 5);
inner.set_cursor_position((0, 2)).unwrap();
let mut terminal = Terminal::with_options(
inner,
TerminalOptions {
viewport: Viewport::Inline(3),
},
)
.unwrap();
let viewport_area = terminal.viewport_area;
{
// `CompletedFrame` borrows the terminal, so backend assertions happen after it drops.
let completed = terminal
.draw(|frame| {
assert_eq!(
frame.area(),
viewport_area,
"inline frame area matches the computed viewport"
);
frame.buffer_mut()[(viewport_area.x, viewport_area.y)] = Cell::new("i");
})
.unwrap();
assert_eq!(
completed.area,
Rect::new(0, 0, 6, 5),
"completed area reports the full terminal size"
);
assert_eq!(
completed.buffer.area, viewport_area,
"completed buffer is sized to the inline viewport"
);
}
assert_eq!(
terminal.backend().buffer()[(viewport_area.x, viewport_area.y)].symbol(),
"i"
);
}
/// Inline viewports are autoresized during `draw`.
///
/// This asserts that when the backend reports a different terminal size, `draw` recomputes the
/// inline viewport rectangle and renders into the new viewport area.
#[test]
fn draw_inline_autoresize_recomputes_viewport_on_grow() {
let mut backend = TestBackend::new(6, 5);
backend
.set_cursor_position(Position { x: 0, y: 2 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(3),
},
)
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
frame.set_cursor_position(Position {
x: area.x,
y: area.y.saturating_add(1),
});
frame.buffer_mut()[(area.x, area.y)] = Cell::new("a");
})
.unwrap();
terminal.backend_mut().resize(8, 7);
let new_area = Rect::new(0, 0, 8, 7);
let previous_viewport = terminal.viewport_area;
terminal
.draw(|frame| {
let area = frame.area();
frame.buffer_mut()[(area.x, area.y)] = Cell::new("g");
})
.unwrap();
assert_eq!(
terminal.last_known_area, new_area,
"inline last_known_area tracks the resized terminal size"
);
assert_eq!(
terminal.viewport_area.width, 8,
"inline viewport width tracks the resized terminal width"
);
assert_eq!(
terminal.viewport_area.height, 3,
"inline viewport height is capped by the configured inline height"
);
assert_eq!(
terminal.viewport_area.y, previous_viewport.y,
"inline viewport stays anchored relative to the cursor across a grow"
);
assert_eq!(
terminal.backend().buffer()[(terminal.viewport_area.x, terminal.viewport_area.y)]
.symbol(),
"g",
"render output lands at the recomputed viewport origin"
);
}
/// Inline viewports are autoresized during `draw`.
///
/// This asserts that shrinking the backend terminal size causes `draw` to recompute the inline
/// viewport origin so it stays visible, and that rendering uses the new viewport origin.
#[test]
fn draw_inline_autoresize_recomputes_viewport_on_shrink() {
let mut backend = TestBackend::new(6, 6);
backend
.set_cursor_position(Position { x: 0, y: 4 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
terminal
.draw(|frame| {
let area = frame.area();
frame.set_cursor_position(Position {
x: area.x,
y: area.y.saturating_add(2),
});
frame.buffer_mut()[(area.x, area.y)] = Cell::new("a");
})
.unwrap();
terminal.backend_mut().resize(6, 5);
let new_area = Rect::new(0, 0, 6, 5);
terminal
.draw(|frame| {
let area = frame.area();
frame.buffer_mut()[(area.x, area.y)] = Cell::new("s");
})
.unwrap();
assert_eq!(
terminal.last_known_area, new_area,
"inline last_known_area tracks the resized terminal size"
);
assert_eq!(
terminal.viewport_area,
Rect::new(0, 1, 6, 4),
"inline viewport is recomputed to stay visible after a shrink"
);
assert_eq!(
terminal.backend().buffer()[(terminal.viewport_area.x, terminal.viewport_area.y)]
.symbol(),
"s",
"render output lands at the recomputed viewport origin"
);
}
/// `CompletedFrame` is only valid until the next draw call.
///
/// This asserts that each `draw` returns the buffer for the frame that was just rendered
/// and that the count increments after each successful draw.
#[test]
fn draw_returns_completed_frame_for_current_render_pass() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
{
// `CompletedFrame` borrows the terminal, and is only valid until the next draw call.
let first = terminal
.draw(|frame| {
frame.buffer_mut()[(0, 0)] = Cell::new("a");
})
.unwrap();
assert_eq!(first.count, 0, "first CompletedFrame has count 0");
assert_eq!(
first.buffer,
&Buffer::with_lines(["a ", " "]),
"first frame's buffer contains the first render output"
);
}
let second = terminal
.draw(|frame| {
frame.buffer_mut()[(0, 0)] = Cell::new("b");
})
.unwrap();
assert_eq!(second.count, 1, "second CompletedFrame has count 1");
assert_eq!(
second.buffer,
&Buffer::with_lines(["b ", " "]),
"second frame's buffer contains the second render output"
);
}
}

View File

@@ -0,0 +1,255 @@
use crate::backend::Backend;
use crate::layout::Rect;
use crate::terminal::inline::compute_inline_size;
use crate::terminal::{Terminal, Viewport};
impl<B: Backend> Terminal<B> {
/// Updates the Terminal so that internal buffers match the requested area.
///
/// This updates the buffer size used for rendering and triggers a full clear so the next
/// [`Terminal::draw`] paints into a consistent area.
///
/// When the viewport is [`Viewport::Inline`], the `area` argument is treated as the new
/// terminal size and the viewport origin is recomputed relative to the current cursor position.
/// Ratatui attempts to keep the cursor at the same relative row within the viewport across
/// resizes.
///
/// See also: [`Terminal::autoresize`] (automatic resizing during [`Terminal::draw`]).
pub fn resize(&mut self, area: Rect) -> Result<(), B::Error> {
let next_area = match self.viewport {
Viewport::Inline(height) => {
let offset_in_previous_viewport = self
.last_known_cursor_pos
.y
.saturating_sub(self.viewport_area.top());
compute_inline_size(
&mut self.backend,
height,
area.as_size(),
offset_in_previous_viewport,
)?
.0
}
Viewport::Fixed(_) | Viewport::Fullscreen => area,
};
self.set_viewport_area(next_area);
self.clear()?;
self.last_known_area = area;
Ok(())
}
/// Queries the backend for size and resizes if it doesn't match the previous size.
///
/// This is called automatically during [`Terminal::draw`] for fullscreen and inline viewports.
/// Fixed viewports are not automatically resized.
///
/// If the size changed, this calls [`Terminal::resize`] (which clears the screen).
pub fn autoresize(&mut self) -> Result<(), B::Error> {
// fixed viewports do not get autoresized
if matches!(self.viewport, Viewport::Fullscreen | Viewport::Inline(_)) {
let area = self.size()?.into();
if area != self.last_known_area {
self.resize(area)?;
}
}
Ok(())
}
/// Resize internal buffers and update the current viewport area.
///
/// This is an internal helper used by [`Terminal::with_options`] and [`Terminal::resize`].
pub(crate) fn set_viewport_area(&mut self, area: Rect) {
self.buffers[self.current].resize(area);
self.buffers[1 - self.current].resize(area);
self.viewport_area = area;
}
}
#[cfg(test)]
mod tests {
use crate::backend::{Backend, TestBackend};
use crate::buffer::Buffer;
use crate::layout::{Position, Rect};
use crate::terminal::{Terminal, TerminalOptions, Viewport};
#[test]
fn resize_fullscreen_updates_viewport_and_buffer_areas() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
terminal.backend_mut().resize(4, 3);
let new_area = Rect::new(0, 0, 4, 3);
terminal.resize(new_area).unwrap();
assert_eq!(terminal.viewport_area, new_area);
assert_eq!(terminal.last_known_area, new_area);
assert_eq!(terminal.buffers[terminal.current].area, new_area);
assert_eq!(terminal.buffers[1 - terminal.current].area, new_area);
}
#[test]
fn resize_fullscreen_triggers_clear_and_resets_back_buffer() {
// This test is specifically about the side effects of `resize`:
// - it calls `clear` to force a full redraw
// - it resets the "previous" buffer
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
// Put visible content on the backend so we can tell whether a clear happened.
{
let frame = terminal.get_frame();
frame.buffer[(0, 0)].set_symbol("x");
}
terminal.flush().unwrap();
terminal.backend().assert_buffer_lines(["x ", " "]);
terminal.backend_mut().resize(4, 3);
let new_area = Rect::new(0, 0, 4, 3);
terminal.resize(new_area).unwrap();
terminal
.backend()
.assert_buffer_lines([" ", " ", " "]);
assert_eq!(
terminal.buffers[1 - terminal.current],
Buffer::empty(new_area)
);
}
#[test]
fn autoresize_fullscreen_uses_backend_size_when_changed() {
let backend = TestBackend::new(3, 2);
let mut terminal = Terminal::new(backend).unwrap();
{
let frame = terminal.get_frame();
frame.buffer[(0, 0)].set_symbol("x");
}
terminal.flush().unwrap();
terminal.backend_mut().resize(4, 3);
terminal.autoresize().unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 0, 4, 3));
assert_eq!(terminal.last_known_area, Rect::new(0, 0, 4, 3));
terminal
.backend()
.assert_buffer_lines([" ", " ", " "]);
}
#[test]
fn autoresize_fixed_does_not_change_viewport() {
let backend = TestBackend::with_lines(["xxx", "yyy"]);
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Fixed(Rect::new(1, 0, 2, 2)),
},
)
.unwrap();
terminal.autoresize().unwrap();
assert_eq!(terminal.viewport_area, Rect::new(1, 0, 2, 2));
assert_eq!(terminal.last_known_area, Rect::new(1, 0, 2, 2));
terminal.backend().assert_buffer_lines(["xxx", "yyy"]);
}
#[test]
fn resize_fixed_changes_viewport_area_and_buffer_sizes() {
let backend = TestBackend::new(5, 3);
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Fixed(Rect::new(1, 1, 2, 1)),
},
)
.unwrap();
terminal.resize(Rect::new(0, 0, 3, 2)).unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 0, 3, 2));
assert_eq!(terminal.last_known_area, Rect::new(0, 0, 3, 2));
assert_eq!(
terminal.buffers[terminal.current].area,
terminal.viewport_area
);
assert_eq!(
terminal.buffers[1 - terminal.current].area,
terminal.viewport_area
);
}
#[test]
fn resize_inline_recomputes_origin_using_previous_cursor_offset() {
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 4 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(4),
},
)
.unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 4, 10, 4));
// Characterization test:
// This test simulates a terminal resize (increasing the terminal height) while an inline
// viewport is active. The key behavior being exercised is that the viewport remains
// anchored to the backend cursor row and preserves the cursor's relative offset within the
// previous viewport.
//
// For inline viewports, `Terminal::resize(area)` interprets `area` as the *new terminal
// size*, then recomputes the viewport origin based on:
// - the backend cursor position at the time of the call
// - the cursor offset within the *previous* viewport (`last_known_cursor_pos -
// viewport_top`)
//
// This means `resize(Rect { .. })` can update `viewport_area.y` even when the passed-in
// `area.y` is 0, because `viewport_area` is anchored to the cursor row, not the terminal
// origin.
terminal.last_known_cursor_pos = Position { x: 0, y: 5 };
terminal
.backend_mut()
.set_cursor_position(Position { x: 0, y: 6 })
.unwrap();
terminal.backend_mut().resize(10, 12);
let new_terminal_area = Rect::new(0, 0, 10, 12);
terminal.resize(new_terminal_area).unwrap();
// Previous viewport top was y=4, and last_known_cursor_pos was y=5, so the cursor offset
// within the viewport is 1 row. At the time of resize the backend cursor is at y=6, so the
// new viewport top becomes 6 - 1 = 5.
assert_eq!(terminal.viewport_area, Rect::new(0, 5, 10, 4));
assert_eq!(terminal.last_known_area, new_terminal_area);
}
#[test]
fn resize_inline_clamps_height_to_terminal_height() {
// Characterization test:
// This test simulates a terminal resize that *reduces* the terminal height. Inline
// viewports clamp their height to the new terminal size so the viewport remains fully
// visible.
let mut backend = TestBackend::new(10, 10);
backend
.set_cursor_position(Position { x: 0, y: 0 })
.unwrap();
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::Inline(10),
},
)
.unwrap();
terminal.backend_mut().resize(10, 3);
terminal.resize(Rect::new(0, 0, 10, 3)).unwrap();
assert_eq!(terminal.viewport_area, Rect::new(0, 0, 10, 3));
}
}

View File

@@ -1,926 +0,0 @@
use crate::backend::{Backend, ClearType};
use crate::buffer::{Buffer, Cell};
use crate::layout::{Position, Rect, Size};
use crate::terminal::{CompletedFrame, Frame, TerminalOptions, Viewport};
/// An interface to interact and draw [`Frame`]s on the user's terminal.
///
/// This is the main entry point for Ratatui. It is responsible for drawing and maintaining the
/// state of the buffers, cursor and viewport.
///
/// The [`Terminal`] is generic over a [`Backend`] implementation which is used to interface with
/// the underlying terminal library. The [`Backend`] trait is implemented for three popular Rust
/// terminal libraries: [Crossterm], [Termion] and [Termwiz]. See the [`backend`] module for more
/// information.
///
/// The `Terminal` struct maintains two buffers: the current and the previous.
/// When the widgets are drawn, the changes are accumulated in the current buffer.
/// At the end of each draw pass, the two buffers are compared, and only the changes
/// between these buffers are written to the terminal, avoiding any redundant operations.
/// After flushing these changes, the buffers are swapped to prepare for the next draw cycle.
///
/// The terminal also has a viewport which is the area of the terminal that is currently visible to
/// the user. It can be either fullscreen, inline or fixed. See [`Viewport`] for more information.
///
/// Applications should detect terminal resizes and call [`Terminal::draw`] to redraw the
/// application with the new size. This will automatically resize the internal buffers to match the
/// new size for inline and fullscreen viewports. Fixed viewports are not resized automatically.
///
/// # Initialization
///
/// For most applications, consider using the convenience functions `ratatui::run()`,
/// `ratatui::init()`, and `ratatui::restore()` (available since version 0.28.1) along with the
/// `DefaultTerminal` type alias instead of constructing `Terminal` instances manually. These
/// functions handle the common setup and teardown tasks automatically. Manual construction
/// using `Terminal::new()` or `Terminal::with_options()` is still supported for applications
/// that need fine-grained control over initialization.
///
/// # Examples
///
/// ## Using convenience functions (recommended for most applications)
///
/// ```rust,ignore
/// // Modern approach using convenience functions
/// ratatui::run(|terminal| {
/// terminal.draw(|frame| {
/// let area = frame.area();
/// frame.render_widget(Paragraph::new("Hello World!"), area);
/// })?;
/// Ok(())
/// })?;
/// ```
///
/// ## Manual construction (for fine-grained control)
///
/// ```rust,ignore
/// use std::io::stdout;
///
/// use ratatui::{backend::CrosstermBackend, widgets::Paragraph, Terminal};
///
/// let backend = CrosstermBackend::new(stdout());
/// let mut terminal = Terminal::new(backend)?;
/// terminal.draw(|frame| {
/// let area = frame.area();
/// frame.render_widget(Paragraph::new("Hello World!"), area);
/// })?;
/// # std::io::Result::Ok(())
/// ```
///
/// [Crossterm]: https://crates.io/crates/crossterm
/// [Termion]: https://crates.io/crates/termion
/// [Termwiz]: https://crates.io/crates/termwiz
/// [`backend`]: crate::backend
/// [`Backend`]: crate::backend::Backend
/// [`Buffer`]: crate::buffer::Buffer
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Terminal<B>
where
B: Backend,
{
/// The backend used to interface with the terminal
backend: B,
/// Holds the results of the current and previous draw calls. The two are compared at the end
/// of each draw pass to output the necessary updates to the terminal
buffers: [Buffer; 2],
/// Index of the current buffer in the previous array
current: usize,
/// Whether the cursor is currently hidden
hidden_cursor: bool,
/// Viewport
viewport: Viewport,
/// Area of the viewport
viewport_area: Rect,
/// Last known area of the terminal. Used to detect if the internal buffers have to be resized.
last_known_area: Rect,
/// Last known position of the cursor. Used to find the new area when the viewport is inlined
/// and the terminal resized.
last_known_cursor_pos: Position,
/// Number of frames rendered up until current time.
frame_count: usize,
}
/// Options to pass to [`Terminal::with_options`]
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Options {
/// Viewport used to draw to the terminal
pub viewport: Viewport,
}
impl<B> Drop for Terminal<B>
where
B: Backend,
{
fn drop(&mut self) {
// Attempt to restore the cursor state
if self.hidden_cursor {
#[allow(unused_variables)]
if let Err(err) = self.show_cursor() {
#[cfg(feature = "std")]
std::eprintln!("Failed to show the cursor: {err}");
}
}
}
}
impl<B> Terminal<B>
where
B: Backend,
{
/// Creates a new [`Terminal`] with the given [`Backend`] with a full screen viewport.
///
/// Note that unlike `ratatui::init`, this does not install a panic hook, so it is recommended
/// to do that manually when using this function, otherwise any panic messages will be printed
/// to the alternate screen and the terminal may be left in an unusable state.
///
/// See [how to set up panic hooks](https://ratatui.rs/recipes/apps/panic-hooks/) and
/// [`better-panic` example](https://ratatui.rs/recipes/apps/better-panic/) for more
/// information.
///
/// # Example
///
/// ```rust,ignore
/// use std::io::stdout;
///
/// use ratatui::{backend::CrosstermBackend, Terminal};
///
/// let backend = CrosstermBackend::new(stdout());
/// let terminal = Terminal::new(backend)?;
///
/// // Optionally set up a panic hook to restore the terminal on panic.
/// let old_hook = std::panic::take_hook();
/// std::panic::set_hook(Box::new(move |info| {
/// ratatui::restore();
/// old_hook(info);
/// }));
/// # std::io::Result::Ok(())
/// ```
pub fn new(backend: B) -> Result<Self, B::Error> {
Self::with_options(
backend,
TerminalOptions {
viewport: Viewport::Fullscreen,
},
)
}
/// Creates a new [`Terminal`] with the given [`Backend`] and [`TerminalOptions`].
///
/// # Example
///
/// ```rust,ignore
/// use std::io::stdout;
///
/// use ratatui::{backend::CrosstermBackend, layout::Rect, Terminal, TerminalOptions, Viewport};
///
/// let backend = CrosstermBackend::new(stdout());
/// let viewport = Viewport::Fixed(Rect::new(0, 0, 10, 10));
/// let terminal = Terminal::with_options(backend, TerminalOptions { viewport })?;
/// # std::io::Result::Ok(())
/// ```
pub fn with_options(mut backend: B, options: TerminalOptions) -> Result<Self, B::Error> {
let area = match options.viewport {
Viewport::Fullscreen | Viewport::Inline(_) => backend.size()?.into(),
Viewport::Fixed(area) => area,
};
let (viewport_area, cursor_pos) = match options.viewport {
Viewport::Fullscreen => (area, Position::ORIGIN),
Viewport::Inline(height) => {
compute_inline_size(&mut backend, height, area.as_size(), 0)?
}
Viewport::Fixed(area) => (area, area.as_position()),
};
Ok(Self {
backend,
buffers: [Buffer::empty(viewport_area), Buffer::empty(viewport_area)],
current: 0,
hidden_cursor: false,
viewport: options.viewport,
viewport_area,
last_known_area: area,
last_known_cursor_pos: cursor_pos,
frame_count: 0,
})
}
/// Get a Frame object which provides a consistent view into the terminal state for rendering.
///
/// # Note
///
/// This exists to support more advanced use cases. Most cases should be fine using
/// [`Terminal::draw`].
///
/// [`Terminal::get_frame`] should be used when you need direct access to the frame buffer
/// outside of draw closure, for example:
///
/// - Unit testing widgets
/// - Buffer state inspection
/// - Cursor manipulation
/// - Multiple rendering passes/Buffer Manipulation
/// - Custom frame lifecycle management
/// - Buffer exporting
///
/// # Example
///
/// Getting the buffer and asserting on some cells after rendering a widget.
///
/// ```rust,ignore
/// use ratatui::{backend::TestBackend, Terminal};
/// use ratatui::widgets::Paragraph;
/// let backend = TestBackend::new(30, 5);
/// let mut terminal = Terminal::new(backend).unwrap();
/// {
/// let mut frame = terminal.get_frame();
/// frame.render_widget(Paragraph::new("Hello"), frame.area());
/// }
/// // When not using `draw`, present the buffer manually:
/// terminal.flush().unwrap();
/// terminal.swap_buffers();
/// terminal.backend_mut().flush().unwrap();
/// ```
pub const fn get_frame(&mut self) -> Frame<'_> {
let count = self.frame_count;
Frame {
cursor_position: None,
viewport_area: self.viewport_area,
buffer: self.current_buffer_mut(),
count,
}
}
/// Gets the current buffer as a mutable reference.
pub const fn current_buffer_mut(&mut self) -> &mut Buffer {
&mut self.buffers[self.current]
}
/// Gets the backend
pub const fn backend(&self) -> &B {
&self.backend
}
/// Gets the backend as a mutable reference
pub const fn backend_mut(&mut self) -> &mut B {
&mut self.backend
}
/// Obtains a difference between the previous and the current buffer and passes it to the
/// current backend for drawing.
pub fn flush(&mut self) -> Result<(), B::Error> {
let previous_buffer = &self.buffers[1 - self.current];
let current_buffer = &self.buffers[self.current];
let updates = previous_buffer.diff(current_buffer);
if let Some((col, row, _)) = updates.last() {
self.last_known_cursor_pos = Position { x: *col, y: *row };
}
self.backend.draw(updates.into_iter())
}
/// Updates the Terminal so that internal buffers match the requested area.
///
/// Requested area will be saved to remain consistent when rendering. This leads to a full clear
/// of the screen.
pub fn resize(&mut self, area: Rect) -> Result<(), B::Error> {
let next_area = match self.viewport {
Viewport::Inline(height) => {
let offset_in_previous_viewport = self
.last_known_cursor_pos
.y
.saturating_sub(self.viewport_area.top());
compute_inline_size(
&mut self.backend,
height,
area.as_size(),
offset_in_previous_viewport,
)?
.0
}
Viewport::Fixed(_) | Viewport::Fullscreen => area,
};
self.set_viewport_area(next_area);
self.clear()?;
self.last_known_area = area;
Ok(())
}
fn set_viewport_area(&mut self, area: Rect) {
self.buffers[self.current].resize(area);
self.buffers[1 - self.current].resize(area);
self.viewport_area = area;
}
/// Queries the backend for size and resizes if it doesn't match the previous size.
pub fn autoresize(&mut self) -> Result<(), B::Error> {
// fixed viewports do not get autoresized
if matches!(self.viewport, Viewport::Fullscreen | Viewport::Inline(_)) {
let area = self.size()?.into();
if area != self.last_known_area {
self.resize(area)?;
}
}
Ok(())
}
/// Draws a single frame to the terminal.
///
/// Returns a [`CompletedFrame`] if successful, otherwise a [`std::io::Error`].
///
/// If the render callback passed to this method can fail, use [`try_draw`] instead.
///
/// Applications should call `draw` or [`try_draw`] in a loop to continuously render the
/// terminal. These methods are the main entry points for drawing to the terminal.
///
/// [`try_draw`]: Terminal::try_draw
///
/// This method will:
///
/// - autoresize the terminal if necessary
/// - call the render callback, passing it a [`Frame`] reference to render to
/// - flush the current internal state by copying the current buffer to the backend
/// - move the cursor to the last known position if it was set during the rendering closure
/// - return a [`CompletedFrame`] with the current buffer and the area of the terminal
///
/// The [`CompletedFrame`] returned by this method can be useful for debugging or testing
/// purposes, but it is often not used in regular applications.
///
/// The render callback should fully render the entire frame when called, including areas that
/// are unchanged from the previous frame. This is because each frame is compared to the
/// previous frame to determine what has changed, and only the changes are written to the
/// terminal. If the render callback does not fully render the frame, the terminal will not be
/// in a consistent state.
///
/// # Examples
///
/// ```rust,ignore
/// # let backend = ratatui::backend::TestBackend::new(10, 10);
/// # let mut terminal = ratatui::Terminal::new(backend)?;
/// use ratatui::{layout::Position, widgets::Paragraph};
///
/// // with a closure
/// terminal.draw(|frame| {
/// let area = frame.area();
/// frame.render_widget(Paragraph::new("Hello World!"), area);
/// frame.set_cursor_position(Position { x: 0, y: 0 });
/// })?;
///
/// // or with a function
/// terminal.draw(render)?;
///
/// fn render(frame: &mut ratatui::Frame) {
/// frame.render_widget(Paragraph::new("Hello World!"), frame.area());
/// }
/// # std::io::Result::Ok(())
/// ```
pub fn draw<F>(&mut self, render_callback: F) -> Result<CompletedFrame<'_>, B::Error>
where
F: FnOnce(&mut Frame),
{
self.try_draw(|frame| {
render_callback(frame);
Ok::<(), B::Error>(())
})
}
/// Tries to draw a single frame to the terminal.
///
/// Returns [`Result::Ok`] containing a [`CompletedFrame`] if successful, otherwise
/// [`Result::Err`] containing the [`std::io::Error`] that caused the failure.
///
/// This is the equivalent of [`Terminal::draw`] but the render callback is a function or
/// closure that returns a `Result` instead of nothing.
///
/// Applications should call `try_draw` or [`draw`] in a loop to continuously render the
/// terminal. These methods are the main entry points for drawing to the terminal.
///
/// [`draw`]: Terminal::draw
///
/// This method will:
///
/// - autoresize the terminal if necessary
/// - call the render callback, passing it a [`Frame`] reference to render to
/// - flush the current internal state by copying the current buffer to the backend
/// - move the cursor to the last known position if it was set during the rendering closure
/// - return a [`CompletedFrame`] with the current buffer and the area of the terminal
///
/// The render callback passed to `try_draw` can return any [`Result`] with an error type that
/// can be converted into an [`std::io::Error`] using the [`Into`] trait. This makes it possible
/// to use the `?` operator to propagate errors that occur during rendering. If the render
/// callback returns an error, the error will be returned from `try_draw` as an
/// [`std::io::Error`] and the terminal will not be updated.
///
/// The [`CompletedFrame`] returned by this method can be useful for debugging or testing
/// purposes, but it is often not used in regular applications.
///
/// The render callback should fully render the entire frame when called, including areas that
/// are unchanged from the previous frame. This is because each frame is compared to the
/// previous frame to determine what has changed, and only the changes are written to the
/// terminal. If the render function does not fully render the frame, the terminal will not be
/// in a consistent state.
///
/// # Examples
///
/// ```ignore
/// # use ratatui::layout::Position;;
/// # let backend = ratatui::backend::TestBackend::new(10, 10);
/// # let mut terminal = ratatui::Terminal::new(backend)?;
/// use std::io;
///
/// use ratatui::widgets::Paragraph;
///
/// // with a closure
/// terminal.try_draw(|frame| {
/// let value: u8 = "not a number".parse().map_err(io::Error::other)?;
/// let area = frame.area();
/// frame.render_widget(Paragraph::new("Hello World!"), area);
/// frame.set_cursor_position(Position { x: 0, y: 0 });
/// io::Result::Ok(())
/// })?;
///
/// // or with a function
/// terminal.try_draw(render)?;
///
/// fn render(frame: &mut ratatui::Frame) -> io::Result<()> {
/// let value: u8 = "not a number".parse().map_err(io::Error::other)?;
/// frame.render_widget(Paragraph::new("Hello World!"), frame.area());
/// Ok(())
/// }
/// # io::Result::Ok(())
/// ```
pub fn try_draw<F, E>(&mut self, render_callback: F) -> Result<CompletedFrame<'_>, B::Error>
where
F: FnOnce(&mut Frame) -> Result<(), E>,
E: Into<B::Error>,
{
// Autoresize - otherwise we get glitches if shrinking or potential desync between widgets
// and the terminal (if growing), which may OOB.
self.autoresize()?;
let mut frame = self.get_frame();
render_callback(&mut frame).map_err(Into::into)?;
// We can't change the cursor position right away because we have to flush the frame to
// stdout first. But we also can't keep the frame around, since it holds a &mut to
// Buffer. Thus, we're taking the important data out of the Frame and dropping it.
let cursor_position = frame.cursor_position;
// Draw to stdout
self.flush()?;
match cursor_position {
None => self.hide_cursor()?,
Some(position) => {
self.show_cursor()?;
self.set_cursor_position(position)?;
}
}
self.swap_buffers();
// Flush
self.backend.flush()?;
let completed_frame = CompletedFrame {
buffer: &self.buffers[1 - self.current],
area: self.last_known_area,
count: self.frame_count,
};
// increment frame count before returning from draw
self.frame_count = self.frame_count.wrapping_add(1);
Ok(completed_frame)
}
/// Hides the cursor.
pub fn hide_cursor(&mut self) -> Result<(), B::Error> {
self.backend.hide_cursor()?;
self.hidden_cursor = true;
Ok(())
}
/// Shows the cursor.
pub fn show_cursor(&mut self) -> Result<(), B::Error> {
self.backend.show_cursor()?;
self.hidden_cursor = false;
Ok(())
}
/// Gets the current cursor position.
///
/// This is the position of the cursor after the last draw call and is returned as a tuple of
/// `(x, y)` coordinates.
#[deprecated = "use `get_cursor_position()` instead which returns `Result<Position>`"]
pub fn get_cursor(&mut self) -> Result<(u16, u16), B::Error> {
let Position { x, y } = self.get_cursor_position()?;
Ok((x, y))
}
/// Sets the cursor position.
#[deprecated = "use `set_cursor_position((x, y))` instead which takes `impl Into<Position>`"]
pub fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), B::Error> {
self.set_cursor_position(Position { x, y })
}
/// Gets the current cursor position.
///
/// This is the position of the cursor after the last draw call.
pub fn get_cursor_position(&mut self) -> Result<Position, B::Error> {
self.backend.get_cursor_position()
}
/// Sets the cursor position.
pub fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> Result<(), B::Error> {
let position = position.into();
self.backend.set_cursor_position(position)?;
self.last_known_cursor_pos = position;
Ok(())
}
/// Clear the terminal and force a full redraw on the next draw call.
pub fn clear(&mut self) -> Result<(), B::Error> {
match self.viewport {
Viewport::Fullscreen => self.backend.clear_region(ClearType::All)?,
Viewport::Inline(_) => {
self.backend
.set_cursor_position(self.viewport_area.as_position())?;
self.backend.clear_region(ClearType::AfterCursor)?;
}
Viewport::Fixed(_) => {
let area = self.viewport_area;
for y in area.top()..area.bottom() {
self.backend.set_cursor_position(Position { x: 0, y })?;
self.backend.clear_region(ClearType::AfterCursor)?;
}
}
}
// Reset the back buffer to make sure the next update will redraw everything.
self.buffers[1 - self.current].reset();
Ok(())
}
/// Clears the inactive buffer and swaps it with the current buffer
pub fn swap_buffers(&mut self) {
self.buffers[1 - self.current].reset();
self.current = 1 - self.current;
}
/// Queries the real size of the backend.
pub fn size(&self) -> Result<Size, B::Error> {
self.backend.size()
}
/// Insert some content before the current inline viewport. This has no effect when the
/// viewport is not inline.
///
/// The `draw_fn` closure will be called to draw into a writable `Buffer` that is `height`
/// lines tall. The content of that `Buffer` will then be inserted before the viewport.
///
/// If the viewport isn't yet at the bottom of the screen, inserted lines will push it towards
/// the bottom. Once the viewport is at the bottom of the screen, inserted lines will scroll
/// the area of the screen above the viewport upwards.
///
/// Before:
/// ```ignore
/// +---------------------+
/// | pre-existing line 1 |
/// | pre-existing line 2 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// | |
/// | |
/// +---------------------+
/// ```
///
/// After inserting 2 lines:
/// ```ignore
/// +---------------------+
/// | pre-existing line 1 |
/// | pre-existing line 2 |
/// | inserted line 1 |
/// | inserted line 2 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// +---------------------+
/// ```
///
/// After inserting 2 more lines:
/// ```ignore
/// +---------------------+
/// | pre-existing line 2 |
/// | inserted line 1 |
/// | inserted line 2 |
/// | inserted line 3 |
/// | inserted line 4 |
/// +---------------------+
/// | viewport |
/// +---------------------+
/// ```
///
/// If more lines are inserted than there is space on the screen, then the top lines will go
/// directly into the terminal's scrollback buffer. At the limit, if the viewport takes up the
/// whole screen, all lines will be inserted directly into the scrollback buffer.
///
/// # Examples
///
/// ## Insert a single line before the current viewport
///
/// ```rust,ignore
/// use ratatui::{
/// backend::TestBackend,
/// style::{Color, Style},
/// text::{Line, Span},
/// widgets::{Paragraph, Widget},
/// Terminal,
/// };
/// # let backend = TestBackend::new(10, 10);
/// # let mut terminal = Terminal::new(backend).unwrap();
/// terminal.insert_before(1, |buf| {
/// Paragraph::new(Line::from(vec![
/// Span::raw("This line will be added "),
/// Span::styled("before", Style::default().fg(Color::Blue)),
/// Span::raw(" the current viewport"),
/// ]))
/// .render(buf.area, buf);
/// });
/// ```
pub fn insert_before<F>(&mut self, height: u16, draw_fn: F) -> Result<(), B::Error>
where
F: FnOnce(&mut Buffer),
{
match self.viewport {
#[cfg(feature = "scrolling-regions")]
Viewport::Inline(_) => self.insert_before_scrolling_regions(height, draw_fn),
#[cfg(not(feature = "scrolling-regions"))]
Viewport::Inline(_) => self.insert_before_no_scrolling_regions(height, draw_fn),
_ => Ok(()),
}
}
/// Implement `Self::insert_before` using standard backend capabilities.
#[cfg(not(feature = "scrolling-regions"))]
fn insert_before_no_scrolling_regions(
&mut self,
height: u16,
draw_fn: impl FnOnce(&mut Buffer),
) -> Result<(), B::Error> {
// The approach of this function is to first render all of the lines to insert into a
// temporary buffer, and then to loop drawing chunks from the buffer to the screen. drawing
// this buffer onto the screen.
let area = Rect {
x: 0,
y: 0,
width: self.viewport_area.width,
height,
};
let mut buffer = Buffer::empty(area);
draw_fn(&mut buffer);
let mut buffer = buffer.content.as_slice();
// Use i32 variables so we don't have worry about overflowed u16s when adding, or about
// negative results when subtracting.
let mut drawn_height: i32 = self.viewport_area.top().into();
let mut buffer_height: i32 = height.into();
let viewport_height: i32 = self.viewport_area.height.into();
let screen_height: i32 = self.last_known_area.height.into();
// The algorithm here is to loop, drawing large chunks of text (up to a screen-full at a
// time), until the remainder of the buffer plus the viewport fits on the screen. We choose
// this loop condition because it guarantees that we can write the remainder of the buffer
// with just one call to Self::draw_lines().
while buffer_height + viewport_height > screen_height {
// We will draw as much of the buffer as possible on this iteration in order to make
// forward progress. So we have:
//
// to_draw = min(buffer_height, screen_height)
//
// We may need to scroll the screen up to make room to draw. We choose the minimal
// possible scroll amount so we don't end up with the viewport sitting in the middle of
// the screen when this function is done. The amount to scroll by is:
//
// scroll_up = max(0, drawn_height + to_draw - screen_height)
//
// We want `scroll_up` to be enough so that, after drawing, we have used the whole
// screen (drawn_height - scroll_up + to_draw = screen_height). However, there might
// already be enough room on the screen to draw without scrolling (drawn_height +
// to_draw <= screen_height). In this case, we just don't scroll at all.
let to_draw = buffer_height.min(screen_height);
let scroll_up = 0.max(drawn_height + to_draw - screen_height);
self.scroll_up(scroll_up as u16)?;
buffer = self.draw_lines((drawn_height - scroll_up) as u16, to_draw as u16, buffer)?;
drawn_height += to_draw - scroll_up;
buffer_height -= to_draw;
}
// There is now enough room on the screen for the remaining buffer plus the viewport,
// though we may still need to scroll up some of the existing text first. It's possible
// that by this point we've drained the buffer, but we may still need to scroll up to make
// room for the viewport.
//
// We want to scroll up the exact amount that will leave us completely filling the screen.
// However, it's possible that the viewport didn't start on the bottom of the screen and
// the added lines weren't enough to push it all the way to the bottom. We deal with this
// case by just ensuring that our scroll amount is non-negative.
//
// We want:
// screen_height = drawn_height - scroll_up + buffer_height + viewport_height
// Or, equivalently:
// scroll_up = drawn_height + buffer_height + viewport_height - screen_height
let scroll_up = 0.max(drawn_height + buffer_height + viewport_height - screen_height);
self.scroll_up(scroll_up as u16)?;
self.draw_lines(
(drawn_height - scroll_up) as u16,
buffer_height as u16,
buffer,
)?;
drawn_height += buffer_height - scroll_up;
self.set_viewport_area(Rect {
y: drawn_height as u16,
..self.viewport_area
});
// Clear the viewport off the screen. We didn't clear earlier for two reasons. First, it
// wasn't necessary because the buffer we drew out of isn't sparse, so it overwrote
// whatever was on the screen. Second, there is a weird bug with tmux where a full screen
// clear plus immediate scrolling causes some garbage to go into the scrollback.
self.clear()?;
Ok(())
}
/// Implement `Self::insert_before` using scrolling regions.
///
/// If a terminal supports scrolling regions, it means that we can define a subset of rows of
/// the screen, and then tell the terminal to scroll up or down just within that region. The
/// rows outside of the region are not affected.
///
/// This function utilizes this feature to avoid having to redraw the viewport. This is done
/// either by splitting the screen at the top of the viewport, and then creating a gap by
/// either scrolling the viewport down, or scrolling the area above it up. The lines to insert
/// are then drawn into the gap created.
#[cfg(feature = "scrolling-regions")]
fn insert_before_scrolling_regions(
&mut self,
mut height: u16,
draw_fn: impl FnOnce(&mut Buffer),
) -> Result<(), B::Error> {
// The approach of this function is to first render all of the lines to insert into a
// temporary buffer, and then to loop drawing chunks from the buffer to the screen. drawing
// this buffer onto the screen.
let area = Rect {
x: 0,
y: 0,
width: self.viewport_area.width,
height,
};
let mut buffer = Buffer::empty(area);
draw_fn(&mut buffer);
let mut buffer = buffer.content.as_slice();
// Handle the special case where the viewport takes up the whole screen.
if self.viewport_area.height == self.last_known_area.height {
// "Borrow" the top line of the viewport. Draw over it, then immediately scroll it into
// scrollback. Do this repeatedly until the whole buffer has been put into scrollback.
let mut first = true;
while !buffer.is_empty() {
buffer = if first {
self.draw_lines(0, 1, buffer)?
} else {
self.draw_lines_over_cleared(0, 1, buffer)?
};
first = false;
self.backend.scroll_region_up(0..1, 1)?;
}
// Redraw the top line of the viewport.
let width = self.viewport_area.width as usize;
let top_line = self.buffers[1 - self.current].content[0..width].to_vec();
self.draw_lines_over_cleared(0, 1, &top_line)?;
return Ok(());
}
// Handle the case where the viewport isn't yet at the bottom of the screen.
{
let viewport_top = self.viewport_area.top();
let viewport_bottom = self.viewport_area.bottom();
let screen_bottom = self.last_known_area.bottom();
if viewport_bottom < screen_bottom {
let to_draw = height.min(screen_bottom - viewport_bottom);
self.backend
.scroll_region_down(viewport_top..viewport_bottom + to_draw, to_draw)?;
buffer = self.draw_lines_over_cleared(viewport_top, to_draw, buffer)?;
self.set_viewport_area(Rect {
y: viewport_top + to_draw,
..self.viewport_area
});
height -= to_draw;
}
}
let viewport_top = self.viewport_area.top();
while height > 0 {
let to_draw = height.min(viewport_top);
self.backend.scroll_region_up(0..viewport_top, to_draw)?;
buffer = self.draw_lines_over_cleared(viewport_top - to_draw, to_draw, buffer)?;
height -= to_draw;
}
Ok(())
}
/// Draw lines at the given vertical offset. The slice of cells must contain enough cells
/// for the requested lines. A slice of the unused cells are returned.
fn draw_lines<'a>(
&mut self,
y_offset: u16,
lines_to_draw: u16,
cells: &'a [Cell],
) -> Result<&'a [Cell], B::Error> {
let width: usize = self.last_known_area.width.into();
let (to_draw, remainder) = cells.split_at(width * lines_to_draw as usize);
if lines_to_draw > 0 {
let iter = to_draw
.iter()
.enumerate()
.map(|(i, c)| ((i % width) as u16, y_offset + (i / width) as u16, c));
self.backend.draw(iter)?;
self.backend.flush()?;
}
Ok(remainder)
}
/// Draw lines at the given vertical offset, assuming that the lines they are replacing on the
/// screen are cleared. The slice of cells must contain enough cells for the requested lines. A
/// slice of the unused cells are returned.
#[cfg(feature = "scrolling-regions")]
fn draw_lines_over_cleared<'a>(
&mut self,
y_offset: u16,
lines_to_draw: u16,
cells: &'a [Cell],
) -> Result<&'a [Cell], B::Error> {
let width: usize = self.last_known_area.width.into();
let (to_draw, remainder) = cells.split_at(width * lines_to_draw as usize);
if lines_to_draw > 0 {
let area = Rect::new(0, y_offset, width as u16, y_offset + lines_to_draw);
let old = Buffer::empty(area);
let new = Buffer {
area,
content: to_draw.to_vec(),
};
self.backend.draw(old.diff(&new).into_iter())?;
self.backend.flush()?;
}
Ok(remainder)
}
/// Scroll the whole screen up by the given number of lines.
#[cfg(not(feature = "scrolling-regions"))]
fn scroll_up(&mut self, lines_to_scroll: u16) -> Result<(), B::Error> {
if lines_to_scroll > 0 {
self.set_cursor_position(Position::new(
0,
self.last_known_area.height.saturating_sub(1),
))?;
self.backend.append_lines(lines_to_scroll)?;
}
Ok(())
}
}
fn compute_inline_size<B: Backend>(
backend: &mut B,
height: u16,
size: Size,
offset_in_previous_viewport: u16,
) -> Result<(Rect, Position), B::Error> {
let pos = backend.get_cursor_position()?;
let mut row = pos.y;
let max_height = size.height.min(height);
let lines_after_cursor = height
.saturating_sub(offset_in_previous_viewport)
.saturating_sub(1);
backend.append_lines(lines_after_cursor)?;
let available_lines = size.height.saturating_sub(row).saturating_sub(1);
let missing_lines = lines_after_cursor.saturating_sub(available_lines);
if missing_lines > 0 {
row = row.saturating_sub(missing_lines);
}
row = row.saturating_sub(offset_in_previous_viewport);
Ok((
Rect {
x: 0,
y: row,
width: size.width,
height: max_height,
},
pos,
))
}

View File

@@ -2,31 +2,67 @@ use core::fmt;
use crate::layout::Rect;
/// Represents the viewport of the terminal. The viewport is the area of the terminal that is
/// currently visible to the user. It can be either fullscreen, inline or fixed.
/// The area of the terminal that Ratatui draws into.
///
/// When the viewport is fullscreen, the whole terminal is used to draw the application.
/// A [`Viewport`] controls where widgets render and what [`Frame::area`] returns.
///
/// When the viewport is inline, it is drawn inline with the rest of the terminal. The height of
/// the viewport is fixed, but the width is the same as the terminal width.
/// For a higher-level overview of viewports in the context of an application (including
/// examples), see [`Terminal`].
///
/// When the viewport is fixed, it is drawn in a fixed area of the terminal. The area is specified
/// by a [`Rect`].
/// Most applications use [`Viewport::Fullscreen`]. Use [`Viewport::Inline`] when you want to embed
/// a UI into a larger CLI flow (for example: print some text, then start an interactive UI below
/// it). Use [`Viewport::Fixed`] when you want Ratatui to render into a specific region of the
/// terminal.
///
/// See [`Terminal::with_options`] for more information.
/// In fullscreen mode, the viewport starts at (0, 0). In inline and fixed mode, the viewport may
/// have a non-zero `x`/`y` origin; prefer using `Frame::area()` as your root layout rectangle.
///
/// See [`Terminal::with_options`] for how to select a viewport, and [`Terminal::resize`] /
/// [`Terminal::autoresize`] for resize behavior.
///
/// [`Frame::area`]: crate::terminal::Frame::area
/// [`Terminal`]: crate::terminal::Terminal
/// [`Terminal::with_options`]: crate::terminal::Terminal::with_options
/// [`Terminal::resize`]: crate::terminal::Terminal::resize
/// [`Terminal::autoresize`]: crate::terminal::Terminal::autoresize
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub enum Viewport {
/// The viewport is fullscreen
/// Draw into the entire terminal.
///
/// This is the default viewport used by [`Terminal::new`].
///
/// When the terminal size changes, Ratatui automatically resizes internal buffers during
/// [`Terminal::draw`].
///
/// `Frame::area()` always starts at (0, 0).
///
/// [`Terminal::new`]: crate::terminal::Terminal::new
/// [`Terminal::draw`]: crate::terminal::Terminal::draw
#[default]
Fullscreen,
/// The viewport is inline with the rest of the terminal.
/// Draw the application inline with the rest of the terminal output.
///
/// The viewport's height is fixed and specified in number of lines. The width is the same as
/// the terminal's width. The viewport is drawn below the cursor position.
/// The viewport spans the full terminal width and its top-left corner is anchored to column 0
/// of the current cursor row when the terminal is created (and when it is resized). Ratatui
/// reserves space for the requested height; if the cursor is near the bottom of the screen,
/// this may scroll the terminal so the viewport remains fully visible.
///
/// The height is specified in rows and is clamped to the current terminal height.
Inline(u16),
/// The viewport is drawn in a fixed area of the terminal. The area is specified by a [`Rect`].
/// Draw into a fixed region of the terminal.
///
/// This can be useful when Ratatui is responsible for only part of the screen (for example, a
/// status panel beside another renderer), or when you want to manage the overall layout
/// yourself.
///
/// Fixed viewports are not automatically resized. If the region should change (for example, on
/// terminal resize), call [`Terminal::resize`] yourself.
///
/// The area is specified as a [`Rect`] in terminal coordinates.
///
/// `Frame::area()` returns this rectangle as-is (including its `x`/`y` offset).
///
/// [`Terminal::resize`]: crate::terminal::Terminal::resize
Fixed(Rect),
}

View File

@@ -803,7 +803,7 @@ fn spans_after_width<'a>(
/// A trait for converting a value to a [`Line`].
///
/// This trait is automatically implemented for any type that implements the [`Display`] trait. As
/// such, `ToLine` shouln't be implemented directly: [`Display`] should be implemented instead, and
/// such, `ToLine` shouldn't be implemented directly: [`Display`] should be implemented instead, and
/// you get the `ToLine` implementation for free.
///
/// [`Display`]: std::fmt::Display

View File

@@ -474,7 +474,7 @@ impl Widget for &Span<'_> {
/// A trait for converting a value to a [`Span`].
///
/// This trait is automatically implemented for any type that implements the [`Display`] trait. As
/// such, `ToSpan` shouln't be implemented directly: [`Display`] should be implemented instead, and
/// such, `ToSpan` shouldn't be implemented directly: [`Display`] should be implemented instead, and
/// you get the `ToSpan` implementation for free.
///
/// [`Display`]: std::fmt::Display

View File

@@ -72,7 +72,7 @@ fn outer() {
#[test]
fn offset() {
let base = Rect::new(2, 2, 5, 3);
let moved = base.offset(Offset { x: 4, y: 2 });
let moved = base + Offset::new(4, 2);
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 10));
Filled { symbol: "" }.render(base, &mut buf);

View File

@@ -1,8 +1,8 @@
[package]
name = "ratatui-crossterm"
version = "0.1.0-beta.0"
version = "0.1.0"
description = "Crossterm backend for the Ratatui Terminal UI library."
documentation = "https://docs.rs/ratatui-crossterm/"
documentation = "https://docs.rs/ratatui-crossterm"
readme = "README.md"
authors.workspace = true
repository.workspace = true

View File

@@ -423,6 +423,79 @@ impl IntoCrossterm<CrosstermColor> for Color {
}
}
impl IntoCrossterm<ContentStyle> for Style {
fn into_crossterm(self) -> ContentStyle {
let mut attributes = CrosstermAttributes::default();
// Add modifiers
if self.add_modifier.contains(Modifier::BOLD) {
attributes.set(CrosstermAttribute::Bold);
}
if self.add_modifier.contains(Modifier::DIM) {
attributes.set(CrosstermAttribute::Dim);
}
if self.add_modifier.contains(Modifier::ITALIC) {
attributes.set(CrosstermAttribute::Italic);
}
if self.add_modifier.contains(Modifier::UNDERLINED) {
attributes.set(CrosstermAttribute::Underlined);
}
if self.add_modifier.contains(Modifier::SLOW_BLINK) {
attributes.set(CrosstermAttribute::SlowBlink);
}
if self.add_modifier.contains(Modifier::RAPID_BLINK) {
attributes.set(CrosstermAttribute::RapidBlink);
}
if self.add_modifier.contains(Modifier::REVERSED) {
attributes.set(CrosstermAttribute::Reverse);
}
if self.add_modifier.contains(Modifier::HIDDEN) {
attributes.set(CrosstermAttribute::Hidden);
}
if self.add_modifier.contains(Modifier::CROSSED_OUT) {
attributes.set(CrosstermAttribute::CrossedOut);
}
// Sub modifiers (remove modifiers)
if self.sub_modifier.contains(Modifier::BOLD) {
attributes.set(CrosstermAttribute::NoBold);
}
if self.sub_modifier.contains(Modifier::DIM) {
attributes.set(CrosstermAttribute::NormalIntensity);
}
if self.sub_modifier.contains(Modifier::ITALIC) {
attributes.set(CrosstermAttribute::NoItalic);
}
if self.sub_modifier.contains(Modifier::UNDERLINED) {
attributes.set(CrosstermAttribute::NoUnderline);
}
if self.sub_modifier.contains(Modifier::SLOW_BLINK)
|| self.sub_modifier.contains(Modifier::RAPID_BLINK)
{
attributes.set(CrosstermAttribute::NoBlink);
}
if self.sub_modifier.contains(Modifier::REVERSED) {
attributes.set(CrosstermAttribute::NoReverse);
}
if self.sub_modifier.contains(Modifier::HIDDEN) {
attributes.set(CrosstermAttribute::NoHidden);
}
if self.sub_modifier.contains(Modifier::CROSSED_OUT) {
attributes.set(CrosstermAttribute::NotCrossedOut);
}
ContentStyle {
foreground_color: self.fg.map(IntoCrossterm::into_crossterm),
background_color: self.bg.map(IntoCrossterm::into_crossterm),
#[cfg(feature = "underline-color")]
underline_color: self.underline_color.map(IntoCrossterm::into_crossterm),
#[cfg(not(feature = "underline-color"))]
underline_color: None,
attributes,
}
}
}
impl FromCrossterm<CrosstermColor> for Color {
fn from_crossterm(value: CrosstermColor) -> Self {
match value {
@@ -876,4 +949,176 @@ mod tests {
Style::default().underline_color(Color::Red)
);
}
#[rstest]
#[case(Style::default(), ContentStyle::default())]
#[case(
Style::default().fg(Color::Yellow),
ContentStyle {
foreground_color: Some(CrosstermColor::DarkYellow),
..Default::default()
}
)]
#[case(
Style::default().bg(Color::Yellow),
ContentStyle {
background_color: Some(CrosstermColor::DarkYellow),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::BOLD),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Bold),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::BOLD),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoBold),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::ITALIC),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Italic),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::ITALIC),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoItalic),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::UNDERLINED),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Underlined),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::UNDERLINED),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoUnderline),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::DIM),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Dim),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::DIM),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NormalIntensity),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::SLOW_BLINK),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::SlowBlink),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::RAPID_BLINK),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::RapidBlink),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::SLOW_BLINK),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoBlink),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::REVERSED),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Reverse),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::REVERSED),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoReverse),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::HIDDEN),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::Hidden),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::HIDDEN),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NoHidden),
..Default::default()
}
)]
#[case(
Style::default().add_modifier(Modifier::CROSSED_OUT),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::CrossedOut),
..Default::default()
}
)]
#[case(
Style::default().remove_modifier(Modifier::CROSSED_OUT),
ContentStyle {
attributes: CrosstermAttributes::from(CrosstermAttribute::NotCrossedOut),
..Default::default()
}
)]
#[case(
Style::default()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::ITALIC),
ContentStyle {
attributes: CrosstermAttributes::from(
[CrosstermAttribute::Bold, CrosstermAttribute::Italic].as_ref()
),
..Default::default()
}
)]
#[case(
Style::default()
.remove_modifier(Modifier::BOLD)
.remove_modifier(Modifier::ITALIC),
ContentStyle {
attributes: CrosstermAttributes::from(
[CrosstermAttribute::NoBold, CrosstermAttribute::NoItalic].as_ref()
),
..Default::default()
}
)]
fn into_crossterm_content_style(#[case] style: Style, #[case] content_style: ContentStyle) {
assert_eq!(style.into_crossterm(), content_style);
}
#[test]
#[cfg(feature = "underline-color")]
fn into_crossterm_content_style_underline() {
let style = Style::default().underline_color(Color::Red);
let content_style = ContentStyle {
underline_color: Some(CrosstermColor::DarkRed),
..Default::default()
};
assert_eq!(style.into_crossterm(), content_style);
}
}

View File

@@ -1,9 +1,9 @@
[package]
name = "ratatui-macros"
version = "0.7.0-beta.0"
version = "0.7.0"
description = "Macros for Ratatui"
edition.workspace = true
authors = ["The Ratatui Developers"]
description = "Macros for Ratatui"
license = "MIT"
repository = "https://github.com/ratatui/ratatui"
documentation = "https://docs.rs/ratatui-macros"

View File

@@ -1,8 +1,8 @@
[package]
name = "ratatui-termion"
version = "0.1.0-beta.0"
version = "0.1.0"
description = "Termion backend for the Ratatui Terminal UI library."
documentation = "https://docs.rs/ratatui-termion/"
documentation = "https://docs.rs/ratatui-termion"
readme = "README.md"
authors.workspace = true
repository.workspace = true

View File

@@ -1,8 +1,8 @@
[package]
name = "ratatui-termwiz"
version = "0.1.0-beta.0"
version = "0.1.0"
description = "Termwiz backend for the Ratatui Terminal UI library."
documentation = "https://docs.rs/ratatui-termwiz/"
documentation = "https://docs.rs/ratatui-termwiz"
readme = "README.md"
authors.workspace = true
repository.workspace = true

View File

@@ -1,12 +1,12 @@
[package]
name = "ratatui-widgets"
description = "A collection of Ratatui widgets for building terminal user interfaces using Ratatui."
# Note that this started at 0.3.0 as there was a previous crate using the name `ratatui-widgets`.
# <https://github.com/joshka/ratatui-widgets/issues/46>
version = "0.3.0-beta.0"
version = "0.3.0"
description = "A collection of Ratatui widgets for building terminal user interfaces using Ratatui."
documentation = "https://docs.rs/ratatui-widgets"
readme = "README.md"
authors.workspace = true
documentation.workspace = true
repository.workspace = true
homepage.workspace = true
keywords.workspace = true
@@ -18,7 +18,6 @@ rust-version.workspace = true
[package.metadata.docs.rs]
all-features = true
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
rustdoc-args = ["--cfg", "docsrs"]
[features]
@@ -73,8 +72,3 @@ rstest.workspace = true
[lints]
workspace = true
# Adding a single example is enough for activating rustdoc-scrape-examples
[[example]]
name = "barchart"
doc-scrape-examples = true

View File

@@ -53,7 +53,7 @@ fn render(frame: &mut Frame, selected_tab: usize) {
frame.render_widget(title.centered(), top);
render_content(frame, main, selected_tab);
render_tabs(frame, main.offset(Offset { x: 1, y: 0 }), selected_tab);
render_tabs(frame, main + Offset::new(1, 0), selected_tab);
}
/// Render the tabs.

View File

@@ -0,0 +1,111 @@
/// Implement `AsRef<Self>` for widget types to enable `as_ref()` in generic contexts.
///
/// This keeps widget rendering ergonomic when APIs accept `AsRef<WidgetType>` bounds, avoiding
/// the need for `(&widget).render(...)` just to satisfy a trait bound.
///
/// # Example
///
/// ```rust
/// use ratatui_widgets::block::Block;
///
/// let block = Block::default();
/// let block_ref: &Block<'_> = block.as_ref();
/// ```
///
/// # Generated impls
///
/// ```rust,ignore
/// // Non-generic widgets (e.g. Clear, RatatuiLogo).
/// impl AsRef<Clear> for Clear {
/// fn as_ref(&self) -> &Clear {
/// self
/// }
/// }
///
/// // Generic widgets (e.g. Block with a lifetime, Canvas with a lifetime + type parameter).
/// impl<'a> AsRef<Block<'a>> for Block<'a> {
/// fn as_ref(&self) -> &Block<'a> {
/// self
/// }
/// }
///
/// impl<'a, F> AsRef<Canvas<'a, F>> for Canvas<'a, F>
/// where
/// F: Fn(&mut Context),
/// {
/// fn as_ref(&self) -> &Canvas<'a, F> {
/// self
/// }
/// }
/// ```
macro_rules! impl_as_ref {
($type:ty, <$($gen:tt),+> $(where $($bounds:tt)+)?) => {
impl<$($gen),+> AsRef<$type> for $type $(where $($bounds)+)? {
fn as_ref(&self) -> &$type {
self
}
}
};
($type:ty) => {
impl AsRef<$type> for $type {
fn as_ref(&self) -> &$type {
self
}
}
};
}
impl_as_ref!(crate::barchart::BarChart<'a>, <'a>);
impl_as_ref!(crate::block::Block<'a>, <'a>);
impl_as_ref!(crate::canvas::Canvas<'a, F>, <'a, F> where F: Fn(&mut crate::canvas::Context));
impl_as_ref!(crate::chart::Chart<'a>, <'a>);
impl_as_ref!(crate::clear::Clear);
impl_as_ref!(crate::gauge::Gauge<'a>, <'a>);
impl_as_ref!(crate::gauge::LineGauge<'a>, <'a>);
impl_as_ref!(crate::list::List<'a>, <'a>);
impl_as_ref!(crate::logo::RatatuiLogo);
impl_as_ref!(crate::mascot::RatatuiMascot);
impl_as_ref!(crate::paragraph::Paragraph<'a>, <'a>);
impl_as_ref!(crate::scrollbar::Scrollbar<'a>, <'a>);
impl_as_ref!(crate::sparkline::Sparkline<'a>, <'a>);
impl_as_ref!(crate::table::Table<'a>, <'a>);
impl_as_ref!(crate::tabs::Tabs<'a>, <'a>);
#[cfg(feature = "calendar")]
impl_as_ref!(
crate::calendar::Monthly<'a, DS>,
<'a, DS> where DS: crate::calendar::DateStyler
);
#[cfg(test)]
mod tests {
use alloc::vec;
#[test]
fn widgets_implement_as_ref() {
let _ = crate::barchart::BarChart::default().as_ref();
let _ = crate::block::Block::new().as_ref();
let _ = crate::canvas::Canvas::default().paint(|_| {}).as_ref();
let _ = crate::chart::Chart::new(vec![]).as_ref();
let _ = crate::clear::Clear.as_ref();
let _ = crate::gauge::Gauge::default().as_ref();
let _ = crate::gauge::LineGauge::default().as_ref();
let _ = crate::list::List::new(["foo"]).as_ref();
let _ = crate::logo::RatatuiLogo::default().as_ref();
let _ = crate::mascot::RatatuiMascot::default().as_ref();
let _ = crate::paragraph::Paragraph::new("").as_ref();
let _ = crate::scrollbar::Scrollbar::default().as_ref();
let _ = crate::sparkline::Sparkline::default().as_ref();
let _ = crate::table::Table::default().as_ref();
let _ = crate::tabs::Tabs::default().as_ref();
}
#[cfg(feature = "calendar")]
#[test]
fn calendar_widget_implements_as_ref() {
use time::{Date, Month};
let date = Date::from_calendar_date(2024, Month::January, 1).unwrap();
let _ = crate::calendar::Monthly::new(date, crate::calendar::CalendarEventStore::default())
.as_ref();
}
}

View File

@@ -1951,18 +1951,18 @@ mod tests {
let mut offset = Offset::ZERO;
for (border_type_1, border_type_2) in iproduct!(border_types, border_types) {
let title = format!("{border_type_1} + {border_type_2}");
let title_area = Rect::new(0, 0, 43, 1).offset(offset);
let title_area = Rect::new(0, 0, 43, 1) + offset;
title.render(title_area, &mut buffer);
offset.y += 1;
for (rect_1, rect_2) in rects {
Block::bordered()
.border_type(border_type_1)
.merge_borders(strategy)
.render(rect_1.offset(offset), &mut buffer);
.render(rect_1 + offset, &mut buffer);
Block::bordered()
.border_type(border_type_2)
.merge_borders(strategy)
.render(rect_2.offset(offset), &mut buffer);
.render(rect_2 + offset, &mut buffer);
}
offset.y += 9;
}

View File

@@ -104,6 +104,36 @@ impl<'a, DS: DateStyler> Monthly<'a, DS> {
self
}
/// Return the width required to render the calendar.
#[must_use]
pub fn width(&self) -> u16 {
const DAYS_PER_WEEK: u16 = 7;
const GUTTER_WIDTH: u16 = 1;
const DAY_WIDTH: u16 = 2;
let mut width = DAYS_PER_WEEK * (GUTTER_WIDTH + DAY_WIDTH);
if let Some(block) = &self.block {
let (left, right) = block.horizontal_space();
width = width.saturating_add(left).saturating_add(right);
}
width
}
/// Return the height required to render the calendar.
#[must_use]
pub fn height(&self) -> u16 {
let mut height = u16::from(sunday_based_weeks(self.display_date))
.saturating_add(u16::from(self.show_month.is_some()))
.saturating_add(u16::from(self.show_weekday.is_some()));
if let Some(block) = &self.block {
let (top, bottom) = block.vertical_space();
height = height.saturating_add(top).saturating_add(bottom);
}
height
}
/// Return a style with only the background from the default style
const fn default_bg(&self) -> Style {
match self.default_style.bg {
@@ -200,6 +230,22 @@ impl<DS: DateStyler> Monthly<'_, DS> {
}
}
/// Compute how many Sunday-based week rows are needed to render `display_date`.
///
/// Mirrors the rendering logic by taking the difference between the first and last day
/// Sunday-based week numbers (inclusive).
fn sunday_based_weeks(display_date: Date) -> u8 {
let first_of_month = display_date
.replace_day(1)
.expect("valid first day of month");
let last_of_month = first_of_month
.replace_day(first_of_month.month().length(first_of_month.year()))
.expect("valid last of month");
let first_week = first_of_month.sunday_based_week();
let last_week = last_of_month.sunday_based_week();
last_week.saturating_sub(first_week) + 1
}
/// Provides a method for styling a given date. [Monthly] is generic on this trait, so any type
/// that implements this trait can be used.
pub trait DateStyler {
@@ -268,10 +314,11 @@ impl Default for CalendarEventStore {
#[cfg(test)]
mod tests {
use ratatui_core::style::Color;
use ratatui_core::style::{Color, Style};
use time::Month;
use super::*;
use crate::block::{Block, Padding};
#[test]
fn event_store() {
@@ -325,4 +372,87 @@ mod tests {
// This should not panic, even if the buffer has zero size.
calendar.render(buffer.area, &mut buffer);
}
#[test]
fn calendar_width_reflects_grid_layout() {
let date = Date::from_calendar_date(2023, Month::January, 1).unwrap();
let calendar = Monthly::new(date, CalendarEventStore::default());
assert_eq!(calendar.width(), 21);
}
#[test]
fn calendar_height_counts_weeks_and_headers() {
let date = Date::from_calendar_date(2015, Month::February, 1).unwrap();
let base_calendar = Monthly::new(date, CalendarEventStore::default());
assert_eq!(base_calendar.height(), 4);
let decorated_calendar = Monthly::new(date, CalendarEventStore::default())
.show_month_header(Style::default())
.show_weekdays_header(Style::default());
assert_eq!(decorated_calendar.height(), 6);
}
#[test]
fn calendar_dimensions_examples() {
// Feb 2015 starts Sunday and spans 4 rows.
let feb_2015 = Date::from_calendar_date(2015, Month::February, 1).unwrap();
let cal = Monthly::new(feb_2015, CalendarEventStore::default());
assert_eq!(cal.width(), 21, "4w base width");
assert_eq!(cal.height(), 4, "Feb 2015 rows");
let cal = Monthly::new(feb_2015, CalendarEventStore::default())
.show_month_header(Style::default())
.show_weekdays_header(Style::default());
assert_eq!(cal.height(), 6, "Headers add 2 rows");
let block = Block::bordered().padding(Padding::new(2, 3, 1, 2));
let cal = Monthly::new(feb_2015, CalendarEventStore::default()).block(block);
assert_eq!(cal.width(), 28, "Padding widens width");
assert_eq!(cal.height(), 9, "Padding grows height");
// Feb 2024 starts Thursday and spans 5 rows.
let feb_2024 = Date::from_calendar_date(2024, Month::February, 1).unwrap();
let cal = Monthly::new(feb_2024, CalendarEventStore::default());
assert_eq!(cal.width(), 21, "5w base width");
assert_eq!(cal.height(), 5, "Feb 2024 rows");
let cal = Monthly::new(feb_2024, CalendarEventStore::default())
.show_month_header(Style::default())
.show_weekdays_header(Style::default());
assert_eq!(cal.height(), 7, "Headers add 2 rows (5w)");
let cal = Monthly::new(feb_2024, CalendarEventStore::default()).block(Block::bordered());
assert_eq!(cal.width(), 23, "Border adds 2 cols");
assert_eq!(cal.height(), 7, "Border adds 2 rows");
// Apr 2023 starts Saturday and spans 6 rows.
let apr_2023 = Date::from_calendar_date(2023, Month::April, 1).unwrap();
let cal = Monthly::new(apr_2023, CalendarEventStore::default());
assert_eq!(cal.width(), 21, "6w base width");
assert_eq!(cal.height(), 6, "Apr 2023 rows");
let cal = Monthly::new(apr_2023, CalendarEventStore::default())
.show_month_header(Style::default())
.show_weekdays_header(Style::default());
assert_eq!(cal.height(), 8, "Headers add 2 rows (6w)");
let block = Block::bordered().padding(Padding::symmetric(1, 1));
let cal = Monthly::new(apr_2023, CalendarEventStore::default()).block(block);
assert_eq!(cal.width(), 25, "Symmetric padding width");
assert_eq!(cal.height(), 10, "Symmetric padding height");
}
#[test]
fn sunday_based_weeks_shapes() {
let sunday_start =
Date::from_calendar_date(2015, Month::February, 11).expect("valid test date");
let saturday_start =
Date::from_calendar_date(2023, Month::April, 9).expect("valid test date");
let leap_year =
Date::from_calendar_date(2024, Month::February, 29).expect("valid test date");
assert_eq!(sunday_based_weeks(sunday_start), 4);
assert_eq!(sunday_based_weeks(saturday_start), 6);
assert_eq!(sunday_based_weeks(leap_year), 5);
}
}

View File

@@ -14,7 +14,6 @@
//! You can also implement your own custom [`Shape`]s.
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
@@ -24,6 +23,8 @@ use itertools::Itertools;
use ratatui_core::buffer::Buffer;
use ratatui_core::layout::Rect;
use ratatui_core::style::{Color, Style};
use ratatui_core::symbols::braille::BRAILLE;
use ratatui_core::symbols::pixel::{OCTANTS, QUADRANTS, SEXTANTS};
use ratatui_core::symbols::{self, Marker};
use ratatui_core::text::Line as TextLine;
use ratatui_core::widgets::Widget;
@@ -69,11 +70,20 @@ pub struct Label<'a> {
/// multiple shapes on the canvas in specific order.
#[derive(Debug)]
struct Layer {
// A string of characters representing the grid. This will be wrapped to the width of the grid
// when rendering
string: String,
// Colors for foreground and background of each cell
colors: Vec<(Color, Color)>,
contents: Vec<LayerCell>,
}
/// A cell within a layer.
///
/// If a [`Context`] contains multiple layers, then the symbol, foreground, and background colors
/// for a character will be determined by the top-most layer that provides a value for that
/// character. For example, a chart drawn with [`Marker::Block`] may provide the background color,
/// and a later chart drawn with [`Marker::Braille`] may provide the symbol and foreground color.
#[derive(Debug)]
struct LayerCell {
symbol: Option<char>,
fg: Option<Color>,
bg: Option<Color>,
}
/// A grid of cells that can be painted on.
@@ -100,73 +110,111 @@ trait Grid: fmt::Debug {
fn reset(&mut self);
}
/// The `BrailleGrid` is a grid made up of cells each containing a Braille pattern.
/// The pattern and color of a `PatternGrid` cell.
#[derive(Copy, Clone, Debug, Default)]
struct PatternCell {
/// The pattern of a grid character.
///
/// The pattern is stored in the lower bits in a row-major order. For instance, for a 2x4
/// pattern marker, bits 0 to 7 of this field should represent the following pseudo-pixels:
///
/// | 0 1 |
/// | 2 3 |
/// | 4 5 |
/// | 6 7 |
pattern: u8,
/// The color of a cell only supports foreground colors for now as there's no way to
/// individually set the background color of each pseudo-pixel in a pattern character.
color: Option<Color>,
}
/// The `PatternGrid` is a grid made up of cells each containing a `W`x`H` pattern character.
///
/// This makes it possible to draw shapes with a resolution of 2x4 dots per cell. This is useful
/// when you want to draw shapes with a high resolution. Font support for Braille patterns is
/// required to see the dots. If your terminal or font does not support this unicode block, you
/// will see unicode replacement characters (<28>) instead of braille dots.
/// This makes it possible to draw shapes with a resolution of e.g. 2x4 (Braille or unicode octant)
/// per cell.
/// Font support for the relevant pattern character is required. If your terminal or font does not
/// support the relevant unicode block, you will see unicode replacement characters (<28>) instead.
///
/// This grid type only supports a single foreground color for each 2x4 dots cell. There is no way
/// to set the individual color of each dot in the braille pattern.
/// This grid type only supports a single foreground color for each `W`x`H` pattern character.
/// There is no way to set the individual color of each pseudo-pixel.
#[derive(Debug)]
struct BrailleGrid {
struct PatternGrid<const W: usize, const H: usize> {
/// Width of the grid in number of terminal columns
width: u16,
/// Height of the grid in number of terminal rows
height: u16,
/// Represents the unicode braille patterns. Will take a value between `0x2800` and `0x28FF`
/// this is converted to an utf16 string when converting to a layer. See
/// <https://en.wikipedia.org/wiki/Braille_Patterns> for more info.
utf16_code_points: Vec<u16>,
/// The color of each cell only supports foreground colors for now as there's no way to
/// individually set the background color of each dot in the braille pattern.
colors: Vec<Color>,
/// Pattern and color of the cells.
cells: Vec<PatternCell>,
/// Lookup table mapping patterns to characters.
char_table: &'static [char],
}
impl BrailleGrid {
/// Create a new `BrailleGrid` with the given width and height measured in terminal columns and
/// rows respectively.
fn new(width: u16, height: u16) -> Self {
impl<const W: usize, const H: usize> PatternGrid<W, H> {
/// Statically check that the dimension of the pattern is supported.
const _PATTERN_DIMENSION_CHECK: usize = u8::BITS as usize - W * H;
/// Create a new `PatternGrid` with the given width and height measured in terminal columns
/// and rows respectively.
fn new(width: u16, height: u16, char_table: &'static [char]) -> Self {
// Cause a static error if the pattern doesn't fit within 8 bits.
let _ = Self::_PATTERN_DIMENSION_CHECK;
let length = usize::from(width) * usize::from(height);
Self {
width,
height,
utf16_code_points: vec![symbols::braille::BLANK; length],
colors: vec![Color::Reset; length],
cells: vec![PatternCell::default(); length],
char_table,
}
}
}
impl Grid for BrailleGrid {
impl<const W: usize, const H: usize> Grid for PatternGrid<W, H> {
fn resolution(&self) -> (f64, f64) {
(f64::from(self.width) * 2.0, f64::from(self.height) * 4.0)
(
f64::from(self.width) * W as f64,
f64::from(self.height) * H as f64,
)
}
fn save(&self) -> Layer {
let string = String::from_utf16(&self.utf16_code_points).unwrap();
// the background color is always reset for braille patterns
let colors = self.colors.iter().map(|c| (*c, Color::Reset)).collect();
Layer { string, colors }
let contents = self
.cells
.iter()
.map(|&cell| {
let symbol = match cell.pattern {
// Skip rendering blank patterns to allow layers underneath
// to show through.
0 => None,
idx => Some(self.char_table[idx as usize]),
};
LayerCell {
symbol,
fg: cell.color,
// Patterns only affect foreground.
bg: None,
}
})
.collect();
Layer { contents }
}
fn reset(&mut self) {
self.utf16_code_points.fill(symbols::braille::BLANK);
self.colors.fill(Color::Reset);
self.cells.fill_with(Default::default);
}
fn paint(&mut self, x: usize, y: usize, color: Color) {
let index = y
.saturating_div(4)
.saturating_div(H)
.saturating_mul(self.width as usize)
.saturating_add(x.saturating_div(2));
.saturating_add(x.saturating_div(W));
// using get_mut here because we are indexing the vector with usize values
// and we want to make sure we don't panic if the index is out of bounds
if let Some(c) = self.utf16_code_points.get_mut(index) {
*c |= symbols::braille::DOTS[y % 4][x % 2];
}
if let Some(c) = self.colors.get_mut(index) {
*c = color;
if let Some(cell) = self.cells.get_mut(index) {
cell.pattern |= 1u8 << ((x % W) + W * (y % H));
cell.color = Some(color);
}
}
}
@@ -181,12 +229,16 @@ struct CharGrid {
width: u16,
/// Height of the grid in number of terminal rows
height: u16,
/// Represents a single character for each cell
cells: Vec<char>,
/// The color of each cell
colors: Vec<Color>,
cells: Vec<Option<Color>>,
/// The character to use for every cell - e.g. a block, dot, etc.
cell_char: char,
/// If true, apply the color to the background as well as the foreground. This is used for
/// [`Marker::Block`], so that it will overwrite any previous foreground character, but also
/// leave a background that can be overlaid with an additional foreground character.
apply_color_to_bg: bool,
}
impl CharGrid {
@@ -197,9 +249,16 @@ impl CharGrid {
Self {
width,
height,
cells: vec![' '; length],
colors: vec![Color::Reset; length],
cells: vec![None; length],
cell_char,
apply_color_to_bg: false,
}
}
fn apply_color_to_bg(self) -> Self {
Self {
apply_color_to_bg: true,
..self
}
}
}
@@ -211,14 +270,20 @@ impl Grid for CharGrid {
fn save(&self) -> Layer {
Layer {
string: self.cells.iter().collect(),
colors: self.colors.iter().map(|c| (*c, Color::Reset)).collect(),
contents: self
.cells
.iter()
.map(|&color| LayerCell {
symbol: color.map(|_| self.cell_char),
fg: color,
bg: color.filter(|_| self.apply_color_to_bg),
})
.collect(),
}
}
fn reset(&mut self) {
self.cells.fill(' ');
self.colors.fill(Color::Reset);
self.cells.fill(None);
}
fn paint(&mut self, x: usize, y: usize, color: Color) {
@@ -226,10 +291,7 @@ impl Grid for CharGrid {
// using get_mut here because we are indexing the vector with usize values
// and we want to make sure we don't panic if the index is out of bounds
if let Some(c) = self.cells.get_mut(index) {
*c = self.cell_char;
}
if let Some(c) = self.colors.get_mut(index) {
*c = color;
*c = Some(color);
}
}
}
@@ -244,7 +306,7 @@ impl Grid for CharGrid {
/// and lower half of each cell. This allows us to draw shapes with a resolution of 1x2 "pixels" per
/// cell.
///
/// This allows for more flexibility than the `BrailleGrid` which only supports a single
/// This allows for more flexibility than the `PatternGrid` which only supports a single
/// foreground color for each 2x4 dots cell, and the `CharGrid` which only supports a single
/// character for each cell.
#[derive(Debug)]
@@ -254,7 +316,7 @@ struct HalfBlockGrid {
/// Height of the grid in number of terminal rows
height: u16,
/// Represents a single color for each "pixel" arranged in column, row order
pixels: Vec<Vec<Color>>,
pixels: Vec<Vec<Option<Color>>>,
}
impl HalfBlockGrid {
@@ -264,7 +326,7 @@ impl HalfBlockGrid {
Self {
width,
height,
pixels: vec![vec![Color::Reset; width as usize]; (height as usize) * 2],
pixels: vec![vec![None; width as usize]; (height as usize) * 2],
}
}
}
@@ -302,45 +364,34 @@ impl Grid for HalfBlockGrid {
.tuples()
.flat_map(|(upper_row, lower_row)| zip(upper_row, lower_row));
// then we work out what character to print for each pair of pixels
let string = vertical_color_pairs
.clone()
.map(|(upper, lower)| match (upper, lower) {
(Color::Reset, Color::Reset) => ' ',
(Color::Reset, _) => symbols::half_block::LOWER,
(_, Color::Reset) => symbols::half_block::UPPER,
(&lower, &upper) => {
if lower == upper {
symbols::half_block::FULL
} else {
symbols::half_block::UPPER
}
}
})
.collect();
// then we convert these each vertical pair of pixels into a foreground and background color
let colors = vertical_color_pairs
// Then we determine the character to print for each pair, along with the color of the
// foreground and background.
let contents = vertical_color_pairs
.map(|(upper, lower)| {
let (fg, bg) = match (upper, lower) {
(Color::Reset, Color::Reset) => (Color::Reset, Color::Reset),
(Color::Reset, &lower) => (lower, Color::Reset),
(&upper, Color::Reset) => (upper, Color::Reset),
(&upper, &lower) => (upper, lower),
let (symbol, fg, bg) = match (upper, lower) {
(None, None) => (None, None, None),
(None, Some(lower)) => (Some(symbols::half_block::LOWER), Some(*lower), None),
(Some(upper), None) => (Some(symbols::half_block::UPPER), Some(*upper), None),
(Some(upper), Some(lower)) if lower == upper => {
(Some(symbols::half_block::FULL), Some(*upper), Some(*lower))
}
(Some(upper), Some(lower)) => {
(Some(symbols::half_block::UPPER), Some(*upper), Some(*lower))
}
};
(fg, bg)
LayerCell { symbol, fg, bg }
})
.collect();
Layer { string, colors }
Layer { contents }
}
fn reset(&mut self) {
self.pixels.fill(vec![Color::Reset; self.width as usize]);
self.pixels.fill(vec![None; self.width as usize]);
}
fn paint(&mut self, x: usize, y: usize, color: Color) {
self.pixels[y][x] = color;
self.pixels[y][x] = Some(color);
}
}
@@ -462,7 +513,17 @@ impl<'a, 'b> From<&'a mut Context<'b>> for Painter<'a, 'b> {
/// this as similar to the `Frame` struct that is used to draw widgets on the terminal.
#[derive(Debug)]
pub struct Context<'a> {
// Width of the canvas in cells.
//
// This is NOT the resolution in dots/pixels as this varies by marker type.
width: u16,
// Height of the canvas in cells.
//
// This is NOT the resolution in dots/pixels as this varies by marker type.
height: u16,
// Canvas coordinate system width
x_bounds: [f64; 2],
// Canvas coordinate system height
y_bounds: [f64; 2],
grid: Box<dyn Grid>,
dirty: bool,
@@ -501,17 +562,10 @@ impl<'a> Context<'a> {
y_bounds: [f64; 2],
marker: Marker,
) -> Self {
let dot = symbols::DOT.chars().next().unwrap();
let block = symbols::block::FULL.chars().next().unwrap();
let bar = symbols::bar::HALF.chars().next().unwrap();
let grid: Box<dyn Grid> = match marker {
Marker::Dot => Box::new(CharGrid::new(width, height, dot)),
Marker::Block => Box::new(CharGrid::new(width, height, block)),
Marker::Bar => Box::new(CharGrid::new(width, height, bar)),
Marker::Braille => Box::new(BrailleGrid::new(width, height)),
Marker::HalfBlock => Box::new(HalfBlockGrid::new(width, height)),
};
let grid = Self::marker_to_grid(width, height, marker);
Self {
width,
height,
x_bounds,
y_bounds,
grid,
@@ -521,6 +575,30 @@ impl<'a> Context<'a> {
}
}
fn marker_to_grid(width: u16, height: u16, marker: Marker) -> Box<dyn Grid> {
let dot = symbols::DOT.chars().next().unwrap();
let block = symbols::block::FULL.chars().next().unwrap();
let bar = symbols::bar::HALF.chars().next().unwrap();
match marker {
Marker::Block => Box::new(CharGrid::new(width, height, block).apply_color_to_bg()),
Marker::Bar => Box::new(CharGrid::new(width, height, bar)),
Marker::Braille => Box::new(PatternGrid::<2, 4>::new(width, height, &BRAILLE)),
Marker::HalfBlock => Box::new(HalfBlockGrid::new(width, height)),
Marker::Quadrant => Box::new(PatternGrid::<2, 2>::new(width, height, &QUADRANTS)),
Marker::Sextant => Box::new(PatternGrid::<2, 3>::new(width, height, &SEXTANTS)),
Marker::Octant => Box::new(PatternGrid::<2, 4>::new(width, height, &OCTANTS)),
Marker::Dot | _ => Box::new(CharGrid::new(width, height, dot)),
}
}
/// Change the marker being used in this context.
///
/// This will save the last layer if necessary and reset the grid to use the new marker.
pub fn marker(&mut self, marker: Marker) {
self.finish();
self.grid = Self::marker_to_grid(self.width, self.height, marker);
}
/// Draw the given [`Shape`] in this context
pub fn draw<S>(&mut self, shape: &S)
where
@@ -573,16 +651,25 @@ impl<'a> Context<'a> {
///
/// By default the grid is made of Braille patterns but you may change the marker to use a different
/// set of symbols. If your terminal or font does not support this unicode block, you will see
/// unicode replacement characters (<28>) instead of braille dots. The Braille patterns provide a more
/// fine grained result (2x4 dots) but you might want to use a simple dot, block, or bar instead by
/// calling the [`marker`] method if your target environment does not support those symbols.
/// unicode replacement characters (<28>) instead of braille dots. The Braille patterns (as well the
/// octant character patterns) provide a more fine grained result with a 2x4 resolution per
/// character, but you might want to use a simple dot, block, or bar instead by calling the
/// [`marker`] method if your target environment does not support those symbols.
///
/// See [Unicode Braille Patterns](https://en.wikipedia.org/wiki/Braille_Patterns) for more info.
///
/// The `Octant` marker is similar to the `Braille` marker but, instead of sparse dots, displays
/// densely packed and regularly spaced pseudo-pixels, without visible bands between rows and
/// columns. However, it uses characters that are not yet as widely supported as the Braille
/// unicode block.
///
/// The `Quadrant` and `Sextant` markers are in turn akin to the `Octant` marker, but with a 2x2
/// and 2x3 resolution, respectively.
///
/// The `HalfBlock` marker is useful when you want to draw shapes with a higher resolution than a
/// `CharGrid` but lower than a `BrailleGrid`. This grid type supports a foreground and background
/// color for each terminal cell. This allows for more flexibility than the `BrailleGrid` which only
/// supports a single foreground color for each 2x4 dots cell.
/// `CharGrid` but lower than a `PatternGrid`. This grid type supports a foreground and background
/// color for each terminal cell. This allows for more flexibility than the `PatternGrid` which
/// only supports a single foreground color for each 2x4 dots cell.
///
/// The Canvas widget is used by calling the [`Canvas::paint`] method and passing a closure that
/// will be used to draw on the canvas. The closure will be passed a [`Context`] object that can be
@@ -723,7 +810,7 @@ where
/// The [`HalfBlock`] marker is useful when you want to draw shapes with a higher resolution
/// than with a grid of characters (e.g. with [`Block`] or [`Dot`]) but lower than with
/// [`Braille`]. This grid type supports a foreground and background color for each terminal
/// cell. This allows for more flexibility than the `BrailleGrid` which only supports a single
/// cell. This allows for more flexibility than the `PatternGrid` which only supports a single
/// foreground color for each 2x4 dots cell.
///
/// [`Braille`]: ratatui_core::symbols::Marker::Braille
@@ -802,19 +889,21 @@ where
// Retrieve painted points for each layer
for layer in ctx.layers {
for (index, (ch, colors)) in layer.string.chars().zip(layer.colors).enumerate() {
if ch != ' ' && ch != '\u{2800}' {
let (x, y) = (
(index % width) as u16 + canvas_area.left(),
(index / width) as u16 + canvas_area.top(),
);
let cell = buf[(x, y)].set_char(ch);
if colors.0 != Color::Reset {
cell.set_fg(colors.0);
}
if colors.1 != Color::Reset {
cell.set_bg(colors.1);
}
for (index, layer_cell) in layer.contents.iter().enumerate() {
let (x, y) = (
(index % width) as u16 + canvas_area.left(),
(index / width) as u16 + canvas_area.top(),
);
let cell = &mut buf[(x, y)];
if let Some(symbol) = layer_cell.symbol {
cell.set_char(symbol);
}
if let Some(fg) = layer_cell.fg {
cell.set_fg(fg);
}
if let Some(bg) = layer_cell.bg {
cell.set_bg(bg);
}
}
}
@@ -847,12 +936,76 @@ where
mod tests {
use indoc::indoc;
use ratatui_core::buffer::Cell;
use rstest::rstest;
use super::*;
// helper to test the canvas checks that drawing a vertical and horizontal line
// results in the expected output
fn test_marker(marker: Marker, expected: &str) {
#[rstest]
#[case::block(Marker::Block, indoc!(
"
█xxxx
█xxxx
█xxxx
█xxxx
█████"
))]
#[case::half_block(Marker::HalfBlock, indoc!(
"
█xxxx
█xxxx
█xxxx
█xxxx
█▄▄▄▄"
))]
#[case::bar(Marker::Bar, indoc!(
"
▄xxxx
▄xxxx
▄xxxx
▄xxxx
▄▄▄▄▄"
))]
#[case::braille(Marker::Braille, indoc!(
"
⡇xxxx
⡇xxxx
⡇xxxx
⡇xxxx
⣇⣀⣀⣀⣀"
))]
#[case::quadrant(Marker::Quadrant, indoc!(
"
▌xxxx
▌xxxx
▌xxxx
▌xxxx
▙▄▄▄▄"
))]
#[case::sextant(Marker::Sextant, indoc!(
"
▌xxxx
▌xxxx
▌xxxx
▌xxxx
🬲🬭🬭🬭🬭"
))]
#[case::octant(Marker::Octant, indoc!(
"
▌xxxx
▌xxxx
▌xxxx
▌xxxx
𜷀▂▂▂▂"
))]
#[case::dot(Marker::Dot, indoc!(
"
•xxxx
•xxxx
•xxxx
•xxxx
•••••"
))]
fn test_horizontal_with_vertical(#[case] marker: Marker, #[case] expected: &'static str) {
let area = Rect::new(0, 0, 5, 5);
let mut buf = Buffer::filled(area, Cell::new("x"));
let horizontal_line = Line {
@@ -881,71 +1034,104 @@ mod tests {
assert_eq!(buf, Buffer::with_lines(expected.lines()));
}
#[test]
fn test_bar_marker() {
test_marker(
Marker::Bar,
indoc!(
#[rstest]
#[case::block(Marker::Block, indoc!(
"
xxxx
▄xxxx
xxxx
▄xxxx
▄▄▄▄▄"
),
);
}
#[test]
fn test_block_marker() {
test_marker(
Marker::Block,
indoc!(
xxx
x█x█x
xxxx
x█x█x
█xxx█"))]
#[case::half_block(Marker::HalfBlock,
indoc!(
"
█xxxx
█xxxx
xxxx
█xxxx
███"
),
);
}
#[test]
fn test_braille_marker() {
test_marker(
Marker::Braille,
indoc!(
█xxx
x█xx
xxxx
x█xx
xxx")
)]
#[case::bar(Marker::Bar, indoc!(
"
xxxx
⡇xxxx
xxxx
⡇xxxx
⣇⣀⣀⣀⣀"
),
);
}
#[test]
fn test_dot_marker() {
test_marker(
Marker::Dot,
indoc!(
xxx
x▄x▄x
xxxx
x▄x▄x
▄xxx▄"))]
#[case::braille(Marker::Braille, indoc!(
"
xxxx
•xxxx
xxxx
•xxxx
•••••"
),
);
xxx
x⢣x⡜x
xxxx
x⡜x⢣x
⡜xxx⢣"
))]
#[case::quadrant(Marker::Quadrant, indoc!(
"
▚xxx▞
x▚x▞x
xx█xx
x▞x▚x
▞xxx▚"
))]
#[case::sextant(Marker::Sextant, indoc!(
"
🬧xxx🬔
x🬧x🬔x
xx█xx
x🬘x🬣x
🬘xxx🬣"
))]
#[case::octant(Marker::Octant, indoc!(
"
▚xxx▞
x▚x▞x
xx█xx
x▞x▚x
▞xxx▚"
))]
#[case::dot(Marker::Dot, indoc!(
"
•xxx•
x•x•x
xx•xx
x•x•x
•xxx•"
))]
fn test_diagonal_lines(#[case] marker: Marker, #[case] expected: &'static str) {
let area = Rect::new(0, 0, 5, 5);
let mut buf = Buffer::filled(area, Cell::new("x"));
let diagonal_up = Line {
x1: 0.0,
y1: 0.0,
x2: 10.0,
y2: 10.0,
color: Color::Reset,
};
let diagonal_down = Line {
x1: 0.0,
y1: 10.0,
x2: 10.0,
y2: 0.0,
color: Color::Reset,
};
Canvas::default()
.marker(marker)
.paint(|ctx| {
ctx.draw(&diagonal_down);
ctx.draw(&diagonal_up);
})
.x_bounds([0.0, 10.0])
.y_bounds([0.0, 10.0])
.render(area, &mut buf);
assert_eq!(buf, Buffer::with_lines(expected.lines()));
}
// The canvas methods work a lot with arithmetic so here we enter various width and height
// values to check if there are any integer overflows we just initialize the canvas painters
#[test]
fn check_canvas_paint_max() {
let mut b_grid = BrailleGrid::new(u16::MAX, 2);
let mut b_grid = PatternGrid::<2, 4>::new(u16::MAX, 2, &OCTANTS);
let mut c_grid = CharGrid::new(u16::MAX, 2, 'd');
let max = u16::MAX as usize;
@@ -964,7 +1150,7 @@ mod tests {
// We delibately cause integer overflow to check if we don't panic and don't get weird behavior
#[test]
fn check_canvas_paint_overflow() {
let mut b_grid = BrailleGrid::new(u16::MAX, 3);
let mut b_grid = PatternGrid::<2, 4>::new(u16::MAX, 3, &BRAILLE);
let mut c_grid = CharGrid::new(u16::MAX, 3, 'd');
let max = u16::MAX as usize + 10;

View File

@@ -31,7 +31,7 @@ impl MapResolution {
}
}
/// A world map
/// A world map. It represents the world using the [EPSG:4326 coordinate reference system](https://en.wikipedia.org/wiki/EPSG_Geodetic_Parameter_Dataset).
///
/// A world map can be rendered with different [resolutions](MapResolution) and [colors](Color).
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]

View File

@@ -115,7 +115,7 @@ mod tests {
"█ █",
"██████████",
]);
expected.set_style(buffer.area, Style::new().red());
expected.set_style(buffer.area, Style::new().red().on_red());
expected.set_style(buffer.area.inner(Margin::new(1, 1)), Style::reset());
assert_eq!(buffer, expected);
}

View File

@@ -1017,16 +1017,18 @@ impl Widget for &Chart<'_> {
}
}
for dataset in &self.datasets {
Canvas::default()
.background_color(self.style.bg.unwrap_or(Color::Reset))
.x_bounds(self.x_axis.bounds)
.y_bounds(self.y_axis.bounds)
.marker(dataset.marker)
.paint(|ctx| {
Canvas::default()
.background_color(self.style.bg.unwrap_or(Color::Reset))
.x_bounds(self.x_axis.bounds)
.y_bounds(self.y_axis.bounds)
.paint(|ctx| {
for dataset in &self.datasets {
ctx.marker(dataset.marker);
let color = dataset.style.fg.unwrap_or(Color::Reset);
ctx.draw(&Points {
coords: dataset.data,
color: dataset.style.fg.unwrap_or(Color::Reset),
color,
});
match dataset.graph_type {
GraphType::Line => {
@@ -1036,7 +1038,7 @@ impl Widget for &Chart<'_> {
y1: data[0].1,
x2: data[1].0,
y2: data[1].1,
color: dataset.style.fg.unwrap_or(Color::Reset),
color,
});
}
}
@@ -1047,15 +1049,15 @@ impl Widget for &Chart<'_> {
y1: 0.0,
x2: *x,
y2: *y,
color: dataset.style.fg.unwrap_or(Color::Reset),
color,
});
}
}
GraphType::Scatter => {}
}
})
.render(graph_area, buf);
}
}
})
.render(graph_area, buf);
if let Some(Position { x, y }) = layout.title_x {
let title = self.x_axis.title.as_ref().unwrap();
@@ -1548,6 +1550,62 @@ mod tests {
assert_eq!(buffer, expected);
}
#[rstest]
#[case::dot(symbols::Marker::Dot, '•')]
#[case::dot(symbols::Marker::Braille, '⢣')]
fn overlapping_lines(#[case] marker: symbols::Marker, #[case] symbol: char) {
let data_diagonal_up = [(0.0, 0.0), (5.0, 5.0)];
let data_diagonal_down = [(0.0, 5.0), (5.0, 0.0)];
let lines = vec![
Dataset::default()
.data(&data_diagonal_up)
.marker(symbols::Marker::Block)
.graph_type(GraphType::Line)
.blue(),
Dataset::default()
.data(&data_diagonal_down)
.marker(marker)
.graph_type(GraphType::Line)
.red(),
];
let chart = Chart::new(lines)
.x_axis(Axis::default().bounds([0.0, 5.0]))
.y_axis(Axis::default().bounds([0.0, 5.0]));
let area = Rect::new(0, 0, 5, 5);
let mut buffer = Buffer::empty(area);
chart.render(buffer.area, &mut buffer);
#[rustfmt::skip]
let mut expected = Buffer::with_lines([
format!("{symbol}"),
format!(" {symbol}"),
format!(" {symbol} "),
format!("{symbol} "),
format!("{symbol}"),
]);
for i in 0..5 {
// The Marker::Dot and Marker::Braille tiles have the
// foreground set to Red.
expected.set_style(Rect::new(i, i, 1, 1), Style::new().fg(Color::Red));
// The Marker::Block tiles have both the foreground and
// background set to Blue.
expected.set_style(
Rect::new(i, 4 - i, 1, 1),
Style::new().fg(Color::Blue).bg(Color::Blue),
);
}
// Where the Marker::Dot/Braille overlaps with Marker::Block,
// the background is set to blue from the Block, but the
// foreground is set to red from the Dot/Braille. This allows
// two line plots to overlap, so long as one of them is a
// Block.
expected.set_style(
Rect::new(2, 2, 1, 1),
Style::new().fg(Color::Red).bg(Color::Blue),
);
assert_eq!(buffer, expected);
}
#[test]
fn render_in_minimal_buffer() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));

View File

@@ -130,5 +130,6 @@ pub mod tabs;
mod polyfills;
mod reflow;
mod as_ref;
#[cfg(feature = "calendar")]
pub mod calendar;

View File

@@ -403,7 +403,7 @@ impl<'a> List<'a> {
///
/// # Example
///
/// A padding value of 1 will keep 1 item above and 1 item bellow visible if possible
/// A padding value of 1 will keep 1 item above and 1 item below visible if possible
///
/// ```rust
/// use ratatui::widgets::List;

View File

@@ -220,7 +220,7 @@ impl List<'_> {
let last_valid_index = self.items.len().saturating_sub(1);
let selected = selected?.min(last_valid_index);
// The bellow loop handles situations where the list item sizes may not be consistent,
// The below loop handles situations where the list item sizes may not be consistent,
// where the offset would have excluded some items that we want to include, or could
// cause the offset value to be set to an inconsistent value each time we render.
// The padding value will be reduced in case any of these issues would occur
@@ -1219,7 +1219,7 @@ mod tests {
assert_eq!(buffer, Buffer::with_lines(expected));
}
// Tests to make sure when it's pushing back the first visible index value that it doesnt
// Tests to make sure when it's pushing back the first visible index value that it doesn't
// include an item that's too large
#[test]
fn padding_offset_pushback_break() {

View File

@@ -776,7 +776,7 @@ impl StatefulWidget for &Table<'_> {
self.render_header(header_area, buf, &column_widths);
self.render_rows(rows_area, buf, state, selection_width, &column_widths);
self.render_rows(rows_area, buf, selection_width, state, &column_widths);
self.render_footer(footer_area, buf, &column_widths);
}
@@ -806,31 +806,47 @@ impl Table<'_> {
(header_area, rows_area, footer_area)
}
fn render_header(&self, area: Rect, buf: &mut Buffer, column_widths: &[(u16, u16)]) {
/// Render the header cells, if they are not `None`
///
/// The `x` and `width` fields of each `Rect` in `column_widths` denote the starting
/// x-coordinate and width of each column in the table.
fn render_header(&self, area: Rect, buf: &mut Buffer, column_widths: &[Rect]) {
if let Some(ref header) = self.header {
buf.set_style(area, header.style);
for ((x, width), cell) in column_widths.iter().zip(header.cells.iter()) {
cell.render(Rect::new(area.x + x, area.y, *width, area.height), buf);
for (cell_area, cell) in column_widths.iter().zip(header.cells.iter()) {
let new_x = area.x + cell_area.x;
let area_to_render = Rect::new(new_x, area.y, cell_area.width, area.height);
cell.render(area_to_render, buf);
}
}
}
fn render_footer(&self, area: Rect, buf: &mut Buffer, column_widths: &[(u16, u16)]) {
/// Render the footer cells, if they are not `None`
///
/// The `x` and `width` fields of each `Rect` in `column_widths` denote the starting
/// x-coordinate and width of each column in the table.
fn render_footer(&self, area: Rect, buf: &mut Buffer, column_widths: &[Rect]) {
if let Some(ref footer) = self.footer {
buf.set_style(area, footer.style);
for ((x, width), cell) in column_widths.iter().zip(footer.cells.iter()) {
cell.render(Rect::new(area.x + x, area.y, *width, area.height), buf);
for (cell_area, cell) in column_widths.iter().zip(footer.cells.iter()) {
let new_x = area.x + cell_area.x;
let area_to_render = Rect::new(new_x, area.y, cell_area.width, area.height);
cell.render(area_to_render, buf);
}
}
}
/// Render the table rows
///
/// The `x` and `width` fields of each `Rect` in `column_widths` denote the starting
/// x-coordinate and width of each column in the table.
fn render_rows(
&self,
area: Rect,
buf: &mut Buffer,
state: &mut TableState,
selection_width: u16,
columns_widths: &[(u16, u16)],
state: &mut TableState,
columns_widths: &[Rect],
) {
if self.rows.is_empty() {
return;
@@ -856,19 +872,9 @@ impl Table<'_> {
let is_selected = state.selected.is_some_and(|index| index == i);
if selection_width > 0 && is_selected {
let selection_area = Rect {
width: selection_width,
..row_area
};
buf.set_style(selection_area, row.style);
(&self.highlight_symbol).render(selection_area, buf);
}
for ((x, width), cell) in columns_widths.iter().zip(row.cells.iter()) {
cell.render(
Rect::new(row_area.x + x, row_area.y, *width, row_area.height),
buf,
);
self.set_selection_style(buf, selection_width, row_area, row);
}
self.render_row_cells(buf, columns_widths.iter().collect(), &row.cells, row_area);
if is_selected {
selected_row_area = Some(row_area);
}
@@ -878,9 +884,9 @@ impl Table<'_> {
let selected_column_area = state.selected_column.and_then(|s| {
// The selection is clamped by the column count. Since a user can manually specify an
// incorrect number of widths, we should use panic free methods.
columns_widths.get(s).map(|(x, width)| Rect {
x: x + area.x,
width: *width,
columns_widths.get(s).map(|cell_area| Rect {
x: cell_area.x + area.x,
width: cell_area.width,
..area
})
});
@@ -902,6 +908,83 @@ impl Table<'_> {
}
}
/// Render cells into the columns of a row
///
/// Render `Cell`s from `cells` into columns specified by `column_widths`, stopping
/// if either of these iterators are finished. Each `Cell` gets rendered across
/// [`Cell::get_column_span`] columns plus the gaps between them, if this value is > 1.
fn render_row_cells(
&self,
buf: &mut Buffer,
column_widths: Vec<&Rect>,
cells: &Vec<Cell>,
row_area: Rect,
) {
let mut column_widths_iterator = column_widths.into_iter();
for current_cell in cells {
if let Some(cell_area) = Self::get_cell_area(
&mut column_widths_iterator,
current_cell.column_span,
self.column_spacing,
) {
let new_x = row_area.x + cell_area.x;
let area_to_render = Rect::new(new_x, row_area.y, cell_area.width, row_area.height);
current_cell.render(area_to_render, buf);
}
}
}
/// Set the row style and render the highlight symbol
fn set_selection_style(
&self,
buf: &mut Buffer,
selection_width: u16,
row_area: Rect,
row: &Row,
) {
let selection_area = Rect {
width: selection_width,
..row_area
};
buf.set_style(selection_area, row.style);
(&self.highlight_symbol).render(selection_area, buf);
}
/// Return the area that a [`Cell`] should occupy, taking into account its
/// [`Cell::column_span`].
///
/// Returns `None` when there are no more columns for the [`Cell`] to occupy.
///
/// Otherwise, returns `Some(Rect{x, y = 0, width, height = 0})`, representing the start
/// x-coordinate and width of the [`Cell`].
///
/// This function consumes `cell_column_span` `Rect`s from `column_widths_iterator` (or all the
/// `Rects` if the iterator is less than `cell_column_span` `Rect`s long). This function adds
/// the width of each `Rect` plus `column_spacing` to a running total of the final width. The
/// return value is the original x coordinate and the final width, or `None` if
/// `column_widths_iterator` is empty or `cell_column_span` is `0`.
fn get_cell_area<'a, T>(
column_widths_iterator: &mut T,
cell_column_span: u16,
column_spacing: u16,
) -> Option<Rect>
where
T: Iterator<Item = &'a Rect>,
{
if cell_column_span == 0 {
return None;
}
let first = column_widths_iterator.next()?;
let (n_columns_taken, all_columns_width) = column_widths_iterator
.take((cell_column_span - 1).into())
.map(|rect| (1, rect.width))
.fold((1, first.width), |so_far, next_column| {
(next_column.0 + so_far.0, next_column.1 + so_far.1)
});
let width = all_columns_width + (n_columns_taken - 1) * column_spacing;
Some(Rect::new(first.x, first.y, width, 1))
}
/// Return the indexes of the visible rows.
///
/// The algorithm works as follows:
@@ -960,7 +1043,7 @@ impl Table<'_> {
max_width: u16,
selection_width: u16,
col_count: usize,
) -> Vec<(u16, u16)> {
) -> Vec<Rect> {
let widths = if self.widths.is_empty() {
// Divide the space between each column equally
vec![Constraint::Length(max_width / col_count.max(1) as u16); col_count]
@@ -975,7 +1058,10 @@ impl Table<'_> {
.flex(self.flex)
.spacing(self.column_spacing)
.split(columns_area);
rects.iter().map(|c| (c.x, c.width)).collect()
rects
.iter()
.map(|c| Rect::new(c.x, 0, c.width, 1))
.collect()
}
fn column_count(&self) -> usize {
@@ -1352,6 +1438,101 @@ mod tests {
assert_eq!(buf, expected);
}
#[rstest]
#[case(15, 5, vec![
Row::new(vec![
Cell::new("Cell1").column_span(1),
Cell::new("Cell2").column_span(1),
]),
Row::new(vec![
Cell::new("Cell3").column_span(1),
Cell::new("Cell4").column_span(1),
]),
],
&Buffer::with_lines(["Cell1 Cell2 ", "Cell3 Cell4 "]))]
#[case(15, 5, vec![
Row::new(vec![
Cell::new("Cell1").column_span(0),
Cell::new("Cell2").column_span(1),
]),
Row::new(vec![
Cell::new("Cell3").column_span(1),
Cell::new("Cell4").column_span(1),
]),
], &Buffer::with_lines(["Cell2 ", "Cell3 Cell4 "]))]
#[case(15, 5, vec![
Row::new(vec![
Cell::new("Cell1").column_span(2),
Cell::new("Cell2").column_span(1),
]),
Row::new(vec![
Cell::new("Cell3").column_span(1),
Cell::new("Cell4").column_span(1),
]),
], &Buffer::with_lines(["Cell1 ", "Cell3 Cell4 "]))]
fn test_colspans_2_cols<'rows, Rows>(
#[case] width: u16,
#[case] column_width: u16,
#[case] rows: Rows,
#[case] expected: &Buffer,
) where
Rows: IntoIterator<Item = Row<'rows>>,
{
let mut buf = Buffer::empty(Rect::new(0, 0, width, 2));
let table = Table::new(rows, [Constraint::Length(column_width); 2]);
Widget::render(table, Rect::new(0, 0, width, 2), &mut buf);
assert_eq!(buf, *expected);
}
#[rstest]
#[case(17, 5, vec![
Row::new(vec![
Cell::new("Cell1").column_span(2),
Cell::new("Cell2").column_span(1),
]),
Row::new(vec![
Cell::new("Cell3").column_span(1),
Cell::new("Cell4").column_span(1),
Cell::new("Cell5").column_span(1),
]),
], &Buffer::with_lines(["Cell1 Cell2", "Cell3 Cell4 Cell5"]))]
#[case(17, 5, vec![
Row::new(vec![
Cell::new("Cell1").column_span(1),
Cell::new("Cell2").column_span(2),
Cell::new("Cell3").column_span(1),
]),
Row::new(vec![
Cell::new("Cell4").column_span(1),
Cell::new("Cell5").column_span(1),
Cell::new("Cell6").column_span(1),
]),
], &Buffer::with_lines(["Cell1 Cell2 ", "Cell4 Cell5 Cell6"]))]
#[case(15, 5, vec![
Row::new(vec![
Cell::new("11111111111111111111").column_span(2),
Cell::new("22222222222222222222").column_span(1),
]),
Row::new(vec![
Cell::new("33333333333333333333").column_span(1),
Cell::new("44444444444444444444").column_span(2),
Cell::new("55555555555555555555").column_span(1),
]),
], &Buffer::with_lines(["1111111111 2222", "3333 4444444444"]))]
fn test_colspans_3_cols<'rows, Rows>(
#[case] width: u16,
#[case] column_width: u16,
#[case] rows: Rows,
#[case] expected: &Buffer,
) where
Rows: IntoIterator<Item = Row<'rows>>,
{
let mut buf = Buffer::empty(Rect::new(0, 0, width, 2));
let table = Table::new(rows, [Constraint::Length(column_width); 3]);
Widget::render(table, Rect::new(0, 0, width, 2), &mut buf);
assert_eq!(buf, *expected);
}
#[test]
fn render_with_header() {
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 3));
@@ -1676,15 +1857,24 @@ mod tests {
fn length_constraint() {
// without selection, more than needed width
let table = Table::default().widths([Length(4), Length(4)]);
assert_eq!(table.get_column_widths(20, 0, 0), [(0, 4), (5, 4)]);
assert_eq!(
table.get_column_widths(20, 0, 0),
[Rect::new(0, 0, 4, 1), Rect::new(5, 0, 4, 1),]
);
// with selection, more than needed width
let table = Table::default().widths([Length(4), Length(4)]);
assert_eq!(table.get_column_widths(20, 3, 0), [(3, 4), (8, 4)]);
assert_eq!(
table.get_column_widths(20, 3, 0),
[Rect::new(3, 0, 4, 1), Rect::new(8, 0, 4, 1)]
);
// without selection, less than needed width
let table = Table::default().widths([Length(4), Length(4)]);
assert_eq!(table.get_column_widths(7, 0, 0), [(0, 3), (4, 3)]);
assert_eq!(
table.get_column_widths(7, 0, 0),
[Rect::new(0, 0, 3, 1), Rect::new(4, 0, 3, 1)]
);
// with selection, less than needed width
// <--------7px-------->
@@ -1693,26 +1883,41 @@ mod tests {
// └────────┘x└────────┘
// column spacing (i.e. `x`) is always prioritized
let table = Table::default().widths([Length(4), Length(4)]);
assert_eq!(table.get_column_widths(7, 3, 0), [(3, 2), (6, 1)]);
assert_eq!(
table.get_column_widths(7, 3, 0),
[Rect::new(3, 0, 2, 1), Rect::new(6, 0, 1, 1)]
);
}
#[test]
fn max_constraint() {
// without selection, more than needed width
let table = Table::default().widths([Max(4), Max(4)]);
assert_eq!(table.get_column_widths(20, 0, 0), [(0, 4), (5, 4)]);
assert_eq!(
table.get_column_widths(20, 0, 0),
[Rect::new(0, 0, 4, 1), Rect::new(5, 0, 4, 1)]
);
// with selection, more than needed width
let table = Table::default().widths([Max(4), Max(4)]);
assert_eq!(table.get_column_widths(20, 3, 0), [(3, 4), (8, 4)]);
assert_eq!(
table.get_column_widths(20, 3, 0),
[Rect::new(3, 0, 4, 1), Rect::new(8, 0, 4, 1)]
);
// without selection, less than needed width
let table = Table::default().widths([Max(4), Max(4)]);
assert_eq!(table.get_column_widths(7, 0, 0), [(0, 3), (4, 3)]);
assert_eq!(
table.get_column_widths(7, 0, 0),
[Rect::new(0, 0, 3, 1), Rect::new(4, 0, 3, 1)]
);
// with selection, less than needed width
let table = Table::default().widths([Max(4), Max(4)]);
assert_eq!(table.get_column_widths(7, 3, 0), [(3, 2), (6, 1)]);
assert_eq!(
table.get_column_widths(7, 3, 0),
[Rect::new(3, 0, 2, 1), Rect::new(6, 0, 1, 1)]
);
}
#[test]
@@ -1723,42 +1928,66 @@ mod tests {
// without selection, more than needed width
let table = Table::default().widths([Min(4), Min(4)]);
assert_eq!(table.get_column_widths(20, 0, 0), [(0, 10), (11, 9)]);
assert_eq!(
table.get_column_widths(20, 0, 0),
[Rect::new(0, 0, 10, 1), Rect::new(11, 0, 9, 1)]
);
// with selection, more than needed width
let table = Table::default().widths([Min(4), Min(4)]);
assert_eq!(table.get_column_widths(20, 3, 0), [(3, 8), (12, 8)]);
assert_eq!(
table.get_column_widths(20, 3, 0),
[Rect::new(3, 0, 8, 1), Rect::new(12, 0, 8, 1)]
);
// without selection, less than needed width
// allocates spacer
let table = Table::default().widths([Min(4), Min(4)]);
assert_eq!(table.get_column_widths(7, 0, 0), [(0, 3), (4, 3)]);
assert_eq!(
table.get_column_widths(7, 0, 0),
[Rect::new(0, 0, 3, 1), Rect::new(4, 0, 3, 1)]
);
// with selection, less than needed width
// always allocates selection and spacer
let table = Table::default().widths([Min(4), Min(4)]);
assert_eq!(table.get_column_widths(7, 3, 0), [(3, 2), (6, 1)]);
assert_eq!(
table.get_column_widths(7, 3, 0),
[Rect::new(3, 0, 2, 1), Rect::new(6, 0, 1, 1)]
);
}
#[test]
fn percentage_constraint() {
// without selection, more than needed width
let table = Table::default().widths([Percentage(30), Percentage(30)]);
assert_eq!(table.get_column_widths(20, 0, 0), [(0, 6), (7, 6)]);
assert_eq!(
table.get_column_widths(20, 0, 0),
[Rect::new(0, 0, 6, 1), Rect::new(7, 0, 6, 1)]
);
// with selection, more than needed width
let table = Table::default().widths([Percentage(30), Percentage(30)]);
assert_eq!(table.get_column_widths(20, 3, 0), [(3, 5), (9, 5)]);
assert_eq!(
table.get_column_widths(20, 3, 0),
[Rect::new(3, 0, 5, 1), Rect::new(9, 0, 5, 1)]
);
// without selection, less than needed width
// rounds from positions: [0.0, 0.0, 2.1, 3.1, 5.2, 7.0]
let table = Table::default().widths([Percentage(30), Percentage(30)]);
assert_eq!(table.get_column_widths(7, 0, 0), [(0, 2), (3, 2)]);
assert_eq!(
table.get_column_widths(7, 0, 0),
[Rect::new(0, 0, 2, 1), Rect::new(3, 0, 2, 1)]
);
// with selection, less than needed width
// rounds from positions: [0.0, 3.0, 5.1, 6.1, 7.0, 7.0]
let table = Table::default().widths([Percentage(30), Percentage(30)]);
assert_eq!(table.get_column_widths(7, 3, 0), [(3, 1), (5, 1)]);
assert_eq!(
table.get_column_widths(7, 3, 0),
[Rect::new(3, 0, 1, 1), Rect::new(5, 0, 1, 1)]
);
}
#[test]
@@ -1766,22 +1995,34 @@ mod tests {
// without selection, more than needed width
// rounds from positions: [0.00, 0.00, 6.67, 7.67, 14.33]
let table = Table::default().widths([Ratio(1, 3), Ratio(1, 3)]);
assert_eq!(table.get_column_widths(20, 0, 0), [(0, 7), (8, 6)]);
assert_eq!(
table.get_column_widths(20, 0, 0),
[Rect::new(0, 0, 7, 1), Rect::new(8, 0, 6, 1)]
);
// with selection, more than needed width
// rounds from positions: [0.00, 3.00, 10.67, 17.33, 20.00]
let table = Table::default().widths([Ratio(1, 3), Ratio(1, 3)]);
assert_eq!(table.get_column_widths(20, 3, 0), [(3, 6), (10, 5)]);
assert_eq!(
table.get_column_widths(20, 3, 0),
[Rect::new(3, 0, 6, 1), Rect::new(10, 0, 5, 1)]
);
// without selection, less than needed width
// rounds from positions: [0.00, 2.33, 3.33, 5.66, 7.00]
let table = Table::default().widths([Ratio(1, 3), Ratio(1, 3)]);
assert_eq!(table.get_column_widths(7, 0, 0), [(0, 2), (3, 3)]);
assert_eq!(
table.get_column_widths(7, 0, 0),
[Rect::new(0, 0, 2, 1), Rect::new(3, 0, 3, 1)]
);
// with selection, less than needed width
// rounds from positions: [0.00, 3.00, 5.33, 6.33, 7.00, 7.00]
let table = Table::default().widths([Ratio(1, 3), Ratio(1, 3)]);
assert_eq!(table.get_column_widths(7, 3, 0), [(3, 1), (5, 2)]);
assert_eq!(
table.get_column_widths(7, 3, 0),
[Rect::new(3, 0, 1, 1), Rect::new(5, 0, 2, 1)]
);
}
/// When more width is available than requested, the behavior is controlled by flex
@@ -1790,7 +2031,11 @@ mod tests {
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
assert_eq!(
table.get_column_widths(62, 0, 0),
&[(0, 20), (21, 20), (42, 20)]
&[
Rect::new(0, 0, 20, 1),
Rect::new(21, 0, 20, 1),
Rect::new(42, 0, 20, 1)
]
);
let table = Table::default()
@@ -1798,7 +2043,11 @@ mod tests {
.flex(Flex::Legacy);
assert_eq!(
table.get_column_widths(62, 0, 0),
&[(0, 10), (11, 10), (22, 40)]
&[
Rect::new(0, 0, 10, 1),
Rect::new(11, 0, 10, 1),
Rect::new(22, 0, 40, 1)
]
);
let table = Table::default()
@@ -1806,7 +2055,11 @@ mod tests {
.flex(Flex::SpaceBetween);
assert_eq!(
table.get_column_widths(62, 0, 0),
&[(0, 20), (21, 20), (42, 20)]
&[
Rect::new(0, 0, 20, 1),
Rect::new(21, 0, 20, 1),
Rect::new(42, 0, 20, 1)
]
);
}
@@ -1815,7 +2068,11 @@ mod tests {
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
assert_eq!(
table.get_column_widths(62, 0, 0),
&[(0, 20), (21, 20), (42, 20)]
&[
Rect::new(0, 0, 20, 1),
Rect::new(21, 0, 20, 1),
Rect::new(42, 0, 20, 1)
]
);
let table = Table::default()
@@ -1823,7 +2080,11 @@ mod tests {
.flex(Flex::Legacy);
assert_eq!(
table.get_column_widths(62, 0, 0),
&[(0, 10), (11, 10), (22, 40)]
&[
Rect::new(0, 0, 10, 1),
Rect::new(11, 0, 10, 1),
Rect::new(22, 0, 40, 1)
]
);
}
@@ -1840,7 +2101,11 @@ mod tests {
.column_spacing(0);
assert_eq!(
table.get_column_widths(30, 0, 3),
&[(0, 10), (10, 10), (20, 10)]
&[
Rect::new(0, 0, 10, 1),
Rect::new(10, 0, 10, 1),
Rect::new(20, 0, 10, 1)
]
);
}
@@ -1850,7 +2115,10 @@ mod tests {
.rows(vec![])
.header(Row::new(vec!["f", "g"]))
.column_spacing(0);
assert_eq!(table.get_column_widths(10, 0, 2), [(0, 5), (5, 5)]);
assert_eq!(
table.get_column_widths(10, 0, 2),
[Rect::new(0, 0, 5, 1), Rect::new(5, 0, 5, 1)]
);
}
#[test]
@@ -1859,7 +2127,10 @@ mod tests {
.rows(vec![])
.footer(Row::new(vec!["h", "i"]))
.column_spacing(0);
assert_eq!(table.get_column_widths(10, 0, 2), [(0, 5), (5, 5)]);
assert_eq!(
table.get_column_widths(10, 0, 2),
[Rect::new(0, 0, 5, 1), Rect::new(5, 0, 5, 1)]
);
}
#[track_caller]
@@ -2302,4 +2573,145 @@ mod tests {
// This should not panic, even if the buffer has zero size.
Widget::render(table, buffer.area, &mut buffer);
}
#[test]
fn get_area_for_column_span_one_no_more_columns() {
let columns = [];
let column_span = Table::get_cell_area(&mut columns.iter(), 1, 1);
assert!(column_span.is_none());
}
#[test]
fn get_area_for_column_span_two_no_more_columns() {
let columns = [];
let column_span = Table::get_cell_area(&mut columns.iter(), 2, 1);
assert!(column_span.is_none());
}
#[rstest]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}], 2, 5)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}], 2, 5,)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}], 1, 2)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}], 3, 5)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}], 1, 2)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}], 2, 2)]
#[case(&[
Rect{x: 3, width: 2, y: 0, height: 1},
Rect{x: 3, width: 2, y: 0, height: 1},
Rect{x: 3, width: 2, y: 0, height: 1},
Rect{x: 3, width: 2, y: 0, height: 1},
], 3, 8)]
#[case(&[
Rect{x: 3, width: 2, y: 0, height: 1},
Rect{x: 3, width: 2, y: 0, height: 1},
Rect{x: 3, width: 2, y: 0, height: 1},
], 3, 8)]
fn test_colspan_width_single_column_spacing(
#[case] columns: &[Rect],
#[case] column_span: u16,
#[case] expected_column_width: u16,
) {
let column_span = Table::get_cell_area(&mut columns.iter(), column_span, 1);
assert!(column_span.is_some());
assert_eq!(column_span.unwrap().width, expected_column_width);
}
#[rstest]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}, Rect{x: 3, width: 2, y: 0, height: 1}], 3, 10)]
#[case(&[Rect{x: 3, width: 2, y: 0, height: 1}], 3, 2)]
fn test_colspan_width_two_column_spacing(
#[case] columns: &[Rect],
#[case] column_span: u16,
#[case] expected_column_width: u16,
) {
let column_span = Table::get_cell_area(&mut columns.iter(), column_span, 2);
assert!(column_span.is_some());
assert_eq!(column_span.unwrap().width, expected_column_width);
}
#[rstest]
#[case(
HighlightSpacing::Always,
15, // width
1, // spacing
None, // selection
[
Cell::new("ABCDEFGHIJK").column_span(2),
Cell::new("12345678901"),
Cell::new("XYZXYZXYZXY"),
],
[
" ABCDEFGH 123",
" ", // row 2
" ", // row 3
])]
#[case(
HighlightSpacing::Always,
15, // width
1, // spacing
Some(0), // selection
[
Cell::new("ABCDEFGHIJK").column_span(2),
Cell::new("12345678901"),
Cell::new("XYZXYZXYZXY"),
],
[
">>>ABCDEFGH 123",
" ", // row 2
" ", // row 3
])]
#[case(
HighlightSpacing::WhenSelected,
15, // width
1, // spacing
None, // selection
[
Cell::new("ABCDEFGHIJK").column_span(2),
Cell::new("12345678901"),
Cell::new("XYZXYZXYZXY"),
],
[
"ABCDEFGHIJ 1234",
" ", // row 2
" ", // row 3
])]
#[case(
HighlightSpacing::WhenSelected,
15, // width
1, // spacing
Some(0), // selection
[
Cell::new("ABCDEFGHIJK").column_span(2),
Cell::new("12345678901"),
Cell::new("XYZXYZXYZXY"),
],
[
">>>ABCDEFGH 123",
" ", // row 2
" ", // row 3
])]
fn test_table_with_selection_and_column_spans<'line, 'cell, Lines, Cells>(
#[case] highlight_spacing: HighlightSpacing,
#[case] columns: u16,
#[case] spacing: u16,
#[case] selection: Option<usize>,
#[case] cells: Cells,
#[case] expected: Lines,
) where
Cells: IntoIterator,
Cells::Item: Into<Cell<'cell>>,
Lines: IntoIterator,
Lines::Item: Into<Line<'line>>,
{
let table = Table::default()
.rows(vec![Row::new(cells)])
.highlight_spacing(highlight_spacing)
.highlight_symbol(">>>")
.column_spacing(spacing);
let area = Rect::new(0, 0, columns, 3);
let mut buf = Buffer::empty(area);
let mut state = TableState::default().with_selected(selection);
StatefulWidget::render(table, area, &mut buf, &mut state);
assert_eq!(buf, Buffer::with_lines(expected));
}
}

View File

@@ -51,6 +51,8 @@ use ratatui_core::widgets::Widget;
pub struct Cell<'a> {
content: Text<'a>,
style: Style,
/// The number of columns this cell will extend over
pub(crate) column_span: u16,
}
impl<'a> Cell<'a> {
@@ -80,6 +82,7 @@ impl<'a> Cell<'a> {
Self {
content: content.into(),
style: Style::default(),
column_span: 1,
}
}
@@ -113,6 +116,26 @@ impl<'a> Cell<'a> {
self
}
/// Set the `column_span` of this cell
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// # Example
/// ```rust
/// use ratatui::widgets::{Cell, Row};
/// let rows = vec![
/// Row::new(vec![Cell::new("12345").column_span(2)]),
/// Row::new(vec![Cell::new("xx"), Cell::new("yy")]),
/// ];
/// // "12345",
/// // "xx yy",
/// ```
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn column_span(mut self, column_span: u16) -> Self {
self.column_span = column_span;
self
}
/// Set the `Style` of this cell
///
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
@@ -167,6 +190,7 @@ where
Self {
content: content.into(),
style: Style::default(),
column_span: 1,
}
}
}

View File

@@ -1,7 +1,7 @@
[package]
name = "ratatui"
description = "A library that's all about cooking up terminal user interfaces"
version = "0.30.0-beta.0"
version = "0.30.0"
authors.workspace = true
documentation.workspace = true
repository.workspace = true
@@ -32,6 +32,10 @@ default = ["crossterm", "underline-color", "all-widgets", "macros", "layout-cach
#! Generally an application will only use one backend, so you should only enable one of the following features:
## enables the [`CrosstermBackend`](backend::CrosstermBackend) backend and adds a dependency on [`crossterm`].
crossterm = ["std", "dep:ratatui-crossterm"]
## selects the crossterm 0.28.x backend implementation
crossterm_0_28 = ["crossterm", "ratatui-crossterm/crossterm_0_28"]
## selects the crossterm 0.29.x backend implementation (default)
crossterm_0_29 = ["crossterm", "ratatui-crossterm/crossterm_0_29"]
## enables the [`TermionBackend`](backend::TermionBackend) backend and adds a dependency on [`termion`].
termion = ["std", "dep:ratatui-termion"]
## enables the [`TermwizBackend`](backend::TermwizBackend) backend and adds a dependency on [`termwiz`].

View File

@@ -3,6 +3,7 @@ pub mod main {
pub mod block;
pub mod buffer;
pub mod constraints;
pub mod gauge;
pub mod line;
pub mod list;
pub mod paragraph;
@@ -25,4 +26,5 @@ criterion::criterion_main!(
table::benches,
text::benches,
constraints::benches,
gauge::benches,
);

View File

@@ -52,7 +52,7 @@ fn barchart(c: &mut Criterion) {
group.finish();
}
/// Render the widget in a classical size buffer
/// Render the widget in a classical size buffer.
fn render(bencher: &mut Bencher, barchart: &BarChart) {
let mut buffer = Buffer::empty(Rect::new(0, 0, 200, 50));
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -36,7 +36,7 @@ fn block(c: &mut Criterion) {
group.finish();
}
/// render the block into a buffer of the given `size`
/// Render the block into a buffer of the given `size`.
fn render(bencher: &mut Bencher, block: &Block, size: Rect) {
let mut buffer = Buffer::empty(size);
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -0,0 +1,58 @@
use criterion::{BatchSize, Criterion, criterion_group};
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::widgets::{Block, Gauge, Widget};
/// Benchmark for rendering a gauge.
fn gauge(c: &mut Criterion) {
let mut group = c.benchmark_group("gauge");
let (width, height) = (200, 50); // 1080p fullscreen with medium font
let buffer_size = Rect::new(0, 0, width, height);
// Render an empty gauge
group.bench_with_input(
format!("render_empty/{width}x{height}"),
&Gauge::default(),
|b, gauge| {
let mut buffer = Buffer::empty(buffer_size);
// We use `iter_batched` to clone the value in the setup function because
// `Widget::render` consumes the widget.
b.iter_batched(
|| gauge.to_owned(),
|bench_gauge| {
bench_gauge.render(buffer.area, &mut buffer);
},
BatchSize::SmallInput,
);
},
);
// Render with all features
group.bench_with_input(
format!("render_all_feature/{width}x{height}"),
&Gauge::default()
.block(Block::bordered().title("Progress"))
.gauge_style(Style::new().white().on_black().italic())
.percent(20)
.label("20%")
.use_unicode(true),
|b, gauge| {
let mut buffer = Buffer::empty(buffer_size);
// We use `iter_batched` to clone the value in the setup function because
// `Widget::render` consumes the widget.
b.iter_batched(
|| gauge.to_owned(),
|bench_gauge| {
bench_gauge.render(buffer.area, &mut buffer);
},
BatchSize::SmallInput,
);
},
);
group.finish();
}
criterion_group!(benches, gauge);

View File

@@ -39,7 +39,7 @@ fn list(c: &mut Criterion) {
group.finish();
}
/// render the list into a common size buffer
/// Render the list into a common size buffer.
fn render(bencher: &mut Bencher, list: &List) {
let mut buffer = Buffer::empty(Rect::new(0, 0, 200, 50));
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -67,7 +67,7 @@ fn paragraph(c: &mut Criterion) {
group.finish();
}
/// render the paragraph into a buffer with the given width
/// Render the paragraph into a buffer with the given width.
fn render(bencher: &mut Bencher, paragraph: &Paragraph, width: u16) {
let mut buffer = Buffer::empty(Rect::new(0, 0, width, PARAGRAPH_DEFAULT_HEIGHT));
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -25,7 +25,7 @@ fn sparkline(c: &mut Criterion) {
group.finish();
}
/// render the block into a buffer of the given `size`
/// Render the block into a buffer of the given `size`.
fn render(bencher: &mut Bencher, sparkline: &Sparkline) {
let mut buffer = Buffer::empty(Rect::new(0, 0, 200, 50));
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -46,7 +46,7 @@ fn text(c: &mut Criterion) {
group.finish();
}
/// Renders the text into a buffer of the given `size`
/// Render the text into a buffer of the given `size`.
fn render(bencher: &mut Bencher, text: &Text, size: Rect) {
let mut buffer = Buffer::empty(size);
// We use `iter_batched` to clone the value in the setup function.

View File

@@ -616,6 +616,9 @@
//! library `no_std` compatible. This is often easier than you might expect and broadens the range
//! of projects that can use your widgets.
//!
//! For more detail on advantages of this, maintenance tips and feature flags, see the
//! [no-std concept guide].
//!
//! To implement `no_std` compatibility, add the `#![no_std]` attribute at the top of your `lib.rs`.
//! When working in a `no_std` environment, you'll need to make a few adjustments:
//!
@@ -658,6 +661,7 @@
//! straightforward to implement
//!
//! [`ratatui-core`]: https://crates.io/crates/ratatui-core
//! [no-std concept guide]: https://ratatui.rs/concepts/no-std/
pub use ratatui_core::widgets::{StatefulWidget, Widget};
pub use ratatui_widgets::barchart::{Bar, BarChart, BarGroup};

View File

@@ -2,6 +2,7 @@
[default.extend-words]
ratatui = "ratatui"
sectore = "sectore" # https://github.com/sectore
[type.md]
extend-ignore-re = [