跳转到内容
Crystal CodeDocs
简简体中文

Display

此内容尚不支持你的语言。

CrystalCode.Display is the TUI host. Spectre.Console supplies markup, color, panels, grids, rules, and padding as an offline rasterizer. Process startup sets console output to UTF-8 without a BOM, binds Spectre’s profile to the matching UTF-8 writer, and turns its Unicode output on, then restores the previous output encoding when the process exits. Changing the code page replaces Console.Out, so the profile is rebound to the new writer; otherwise Spectre would keep encoding with the old OEM code page. Console input encoding is left alone. Files, prompts, and provider bodies are already UTF-8. The progress spinner is braille, so a Windows OEM code page would replace each frame with ? and garble CJK text. AnsiConsole.Live is not the session shell: it fights the composer. Widgets are rasterized into frame rows. A live user, thinking, tool, or error card keeps rows that are already wrapped. New stream text reflows only the open tail, and scrolling or typing reuses those rows. The shell enters the alternate screen when the terminal is a TTY and paints a retained frame: transcript viewport, optional overlay, optional pinned todos, optional progress row, status bar, and multiline composer. Unchanged rows are left in place; a width or height change clears the buffer. The frame uses one terminal-size snapshot, and the composer window is projected again if overlays or pinned rows leave fewer rows than it requested. Composer tabs display as four spaces while the submitted prompt retains tab characters; other painted rows expand tabs by the same width. One column remains free for the cursor at the right edge. The executable maps engine events onto that frame through SessionProjection and SessionRenderer; it does not paint rows itself. Entering the alternate screen sets the window title to Crystal Code when the terminal allows it, and restores the previous title on exit. If setup fails after the alternate buffer is entered, the shell leaves that buffer, turns off bracketed paste and mouse reporting when those were enabled, and restores the title when it was changed. Windows VT input mode is restored on screen disposal, with a process-exit retry if the first restoration fails. When the terminal drops below the usable minimum (ShellLayout.MinUsableWidth x ShellLayout.MinUsableHeight, 80x24), the frame is replaced by a centered resize notice sized to the real terminal and input is ignored, including keys typed while the window is too small. The session resumes automatically once the window is large enough. /stats also replaces the frame: the status bar, composer, queue, todos, and progress row are not painted, and keys other than Esc, q, and scrolling are ignored. The page is a centered column of Overview, Tokens, and Tools panels. Tool rows show a share bar, count, and percent. Esc, q, or Ctrl+C restores the session frame and leaves the composer draft in place. ShellLayout.MinWidth/MinHeight (16x8) remain a math floor for layout only.

Text that came from a model, a tool, or a file never reaches the terminal as control bytes. TerminalText.Sanitize removes C0 and C1 controls, DEL, and escape introducers from streamed and committed text. Tool bodies still collapse a carriage return the way a terminal overwrites the current line. One-line chrome (SanitizeLine for todos, activity, and progress) flattens carriage returns, line breaks, and tabs to spaces and does not use that overwrite. PaintLine.Fit strips controls again from every row after tab expansion, so no producer can leak an escape sequence into a frame. Todo content, activity and progress text, and widget segments go through the same path. Approval cards are different: the operator must see what is being approved, so control and bidirectional characters in commands, diffs, rationale, and tool summaries are shown as visible \xNN and \uNNNN escapes through TerminalText.Reveal instead of being dropped.

Width policy: TextWidth.Measure must never be narrower than Spectre’s Segment.CellCount(). WideRanges is generated from Spectre’s own widths, and a test compares every code point. Each row is rasterized by FrameRow at a very wide virtual width and cropped at a cell boundary, so Spectre can never re-wrap a row and emit a line feed into the frame. Known limits: variation-selector emoji sequences are measured as one cell, and ambiguous width characters assume a narrow terminal.

ScreenPainter wraps every paint in DEC 2026 synchronized output (?2026h and ?2026l), which terminals that lack the mode ignore. Autowrap is disabled while rows are written. Before it is enabled again the cursor is parked at the origin, so a full-width row cannot leave the pending-wrap flag set and shift ASCII onto the composer. Unchanged rows, including the composer, stay in place. On Windows the console echo flag is off so the host does not print mouse and mode reports into the input line. A finished report whose escape was already consumed is dropped, not pasted. An unfinished tail is still text, so a paste such as [12;40 is kept. WidgetPaint keeps foreground, background, bold, dim, italic, underline, strikethrough, and invert when it rasterizes Spectre widgets. Links and blinking are dropped on purpose.

ScrollAnchor keeps the transcript on the row the operator is reading. That position is one committed row, named by entry index and line. A live tail uses the entry index it will occupy once committed. New rows at the end move the distance from the bottom so the anchored row stays put. At the bottom, where no row is anchored, the view follows new output. A scroll that leaves the bottom is measured from the latest row count. A width change keeps the distance and re-clamps it, then takes a new anchor. When a block above the anchor changes height, the same row is found again.

Terminal.Gui is referenced from CrystalCode.Display with a floating version and is not used. Do not call Application.Init or mix a second console writer with the self-owned loop.

The status bar shows the selected context budget as Context 272K beside the thinking gear. The custom status-line field context-window shows the same value and is included in its default field list.

The status bar shows approval, thinking (when the selected model supports it: Think Off, or Think plus the resolved gear when thinking is on), Tier <token> and Speed <token> when those slots are set, the non-default prompt set as Prompt <name>, model, workspace, the latest request’s context percent (CTX), cumulative token counts (IN / OUT), and, when the bar has room, a cumulative Title Case total (783k Total). During a turn the status bar updates CTX, IN, and OUT after each model round and each tool batch: provider usage as it arrives, then a local transcript estimate after tools until the next round reports. It also shows tool count (Tool / Tools), and elapsed time. When the session has todos, a pinned Todos bar sits above the progress row and status bar. The existing adaptive status bar is the default. Operators may independently enable an ordered custom status line through customStatusLine, statusLine, or /statusline. Custom token fields name their scope explicitly as context, request, or session usage. Disabling the custom line returns to the existing adaptive rendering path. A disk plugin may register extra field names. Those names stay off the adaptive bar, the progress row, /status, and /stats. They appear on the custom line only when the operator lists them. The engine publishes the latest plain text as StatusFieldsChanged, in the order the changes were taken. The terminal stores that text and paints it on the next input poll. The host does not poll the plugin and does not run a status timer. Empty text occupies no cell. A narrow custom line still drops custom slots from the right. Each row is a checkbox colored by status: pending chrome, in progress accent, completed ok, cancelled muted. The bar shows the first four items and a +N more line when the list is longer; /todos (alias /todo) prints the full untruncated list in the transcript. The transcript Result card uses the same colors for - [ ] / - [~] / - [x] / - [-] lines so they are not painted as diff removals. Named chrome labels are Title Case. Short status abbreviations are uppercase. Mode is Plan or Work on the composer prompt and is not repeated on the status bar. While a turn runs, a progress row sits directly above the status bar (Waiting For Model, Thinking, Writing, Running Command, Awaiting Approval, Reviewing, Waiting For Answer, Compacting, Retrying In Ns (Attempt K)). The retry caption counts remaining wait down. The same row shows Loading Tools while operator tool sets are discovered at session start and on /cd or /space, after the frame is up, so a slow assembly load does not leave a blank terminal. The caption is prefixed with a one-cell spinner that advances while the turn is live, plus the current activity elapsed time (5s, 2m18s). When estimatedTokens is on, Thinking and Writing also show a live estimate (~1.2k Tokens) after elapsed time. Elapsed resets when the progress caption changes. It is independent of the status-bar activity bullet (• Bash). The row is omitted when idle. Assistant text is rendered as markdown while it streams and after it commits (headings, lists, fenced code with a dim code background, inline code and bold, and GFM tables). A table is aligned by display columns, wrapped inside a column, or stacked when the terminal cannot give every column its minimum. A table that cannot be parsed or laid out is painted as its original lines. User, thinking, tool, and result blocks are rounded panels. A live turn writes a Tool card when the model round closes with tool calls, before those calls execute, using the same one-line summary as session replay. Tool names in chrome and cards are Title Case; stream name chunks are coalesced per tool call so a repeated snapshot does not become ReadReadRead and sequential calls never concatenate. Success result panels honor verboseResults (config.json, default on, omitted when on). It is the parent of verboseTools and verboseCommands. While it is off, every success result is omitted, including read, search, skill, edit, write, bash, bash_start, bash_status, bash_logs, and bash_stop. The Tool card stays unless verboseCalls is off. That switch (default on, omitted when on) hides every Tool card, including read, search, edit, write, bash, background bash, and external tools. It does not hide success or failure results, and verboseResults does not hide Tool cards. Failure results stay. The child switches stay stored and do not draw a result until the parent is on again; Ctrl+G does not expand a command result in that state because the panel is omitted, not collapsed. A missing verboseResults field keeps the parent on. While the parent is on, tool verbose off omits read/search/skill result panels and still shows edit and write results, and command verbose off collapses bash and the four background bash tools to a hidden-line hint plus the last output line. crystal run does not read verboseResults. Policy and grant auto-pass cards honor verboseApprovals (default on). Review allow cards honor verboseReview (default on). The switches are independent: turning approvals off does not hide a review allow card, and turning review off does not hide a policy or grant card. Cards already in the transcript follow their own switch, and turning that switch back on shows them again. A saved verboseApprovals value of false no longer hides review allow cards. The ask overlay still appears. Ctrl+O toggles tool verbose and Ctrl+G toggles command verbose when the composer is empty; /verbose shows or changes the same settings (tools, commands, results, calls, approvals, review, thinking, on, off). results is the parent of tools and commands. calls hides Tool cards only. Thinking panels honor verboseThinking (default on). When it is off, live and committed Thinking cards are omitted, including cards restored with a session; turning it back on shows the stored text again. Inline output, used when the alternate screen is unavailable, applies the same switches to restored thinking, tool results (including the verboseResults parent), policy and grant approval text, and review allow text. The progress row, the thinking gear, and export stay. crystal run --show-thinking remains a separate one-shot flag and does not read this setting. Approval is a Spectre panel with a two-column Title Case field grid (Status, Reason, Risk, Authority, Outcome). Question panels show header tabs, described choices, selection state, custom input, and a final answer review when confirmation is required. Plain Up/Down stays with question selection. When the question panel is taller than its slot, PageUp/PageDown, the wheel, and Ctrl+Up/Down scroll that panel. Moving the highlighted choice, or the cursor in a custom answer, scrolls the panel to keep that row visible. A manual scroll stays until that row changes. A scroll that would move past either end, and any scroll while the panel already fits, scrolls the transcript. Custom answers edit inside the overlay with an independent buffer: Enter saves and Escape cancels editing without dismissing the question. The paused main composer keeps its draft and hides its cursor. Ask and auto-pass cards for edit and write show a capped + / - preview of old_string / new_string or contents. Overlay keys share the session frame loop, so transcript scroll and resize still work while a prompt is up. Ask overlays use the same card; Y / S / A / N map Once / Session / Always / Deny for ordinary workspace calls. Calls that cannot reuse grants offer only Y / N (Once / Deny) and ignore Session/Always keys. The follow-up queue is a Queued panel above the composer.

Composer keys: Enter submits when idle and queues while a turn is running. Queued text stays above the composer and is sent when the current tool batch or turn ends. Empty Enter while a follow-up is queued interrupts the turn, or compaction if that is still running, so the queue is sent now. Empty Enter with nothing queued does not stop the turn. Backspace deletes one character on every platform. Windows Ctrl+Backspace deletes a word. On Unix, ReadKey tags plain Backspace as Control; that is still one character. Ctrl+W or Alt/Option+Backspace deletes a word. Ctrl+C at idle clears the composer. Two Ctrl+C presses on an empty composer exit. Ctrl+J or \+Enter inserts a newline. Tab toggles Plan/Work or completes a / command. Shift+Tab also toggles Plan/Work. Chrome labels are Plan, Work, Review, Default, Edit, Audit, and Full. When the slash picker is open, plain Up/Down moves its selection without resetting it and scrolls the visible candidate window to keep that selection on screen. Tab accepts the selected completion. Enter accepts a partial selection first; when the composer already contains that complete command or argument, Enter submits normally. Status abbreviations are CTX, IN, and OUT. The status bar includes a queued count while follow-ups wait. Auto-pass prints a panel with Status, Reason, Risk, Authority, and, for review, Outcome plus rationale. Policy and grant panels follow verboseApprovals. Review allow panels follow verboseReview. Reasoning streams into the transcript while verboseThinking is on. Built-in slash verbs live in SlashCatalog and include aliases (/new is /clear, /continue is /resume, /q and /exit are /quit, /think is /thinking, /summarize is /compact, /todo is /todos, /prompts is /promptset, /verbose toggles tool, command, result, call, approval, review, or thinking detail). /export writes markdown or json for the current conversation; /prompts export writes built-in prompt templates. Export roots default to ~/.crystal/exports/ (exportDirectory omitted or home) and are configurable through exportDirectory in config.json. A slash picker appears while the prompt is a command prefix. After a verb that takes an argument (/thinking, /approval, /model, /tokens, /verbose), Tab also completes the argument. /model completes current-provider models, then a provider name, then that provider’s models. /approval model completes on, off, and the stored approval provider’s catalog, and /approval thinking completes the selected approval model’s gear. /export completes the format, optional system flag, and the system flag after an explicit path. /prompts export offers directory examples while Enter on the optional argument boundary still submits with the default directory. Ctrl+O and Ctrl+G toggle verbose tool and command output when the composer is empty. Plain Up/Down move through the composer’s visual rows, including wrapped rows. At the first or last row they navigate submitted prompt history; Up on an empty prompt recalls the latest entry, and Down past the newest entry restores the unsent draft and its cursor. The slash picker owns plain Up/Down while open, but it stays closed while the composer is showing a recalled entry, including one that starts with /. Editing that entry opens the picker again. Submitted text-only history is stored by workspace in ~/.crystal/prompt-history.jsonl with an owner-only file mode where supported. Image-bearing prompts remain in memory only and are forgotten when the session changes, since their markers do not carry image bytes or a stable cross-session attachment. PageUp/PageDown are the primary transcript scroll controls; Ctrl+Up/Down also scroll when the terminal passes those keys through. The alternate screen enables bracketed paste (2004) and mouse reporting (1000 with SGR encoding 1006) and turns alternate scroll (1007) off. While that screen is up, the shell repeats those modes about once a second. On Windows it also puts VT input back and turns quick edit and native mouse input off, then restores the console input mode captured at entry when the screen closes. The next refresh puts the wheel back if the console host cleared it. A wheel report scrolls the transcript and is drained without waiting; other mouse reports are swallowed. The wheel is never converted to Up/Down, so plain Up/Down stay with the composer, prompt history, or the active selection. Terminal text selection needs Shift (Option or Fn on some macOS terminals) while mouse reporting is on, and the help list says so. Escape clears the composer. Pasted text is normalized to LF and tabs, and control, invisible, and bidirectional formatting characters are dropped. Escape is held only when no further bytes are available or the sequence is still incomplete.

KeyBurst collects one ReadKey drain. InputDecoder turns that burst into InputKey, InputPaste, or InputWheel. Platform differences stay in the decoder; the composer, scroll policy, and overlays consume events only. Linux and macOS usually deliver parsed ConsoleKey values. Windows VT input leaves Key empty, so Tab, Enter, letters, and CSI arrive as KeyChar. The shell restores the prior Windows console input mode on exit. macOS Option-as-Meta is ESC plus a letter or Backspace and becomes Alt; a native Alt modifier on a parsed key is kept. A CR+LF drain is one Enter, not paste. Paste is the text between CSI 200~ and 201~. A printable burst with an internal newline is still paste when those markers are absent, so it is inserted and does not submit. A burst whose only newline is one trailing CR or CRLF stays keys, and so does a burst that contains Backspace or Delete. Escape sequences that are not a bracketed-paste wrap are not treated as paste. The host does not parse VT. The frame polls terminal size and repaints when the window is resized. Redirected output stays sequential.