LogView

termflow.tui.widgets.LogView
object LogView

Append-only scrollback viewer for log lines, REPL output, chat transcripts, and similar streams.

The widget renders a fixed-size viewport into a longer line buffer. Apps own the buffer (typically a bounded Vector[String] or a ring-buffer) and a scrollOffset counted in display lines from the bottom — 0 is "tail of the buffer pinned to the last row" (the common live-feed view), positive values scroll back into history.

Long lines are wrapped to fit width when wrap = true (default), or truncated with a trailing when wrap = false. Wrapping is computed by expand (which delegates per line to wrapLine); the visible window is sliced by viewport. Both helpers are public so apps can pre-compute display lines once per buffer change instead of every frame.

given Theme = Theme.dark
Layout.column(gap = 0)(
 LogView(
   lines        = chatBuffer,
   width        = 60,
   height       = 12,
   scrollOffset = 0   // pinned to live tail
 ): _*
)

Value parameters

at

Top-left cell of the viewport.

height

Cell height (number of rows rendered).

lines

The raw line buffer. The widget does not mutate it.

scrollOffset

Number of display lines scrolled up from the tail. 0 keeps the latest line on the last row. Negative values are treated as 0.

style

Optional style override for the rendered rows. Defaults to the theme's foreground slot.

width

Cell width of the viewport.

wrap

Whether to wrap long lines to fit width (default true) or truncate with .

Attributes

Graph
Supertypes
class Object
trait Matchable
class Any
Self type
LogView.type

Members list

Type members

Classlikes

final case class Viewport(at: Coord, width: Int, height: Int)

Rectangle in absolute terminal cells the viewport occupies. Used by scrollDelta to decide whether a mouse-wheel event should drive the LogView; sized identically to the width / height / at arguments passed to LogView.apply.

Rectangle in absolute terminal cells the viewport occupies. Used by scrollDelta to decide whether a mouse-wheel event should drive the LogView; sized identically to the width / height / at arguments passed to LogView.apply.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all

Value members

Concrete methods

def apply(lines: Seq[String], width: Int, height: Int, scrollOffset: Int, at: Coord, wrap: Boolean, style: Option[Style])(using theme: Theme): List[VNode]
def displayLineCount(lines: Seq[String], width: Int, wrap: Boolean): Int

Number of display lines lines would expand to at this width.

Number of display lines lines would expand to at this width.

Attributes

def expand(lines: Seq[String], width: Int, wrap: Boolean): Vector[String]

Expand a raw line buffer into the display-line representation that the viewport will scroll over. Wrapped lines become multiple display lines; truncated lines become one. Empty input lines stay as empty display lines.

Expand a raw line buffer into the display-line representation that the viewport will scroll over. Wrapped lines become multiple display lines; truncated lines become one. Empty input lines stay as empty display lines.

Attributes

def maxScroll(lines: Seq[String], width: Int, height: Int, wrap: Boolean): Int

Maximum scroll offset for lines at this viewport size. Apps can use this to clamp scroll input from arrow keys or wheel events.

Maximum scroll offset for lines at this viewport size. Apps can use this to clamp scroll input from arrow keys or wheel events.

Attributes

def scrollDelta(event: MouseEvent, viewport: Viewport, ticksPerDetent: Int): Option[Int]

Map a MouseEvent.Scroll to a LogView scroll delta (negative for up / older lines, positive for down / newer lines), provided the scroll happened inside the viewport rectangle. Horizontal scroll (Left / Right) is ignored.

Map a MouseEvent.Scroll to a LogView scroll delta (negative for up / older lines, positive for down / newer lines), provided the scroll happened inside the viewport rectangle. Horizontal scroll (Left / Right) is ignored.

Apps wire this into their update:

case Msg.Key(InputKey.Mouse(ev)) =>
 val viewportRect = LogView.Viewport(at, width, height)
 LogView.scrollDelta(ev, viewportRect) match
   case Some(d) => Tui(scrollBy(model, d))
   case None    => model.tui

Value parameters

event

The decoded mouse event.

ticksPerDetent

Lines moved per wheel detent. Defaults to 3, which roughly matches the OS-level scroll-acceleration users expect from a real terminal log pane. Pass 1 for one-line-per- detent semantics.

viewport

Viewport rectangle the scroll must land in.

Attributes

Returns

Some(delta) if the event is a vertical scroll inside the viewport, None otherwise.

def truncateLine(line: String, width: Int): String

Truncate a single line to width, appending if it doesn't fit.

Truncate a single line to width, appending if it doesn't fit.

Attributes

def viewport(displayLines: Seq[String], height: Int, scrollOffset: Int): Vector[String]

Slice displayLines into the visible window: height lines anchored at scrollOffset from the tail. The result is padded on top with blank rows when the buffer is shorter than the viewport, so apps can draw a fixed-height region without conditional logic.

Slice displayLines into the visible window: height lines anchored at scrollOffset from the tail. The result is padded on top with blank rows when the buffer is shorter than the viewport, so apps can draw a fixed-height region without conditional logic.

Attributes

def wrapLine(line: String, width: Int): Vector[String]

Wrap a single line into chunks of at most width columns.

Wrap a single line into chunks of at most width columns.

Attributes