2025-07-07 15:22:29 +00:00

208 lines
41 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-Developers/ARCHITECTURE" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v3.8.1">
<title data-rh="true">Architecture Documentation | Television</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:image" content="https://alexpasmantier.github.io/television/img/tv-social.png"><meta data-rh="true" name="twitter:image" content="https://alexpasmantier.github.io/television/img/tv-social.png"><meta data-rh="true" property="og:url" content="https://alexpasmantier.github.io/television/docs/Developers/ARCHITECTURE"><meta data-rh="true" property="og:locale" content="en"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Architecture Documentation | Television"><meta data-rh="true" name="description" content="NOTE: what follows has mostly been assembled using AI as an experiment and as a basis for further improvements. @lalvarezt and I (@alexpasmantier) have been proofreading it to make sure all the information is technically correct and really reflects the code&#x27;s architecture, so that **other developers may rely on it as a technical source of truth** when getting started with the repo."><meta data-rh="true" property="og:description" content="NOTE: what follows has mostly been assembled using AI as an experiment and as a basis for further improvements. @lalvarezt and I (@alexpasmantier) have been proofreading it to make sure all the information is technically correct and really reflects the code&#x27;s architecture, so that **other developers may rely on it as a technical source of truth** when getting started with the repo."><link data-rh="true" rel="icon" href="/television/img/tv-icon-150.png"><link data-rh="true" rel="canonical" href="https://alexpasmantier.github.io/television/docs/Developers/ARCHITECTURE"><link data-rh="true" rel="alternate" href="https://alexpasmantier.github.io/television/docs/Developers/ARCHITECTURE" hreflang="en"><link data-rh="true" rel="alternate" href="https://alexpasmantier.github.io/television/docs/Developers/ARCHITECTURE" hreflang="x-default"><script data-rh="true" type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Architecture Documentation","item":"https://alexpasmantier.github.io/television/docs/Developers/ARCHITECTURE"}]}</script><link rel="stylesheet" href="/television/assets/css/styles.8c19fd57.css">
<script src="/television/assets/js/runtime~main.0f61a7f8.js" defer="defer"></script>
<script src="/television/assets/js/main.253b8c54.js" defer="defer"></script>
</head>
<body class="navigation-with-keyboard">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><defs>
<symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"/></symbol>
</defs></svg>
<script>!function(){var t="dark";var e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();document.documentElement.setAttribute("data-theme",e||t),document.documentElement.setAttribute("data-theme-choice",e||t)}(),function(){try{const c=new URLSearchParams(window.location.search).entries();for(var[t,e]of c)if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id="__docusaurus"><link rel="preload" as="image" href="/television/img/tv-icon-80.png"><div role="region" aria-label="Skip to main content"><a class="skipToContent_nod4" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="theme-layout-navbar navbar navbar--fixed-top"><div class="navbar__inner"><div class="theme-layout-navbar-left navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/television/"><div class="navbar__logo"><img src="/television/img/tv-icon-80.png" alt="Television Logo" class="themedComponent_rgZj themedComponent--light_hdxy"><img src="/television/img/tv-icon-80.png" alt="Television Logo" class="themedComponent_rgZj themedComponent--dark_Iwy7"></div><b class="navbar__title text--truncate">Television</b></a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/television/docs/Users/installation">docs</a><a href="https://github.com/alexpasmantier/television/releases" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">releases<svg width="13.5" height="13.5" aria-hidden="true" class="iconExternalLink_dOts"><use href="#theme-svg-external-link"></use></svg></a><a href="https://crates.io/crates/television" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">crates.io<svg width="13.5" height="13.5" aria-hidden="true" class="iconExternalLink_dOts"><use href="#theme-svg-external-link"></use></svg></a></div><div class="theme-layout-navbar-right navbar__items navbar__items--right"><a href="https://github.com/alexpasmantier/television" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">GitHub<svg width="13.5" height="13.5" aria-hidden="true" class="iconExternalLink_dOts"><use href="#theme-svg-external-link"></use></svg></a><div class="navbarSearchContainer_VxOy"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="theme-layout-main main-wrapper mainWrapper_HR2q"><div class="docsWrapper_uElw"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_IzB1" type="button"></button><div class="docRoot_MWdD"><aside class="theme-doc-sidebar-container docSidebarContainer_AJtF"><div class="sidebarViewport_usFm"><div class="sidebar_HC93"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_BnDX"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" role="button" aria-expanded="false" href="/television/docs/Users/installation">Users</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret menu__link--active" role="button" aria-expanded="true" href="/television/docs/Developers/ARCHITECTURE">Developers</a></div><ul class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/television/docs/Developers/ARCHITECTURE">Architecture Documentation</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/television/docs/Developers/ui-features">UI Features documentation</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/television/docs/Developers/patch-notes">Patch notes</a></li></ul></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_I1Io"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_KwG0"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></div></aside><main class="docMainContainer_yFTf"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_QLDD"><div class="docItemContainer_Hqnr"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_eD4m" aria-label="Breadcrumbs"><ul class="breadcrumbs"><li class="breadcrumbs__item"><a aria-label="Home page" class="breadcrumbs__link" href="/television/"><svg viewBox="0 0 24 24" class="breadcrumbHomeIcon_YhwE"><path d="M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z" fill="currentColor"></path></svg></a></li><li class="breadcrumbs__item"><span class="breadcrumbs__link">Developers</span></li><li class="breadcrumbs__item breadcrumbs__item--active"><span class="breadcrumbs__link">Architecture Documentation</span></li></ul></nav><div class="tocCollapsible_Qf8d theme-doc-toc-mobile tocMobile_mt20"><button type="button" class="clean-btn tocCollapsibleButton_Hr9f">On this page</button></div><div class="theme-doc-markdown markdown"><header><h1>Architecture Documentation</h1></header>
<p><em>NOTE: what follows has mostly been assembled using AI as an experiment and as a basis for further improvements. @lalvarezt and I (@alexpasmantier) have been proofreading it to make sure all the information is technically correct and really reflects the code&#x27;s architecture, so that <strong>other developers may rely on it as a technical source of truth</strong> when getting started with the repo.</em></p>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="overview">Overview<a href="#overview" class="hash-link" aria-label="Direct link to Overview" title="Direct link to Overview"></a></h2>
<p>Television is a terminal fuzzy finder built with Rust. It uses async/await and separate loops for event handling, rendering, and background tasks to stay responsive.</p>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="high-level-architecture">High-Level Architecture<a href="#high-level-architecture" class="hash-link" aria-label="Direct link to High-Level Architecture" title="Direct link to High-Level Architecture"></a></h2>
<div class="language-text codeBlockContainer_MbdR theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_WPSJ"><pre tabindex="0" class="prism-code language-text codeBlock_ke8T thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_oe7S"><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ┌──────────────┐ ┌──────────────┐ ┌─────────────┐</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ CLI &amp; Config │───►│ Application │───►│ Output │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ │ │ Orchestrator │ │ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> └──────────────┘ └──────────────┘ └─────────────┘</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ┌─────────────────────────────────────────────────┐</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ Event Loops │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ │ Event Loop │ │ Render Loop │ │ Watch Timer │ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ └─────────────┘ └─────────────┘ └─────────────┘ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> └─────────────────────────────────────────────────┘</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ┌─────────────────────────────────────────────────┐</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ Core Components │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ │ Television │ │ Channels │ │ Previewer │ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ │ (State) │ │ (Sources) │ │ │ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> │ └─────────────┘ └─────────────┘ └─────────────┘ │</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> └─────────────────────────────────────────────────┘</span><br></span></code></pre></div></div>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="how-it-works">How It Works<a href="#how-it-works" class="hash-link" aria-label="Direct link to How It Works" title="Direct link to How It Works"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="1-startup">1. Startup<a href="#1-startup" class="hash-link" aria-label="Direct link to 1. Startup" title="Direct link to 1. Startup"></a></h3>
<!-- -->
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="2-runtime-event-flow">2. Runtime Event Flow<a href="#2-runtime-event-flow" class="hash-link" aria-label="Direct link to 2. Runtime Event Flow" title="Direct link to 2. Runtime Event Flow"></a></h3>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="core-components">Core Components<a href="#core-components" class="hash-link" aria-label="Direct link to Core Components" title="Direct link to Core Components"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="application-orchestrator-apprs">Application Orchestrator (<code>app.rs</code>)<a href="#application-orchestrator-apprs" class="hash-link" aria-label="Direct link to application-orchestrator-apprs" title="Direct link to application-orchestrator-apprs"></a></h3>
<!-- -->
<p>The main app that coordinates everything:</p>
<ul>
<li>
<p><strong>What it does:</strong></p>
<ul>
<li>Manages app state and lifecycle</li>
<li>Routes messages between loops using async channels</li>
<li>Handles actions and state changes</li>
<li>Starts and stops components</li>
</ul>
</li>
<li>
<p><strong>Key channels:</strong></p>
<ul>
<li><code>action_tx/rx</code>: Actions from events to main loop</li>
<li><code>render_tx/rx</code>: Rendering tasks to render loop</li>
<li><code>event_rx</code>: Events from event loop</li>
<li><code>ui_state_tx/rx</code>: UI state feedback from render loop</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="event-system">Event System<a href="#event-system" class="hash-link" aria-label="Direct link to Event System" title="Direct link to Event System"></a></h3>
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="event-loop-loopsevent_looprs">Event Loop (<code>loops/event_loop.rs</code>)<a href="#event-loop-loopsevent_looprs" class="hash-link" aria-label="Direct link to event-loop-loopsevent_looprs" title="Direct link to event-loop-loopsevent_looprs"></a></h4>
<!-- -->
<ul>
<li><strong>Purpose:</strong> Handles keyboard input, mouse events, and system signals</li>
<li><strong>Input:</strong> Key presses, mouse clicks, terminal resize, Ctrl+C</li>
<li><strong>Output:</strong> Events sent to main loop</li>
<li><strong>Features:</strong>
<ul>
<li>Non-blocking event reading</li>
<li>Clean shutdown handling</li>
<li>Regular ticks for animations</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="actions-actionrs">Actions (<code>action.rs</code>)<a href="#actions-actionrs" class="hash-link" aria-label="Direct link to actions-actionrs" title="Direct link to actions-actionrs"></a></h4>
<p>All user interactions become actions:</p>
<div class="language-rust codeBlockContainer_MbdR theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_WPSJ"><pre tabindex="0" class="prism-code language-rust codeBlock_ke8T thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_oe7S"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">pub</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">enum</span><span class="token plain"> </span><span class="token type-definition class-name">Action</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">// Input actions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">AddInputChar</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">char</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">DeletePrevChar</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">// Navigation actions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">SelectNextEntry</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">SelectPrevEntry</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">// Application actions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">ConfirmSelection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">ToggleRemoteControl</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">Render</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token comment" style="color:rgb(98, 114, 164)">// System actions</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">Resize</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">u16</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">u16</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> </span><span class="token class-name">Quit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="television-core-televisionrs">Television Core (<code>television.rs</code>)<a href="#television-core-televisionrs" class="hash-link" aria-label="Direct link to television-core-televisionrs" title="Direct link to television-core-televisionrs"></a></h3>
<p>The main state manager:</p>
<ul>
<li>
<p><strong>What it tracks:</strong></p>
<ul>
<li>Current mode (Channel vs RemoteControl)</li>
<li>Search pattern and matching settings</li>
<li>Selected entries and picker state</li>
<li>Preview state and handles</li>
</ul>
</li>
<li>
<p><strong>What it does:</strong></p>
<ul>
<li>Pattern matching and filtering</li>
<li>Entry selection and multi-selection</li>
<li>Channel switching and mode changes</li>
<li>Preview coordination</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="channel-system">Channel System<a href="#channel-system" class="hash-link" aria-label="Direct link to Channel System" title="Direct link to Channel System"></a></h3>
<!-- -->
<!-- -->
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="channel-config-channelsprototypes">Channel Config (<code>channels/prototypes/</code>)<a href="#channel-config-channelsprototypes" class="hash-link" aria-label="Direct link to channel-config-channelsprototypes" title="Direct link to channel-config-channelsprototypes"></a></h4>
<p>Channels are defined in TOML files:</p>
<div class="language-toml codeBlockContainer_MbdR theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_WPSJ"><pre tabindex="0" class="prism-code language-toml codeBlock_ke8T thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_oe7S"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">metadata</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">name</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;files&quot;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">description</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;File finder&quot;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">source</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">command</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;fd -t f&quot;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">preview</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">command</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;bat --color=always &#x27;{}&#x27;&quot;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">ui</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">preview_panel</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token key property">size</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token number">70</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token table class-name">keybindings</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key property">shortcut</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">&quot;f1&quot;</span><br></span></code></pre></div></div>
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="channel-runtime-channelschannelrs">Channel Runtime (<code>channels/channel.rs</code>)<a href="#channel-runtime-channelschannelrs" class="hash-link" aria-label="Direct link to channel-runtime-channelschannelrs" title="Direct link to channel-runtime-channelschannelrs"></a></h4>
<ul>
<li><strong>Purpose:</strong> Run source commands and manage results</li>
<li><strong>Features:</strong>
<ul>
<li>Async command execution with streaming results</li>
<li>Fuzzy matching with nucleo</li>
<li>Reload with debouncing</li>
<li>Multiple source commands</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="rendering-system">Rendering System<a href="#rendering-system" class="hash-link" aria-label="Direct link to Rendering System" title="Direct link to Rendering System"></a></h3>
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="render-loop-loopsrender_looprs">Render Loop (<code>loops/render_loop.rs</code>)<a href="#render-loop-loopsrender_looprs" class="hash-link" aria-label="Direct link to render-loop-loopsrender_looprs" title="Direct link to render-loop-loopsrender_looprs"></a></h4>
<ul>
<li><strong>Purpose:</strong> Update the UI without blocking the main loop</li>
<li><strong>Input:</strong> Rendering tasks via channel</li>
<li><strong>Output:</strong> Terminal updates and UI state feedback</li>
<li><strong>Features:</strong>
<ul>
<li>60 FPS frame rate capping to avoid CPU hogging</li>
<li>Synchronized terminal updates</li>
<li>Layout state tracking</li>
</ul>
</li>
</ul>
<h4 class="anchor anchorWithStickyNavbar_Fogf" id="drawing-drawrs">Drawing (<code>draw.rs</code>)<a href="#drawing-drawrs" class="hash-link" aria-label="Direct link to drawing-drawrs" title="Direct link to drawing-drawrs"></a></h4>
<ul>
<li><strong>Purpose:</strong> Coordinate UI component rendering</li>
<li><strong>Components:</strong>
<ul>
<li>Input box with cursor</li>
<li>Results list with selection</li>
<li>Preview panel with content</li>
<li>Status bar with info</li>
<li>Remote control panel</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="configuration-system">Configuration System<a href="#configuration-system" class="hash-link" aria-label="Direct link to Configuration System" title="Direct link to Configuration System"></a></h3>
<!-- -->
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="preview-system-previewer">Preview System (<code>previewer/</code>)<a href="#preview-system-previewer" class="hash-link" aria-label="Direct link to preview-system-previewer" title="Direct link to preview-system-previewer"></a></h3>
<!-- -->
<ul>
<li><strong>How it works:</strong> Separate async task for non-blocking previews</li>
<li><strong>Communication:</strong> Request/response via channels</li>
<li><strong>Features:</strong>
<ul>
<li>Command-based preview generation</li>
<li>Caching and debouncing</li>
<li>Error handling and fallbacks</li>
<li>Syntax highlighting support</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="watch-timer-loopswatch_timerrs">Watch Timer (<code>loops/watch_timer.rs</code>)<a href="#watch-timer-loopswatch_timerrs" class="hash-link" aria-label="Direct link to watch-timer-loopswatch_timerrs" title="Direct link to watch-timer-loopswatch_timerrs"></a></h3>
<ul>
<li><strong>Purpose:</strong> Automatically reload channels</li>
<li><strong>Features:</strong>
<ul>
<li>Configurable intervals per channel</li>
<li>Auto start/stop on channel switch</li>
<li>Handles missed ticks</li>
</ul>
</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="communication">Communication<a href="#communication" class="hash-link" aria-label="Direct link to Communication" title="Direct link to Communication"></a></h2>
<!-- -->
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="data-flow">Data Flow<a href="#data-flow" class="hash-link" aria-label="Direct link to Data Flow" title="Direct link to Data Flow"></a></h3>
<ul>
<li><strong>One direction:</strong> Events → Actions → State changes → Render</li>
<li><strong>Feedback:</strong> UI state info flows back for optimization</li>
<li><strong>Async:</strong> All blocking operations happen in separate tasks</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="design-patterns">Design Patterns<a href="#design-patterns" class="hash-link" aria-label="Direct link to Design Patterns" title="Direct link to Design Patterns"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="1-actor-model">1. Actor Model<a href="#1-actor-model" class="hash-link" aria-label="Direct link to 1. Actor Model" title="Direct link to 1. Actor Model"></a></h3>
<p>Each major component runs independently and communicates via messages.</p>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="2-command-pattern">2. Command Pattern<a href="#2-command-pattern" class="hash-link" aria-label="Direct link to 2. Command Pattern" title="Direct link to 2. Command Pattern"></a></h3>
<p>All user interactions become Action enums.</p>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="3-observer-pattern">3. Observer Pattern<a href="#3-observer-pattern" class="hash-link" aria-label="Direct link to 3. Observer Pattern" title="Direct link to 3. Observer Pattern"></a></h3>
<p>UI state changes automatically trigger rendering updates.</p>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="4-plugin-architecture">4. Plugin Architecture<a href="#4-plugin-architecture" class="hash-link" aria-label="Direct link to 4. Plugin Architecture" title="Direct link to 4. Plugin Architecture"></a></h3>
<p>Channels are dynamically loaded from TOML config files.</p>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="performance">Performance<a href="#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance"></a></h2>
<ul>
<li><strong>Event Processing:</strong> Non-blocking with batched processing</li>
<li><strong>Rendering:</strong> Capped at 60 FPS with dirty state tracking</li>
<li><strong>Matching:</strong> Incremental fuzzy matching with nucleo</li>
<li><strong>Preview:</strong> Async with caching and debouncing</li>
<li><strong>Memory:</strong> Bounded result sets with efficient data structures</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_Fogf" id="how-to-extend">How to Extend<a href="#how-to-extend" class="hash-link" aria-label="Direct link to How to Extend" title="Direct link to How to Extend"></a></h2>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="adding-new-channels">Adding New Channels<a href="#adding-new-channels" class="hash-link" aria-label="Direct link to Adding New Channels" title="Direct link to Adding New Channels"></a></h3>
<ol>
<li>Create TOML config file</li>
<li>Define source command and output format</li>
<li>Add preview command and UI settings (optional)</li>
<li>Put in cable directory</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="custom-keybindings">Custom Keybindings<a href="#custom-keybindings" class="hash-link" aria-label="Direct link to Custom Keybindings" title="Direct link to Custom Keybindings"></a></h3>
<ul>
<li>Global keybindings in main config</li>
<li>Channel-specific keybindings in channel config</li>
<li>Runtime updates via remote control</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_Fogf" id="ui-themes">UI Themes<a href="#ui-themes" class="hash-link" aria-label="Direct link to UI Themes" title="Direct link to UI Themes"></a></h3>
<ul>
<li>Color scheme definitions in theme files</li>
<li>Component-specific styling</li>
<li>Runtime theme switching</li>
</ul>
<p>This architecture keeps things modular and fast, with clear separation between components and efficient async communication.</p></div></article><nav class="docusaurus-mt-lg pagination-nav" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/television/docs/Users/showcase"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Showcase</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/television/docs/Developers/ui-features"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">UI Features documentation</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_sLnf thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#overview" class="table-of-contents__link toc-highlight">Overview</a></li><li><a href="#high-level-architecture" class="table-of-contents__link toc-highlight">High-Level Architecture</a></li><li><a href="#how-it-works" class="table-of-contents__link toc-highlight">How It Works</a><ul><li><a href="#1-startup" class="table-of-contents__link toc-highlight">1. Startup</a></li><li><a href="#2-runtime-event-flow" class="table-of-contents__link toc-highlight">2. Runtime Event Flow</a></li></ul></li><li><a href="#core-components" class="table-of-contents__link toc-highlight">Core Components</a><ul><li><a href="#application-orchestrator-apprs" class="table-of-contents__link toc-highlight">Application Orchestrator (<code>app.rs</code>)</a></li><li><a href="#event-system" class="table-of-contents__link toc-highlight">Event System</a></li><li><a href="#television-core-televisionrs" class="table-of-contents__link toc-highlight">Television Core (<code>television.rs</code>)</a></li><li><a href="#channel-system" class="table-of-contents__link toc-highlight">Channel System</a></li><li><a href="#rendering-system" class="table-of-contents__link toc-highlight">Rendering System</a></li><li><a href="#configuration-system" class="table-of-contents__link toc-highlight">Configuration System</a></li><li><a href="#preview-system-previewer" class="table-of-contents__link toc-highlight">Preview System (<code>previewer/</code>)</a></li><li><a href="#watch-timer-loopswatch_timerrs" class="table-of-contents__link toc-highlight">Watch Timer (<code>loops/watch_timer.rs</code>)</a></li></ul></li><li><a href="#communication" class="table-of-contents__link toc-highlight">Communication</a><ul><li><a href="#data-flow" class="table-of-contents__link toc-highlight">Data Flow</a></li></ul></li><li><a href="#design-patterns" class="table-of-contents__link toc-highlight">Design Patterns</a><ul><li><a href="#1-actor-model" class="table-of-contents__link toc-highlight">1. Actor Model</a></li><li><a href="#2-command-pattern" class="table-of-contents__link toc-highlight">2. Command Pattern</a></li><li><a href="#3-observer-pattern" class="table-of-contents__link toc-highlight">3. Observer Pattern</a></li><li><a href="#4-plugin-architecture" class="table-of-contents__link toc-highlight">4. Plugin Architecture</a></li></ul></li><li><a href="#performance" class="table-of-contents__link toc-highlight">Performance</a></li><li><a href="#how-to-extend" class="table-of-contents__link toc-highlight">How to Extend</a><ul><li><a href="#adding-new-channels" class="table-of-contents__link toc-highlight">Adding New Channels</a></li><li><a href="#custom-keybindings" class="table-of-contents__link toc-highlight">Custom Keybindings</a></li><li><a href="#ui-themes" class="table-of-contents__link toc-highlight">UI Themes</a></li></ul></li></ul></div></div></div></div></main></div></div></div><footer class="theme-layout-footer footer"><div class="container container-fluid"><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2025 alexpasmantier</div></div></div></footer></div>
</body>
</html>