This document specifies the current behavior and design of the LogControl control as implemented.
For end-user usage and examples, see LogControl.
AppendLine(string message) (splits newlines into multiple entries)AppendMarkupLine(string markup) (splits newlines into multiple entries)AppendMarkupLine(ref AnsiMarkupInterpolatedStringHandler handler)Clear()FollowTail : bool (read-only; indicates whether the view is pinned to the bottom)ScrollToTail() (clears selection, enables follow-tail, and scrolls to the end)SearchText : string? (bindable)Search(string searchText)GoToNextMatch() / GoToPreviousMatch()SearchCaseSensitive : boolSearchWholeWord : boolSearchRegex : boolSearchOptions : LogSearchOptions (flags convenience wrapper)MatchCount : intActiveMatchIndex : int (or -1)HasSelection : boolMaxCapacity : int (0 disables trimming)WrapText : bool (when true, horizontal scrolling is disabled and lines reflow to the viewport width)LogControl styling uses two style keys:
LogControlStyle (surface/border/padding/selection)LogControlSearchStyle (match and active-match highlight, error style)Focusable = trueHorizontalAlignment = Align.Stretch, VerticalAlignment = Align.StretchWrapText = trueFollowTail = truesrc/XenoAtom.Terminal.UI/Controls/LogControl.cssrc/XenoAtom.Terminal.UI/Styling/LogControlStyle.cssrc/XenoAtom.Terminal.UI/Styling/LogControlSearchStyle.cssrc/XenoAtom.Terminal.UI.Tests/LogControlTests.cssamples/ControlsDemo/Demos/LogControlDemo.cssamples/FullscreenDemo/Program.cs (log viewer usage)LogControl is a composite control:
ScrollViewer hosts a private LogContentVisual that renders the entries and provides scrolling extent.SearchReplacePopup is anchored inside the padded viewport and shown in the app window layer (fullscreen only).The LogControl itself owns focus and input handling; the internal ScrollViewer is created with focusable: false.
Entries are stored in a BindableList<LogEntry> where each entry holds:
Text (plain text for the line)StyledRun[] (markup style runs relative to the entry start)When appending markup, the control parses the markup to plain text + style runs at append time using MarkupTextParser and the current theme markup styles.
Because markup is parsed at append time, changing the theme later does not re-parse historical markup runs.
When WrapText is enabled, each entry can occupy multiple rendered rows. The content visual computes:
ExtentHeight as the sum of per-entry row counts.ExtentWidth as the maximum measured cell width of any entry (used when wrapping is disabled).The content visual maintains a prefix-sum array mapping content-row -> entry index (for fast row-to-entry mapping).
MaxCapacity limits the number of retained entries.
FollowTail is false, the control keeps the viewport stable by subtracting the removed row count from ScrollViewer.VerticalOffset before deleting entries.Follow-tail is enabled when the viewport is at the maximum vertical offset (bottom).
FollowTail is true and there is no selection schedules a scroll-to-bottom.ScrollToTail() clears selection and re-enables follow-tail.Selection is tracked as two logical positions: an anchor and an active end position, both expressed as (EntryIndex, TextIndex).
Copy exports plain text (markup stripped):
Terminal.Clipboard.Search is controlled by bindable properties (SearchText and flags). There is also a SearchOptions flags wrapper for convenience.
Matches are computed over the plain entry text and stored as:
(EntryIndex, Start, Length)Search modes:
RegexOptions.CultureInvariant and IgnoreCase when case-insensitive.\\b(?:pattern)\\b.WordBoundaryUtility.IsWordBoundary(...).GoToNextMatch() / GoToPreviousMatch() wrap around when reaching the end/beginning.The built-in UI is a SearchReplacePopup anchored to the top-right of the padded viewport:
Command with CommandPresentation.CommandBar).ISearchReplaceTarget integration.The outer control fills the padded viewport background using LogControlStyle.BackgroundStyle(theme, focused).
LogContentVisual renders only the visible content rows:
WrapText is true).Highlight styles:
LogControlStyle.SelectionStyle(theme).LogControlSearchStyle.ResolveMatchStyle(theme).LogControlSearchStyle.ResolveActiveMatchStyle(theme).The control uses an internal bindable InteractionVersion to invalidate rendering when selection/match state changes.
LogControlTests covers:
ScrollToTail)