Class: TUI::HeightMap

Inherits:
Object
  • Object
show all
Defined in:
lib/tui/height_map.rb

Overview

Tracks estimated visual heights for chat entries, enabling viewport virtualization. Heights are in visual (wrapped) line units, estimated from content length and terminal width.

Provides efficient scroll-position-to-entry-index mapping so the chat screen can render only visible messages instead of processing the entire conversation history.

Examples:

map = HeightMap.new
map.update(entries, 80) { |entry, width| estimate(entry, width) }
first, last = map.visible_range(scroll_offset, viewport_height)
total = map.total_height

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeHeightMap

Returns a new instance of HeightMap.



21
22
23
24
# File 'lib/tui/height_map.rb', line 21

def initialize
  @heights = []
  @size = 0
end

Instance Attribute Details

#sizeInteger (readonly)

Returns number of tracked entries.

Returns:

  • (Integer)

    number of tracked entries



19
20
21
# File 'lib/tui/height_map.rb', line 19

def size
  @size
end

Instance Method Details

#cumulative_height(index) ⇒ Integer

Cumulative height of entries before the given index.

Parameters:

  • index (Integer)

    entry index (0-based)

Returns:

  • (Integer)

    total visual lines above this entry



47
48
49
50
51
52
# File 'lib/tui/height_map.rb', line 47

def cumulative_height(index)
  return 0 if index <= 0 || @heights.empty?
  return @heights.sum(0) if index >= @size

  @heights[0...index].sum(0)
end

#resetvoid

This method returns an undefined value.

Clears all tracked heights.



88
89
90
91
# File 'lib/tui/height_map.rb', line 88

def reset
  @heights.clear
  @size = 0
end

#total_heightInteger

Returns sum of all estimated entry heights.

Returns:

  • (Integer)

    sum of all estimated entry heights



39
40
41
# File 'lib/tui/height_map.rb', line 39

def total_height
  @heights.sum(0)
end

#update(entries, width) {|entry, width| ... } ⇒ void

This method returns an undefined value.

Replaces all heights from a fresh estimation pass. Each entry’s height is computed by the caller-supplied block.

Parameters:

  • entries (Array<Hash>)

    message store entries

  • width (Integer)

    terminal width for wrap estimation

Yields:

  • (entry, width)

    block returning estimated visual line count



33
34
35
36
# File 'lib/tui/height_map.rb', line 33

def update(entries, width)
  @heights = entries.map { |entry| [yield(entry, width), 1].max }
  @size = @heights.size
end

#visible_range(scroll_offset, visible_height) ⇒ Array(Integer, Integer)

Finds the entry range visible within a scroll window. An entry is visible if any of its lines fall within [scroll_offset, scroll_offset + visible_height).

Parameters:

  • scroll_offset (Integer)

    top of viewport in visual lines

  • visible_height (Integer)

    viewport height in visual lines

Returns:

  • (Array(Integer, Integer))
    first_visible, last_visible


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tui/height_map.rb', line 61

def visible_range(scroll_offset, visible_height)
  return [0, 0] if @heights.empty?

  first_found = false
  first = 0
  last = 0
  cumulative = 0
  end_line = scroll_offset + visible_height

  @heights.each_with_index do |entry_height, idx|
    entry_end = cumulative + entry_height
    unless first_found
      if entry_end > scroll_offset
        first = idx
        first_found = true
      end
    end
    last = idx if cumulative < end_line
    cumulative = entry_end
  end

  first = [@size - 1, 0].max unless first_found
  [first, [last, first].max]
end