Buffer Model
MonoTerm uses an optimized memory model to ensure scroll consistency while minimizing memory usage.The Problem
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β THE PROBLEM: Scroll Desync β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β xterm.js calculates scroll based on buffer size: β
β β
β scrollAreaHeight = buffer.lines.length x rowHeight β
β maxScrollTop = scrollAreaHeight - viewportHeight β
β β
β If buffer doesn't match scrollArea: β
β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β buffer.lines = X β != β scrollArea = Y β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β β β
β βββββββββββββ¬ββββββββββββ β
β βΌ β
β SCROLL DESYNC! β
β - Scroll jumps β
β - Thumb size wrong β
β - Position calculation broken β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The Solution: Optimized Memory Layout
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BUFFER STRUCTURE β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Variables: β
β H = history (scrollback lines) β
β V = viewport (visible rows) β
β β
β β
β Index: 0 H-1 H H+V-1 H+V H+2V-1 β
β β β β β β β β
β βΌ βΌ βΌ βΌ βΌ βΌ β
β βββββββββ¬ββββββββββ¬ββββββ¬βββββββ¬βββββββ¬βββββββ¬ββββββββ β
β β ##################### β/////////////β@@@@@@@@@@@@@ β β
β β HISTORY (H) β VIEWPORT β PADDING β β
β β scrollback β (V) β (V) β β
β β actual data β actual data β empty lines β β
β βββββββββββββββββββββββββ΄ββββββββββββββ΄βββββββββββββββ β
β β
β Legend: β
β #### = History lines (scrollback content) β
β //// = Viewport lines (visible screen content) β
β @@@@ = Padding lines (empty, for scroll consistency) β
β β
β Actual content: H + V lines (from Rust) β
β Total size: H + 2V lines (with padding) β
β Padding: V lines (constant, regardless of H) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Why This Layout Works
Safety Guarantee
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ARRAY BOUNDS SAFETY β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Maximum access pattern in xterm.js: β
β β
β buffer.lines[ydisp + y] β
β where: ydisp = H (at bottom) β
β y = 0..V-1 (viewport rows) β
β β
β Maximum index accessed: β
β max_index = H + (V - 1) β
β = H + V - 1 β
β β
β Buffer length: β
β buffer.lines.length = H + 2V β
β β
β Safety check: β
β H + V - 1 < H + 2V β
β V - 1 < 2V β
β -1 < V ALWAYS TRUE (for V > 0) β
β β
β Result: Buffer access is always within bounds β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Memory Efficiency
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MEMORY COMPARISON β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β With H=1000 (history), V=40 (viewport): β
β β
β β
β Alternative Model (wasteful): β
β ββββββββββββββββββββββββββββββ β
β buffer = 2H + V = 2040 lines β
β padding = H = 1000 lines (grows with history!) β
β β
β H=0 -> padding = 0 β
β H=100 -> padding = 100 β
β H=10000 -> padding = 10000 WASTEFUL! β
β β
β β
β MonoTerm Model (efficient): β
β βββββββββββββββββββββββββββ β
β buffer = H + 2V = 1080 lines β
β padding = V = 40 lines (constant!) β
β β
β V=40 -> padding = 40 ALWAYS ~40 lines β
β Regardless of history size! β
β β
β β
β Memory savings with 10,000 line history: β
β β
β Alternative: 20,040 lines β
β MonoTerm: 10,080 lines β
β Saved: 9,960 lines (99%) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Visual Memory Layout
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MEMORY LAYOUT VISUALIZATION β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Example: H=100 (history), V=40 (viewport) β
β β
β β
β βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ β
β β 0 β 1 β 2 β ... β 99 β 100 β 101 β ... β 139 β 140 β β
β βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ β
β β<βββββββββββ H=100 ββββββββββββ<βββββ V=40 βββββββ<ββ V=40 ββββ β
β β
β β
β Region β Indices β Content β Source β
β ββββββββββββΌβββββββββββββΌβββββββββββββββΌβββββββββββββ β
β History β 0..99 β Scrollback β Rust data β
β Viewport β 100..139 β Screen β Rust data β
β Padding β 140..179 β Empty β (no data) β
β β
β β
β Total length: 180 = H(100) + 2V(80) β
β Actual data: 140 = H(100) + V(40) β
β Padding: 40 = V β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Edge Cases
No History (Fresh Terminal)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EDGE CASE: Empty History β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β When: Terminal just started, no scrollback yet β
β β
β Values: β
β H = 0, V = 40 β
β β
β Layout: β
β βββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β/////////////////////////////////β@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@β β
β β VIEWPORT (V=40) β PADDING (V=40) β β
β βββββββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ β
β Index: 0 39 40 79β
β β
β Buffer size: 0 + 80 = 80 lines β
β Safety: max_index = 0 + 39 = 39 < 80 OK β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Large History
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EDGE CASE: Large Scrollback β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β When: Long-running terminal, lots of output β
β β
β Values: β
β H = 100,000 (max scrollback) β
β V = 40 β
β β
β β
β Alternative (wasteful): β
β buffer.length = 200,040 lines β
β padding = 100,000 lines (same as history!) β
β β
β β
β MonoTerm (efficient): β
β buffer.length = 100,080 lines β
β padding = 40 lines (same as viewport) β
β β
β β
β Memory savings: 99,960 empty lines avoided! β
β β
β Safety: max_index = 100,039 < 100,080 OK β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Scrollbar Integration
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SCROLLBAR SIZE CALCULATION β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β From GridUpdate: β
β totalLines = H + 2V β
β viewportRows = V β
β β
β Thumb SIZE (proportion): β
β thumbHeight = (V / (H + 2V)) x trackHeight β
β β
β Thumb POSITION: β
β scrollableRange = H + V β
β scrollFraction = ydisp / scrollableRange β
β thumbTop = scrollFraction x (trackHeight - thumbHeight) β
β β
β β
β Track representation: β
β β
β βββββ β
β β...β <- History region (H) β
β β...β β
β β...β β
β β###β <- Thumb (V / (H+2V) of track) β
β β...β <- Padding region (V) β
β βββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Scroll Position Mapping
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SCROLL POSITION MAPPING β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ydisp (internal) <--> scrollTop (DOM pixel) β
β β
β Conversion: β
β scrollTop = ydisp x rowHeight β
β ydisp = Math.floor(scrollTop / rowHeight) β
β β
β Range: β
β ydisp: 0 (top of history) to H (bottom, current screen) β
β scrollTop: 0 to (H + V) x rowHeight β
β β
β Visual: β
β β
β ydisp=0 ydisp=H/2 ydisp=H β
β scrollTop=0 scrollTop=M scrollTop=max β
β β β β β
β βΌ βΌ βΌ β
β βββββββββ βββββββββ βββββββββ β
β β#######β β.......β β.......β <- viewport window β
β β#######β β#######β β.......β β
β β.......β β#######β β#######β β
β β.......β β.......β β#######β β
β βββββββββ βββββββββ βββββββββ β
β top of middle of bottom of β
β history history history (current) β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Summary
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BUFFER MODEL SUMMARY β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [OK] WHAT IT SOLVES: β
β - xterm.js scroll/buffer desync β
β - Unpredictable buffer growth β
β - Scrollbar calculation errors β
β β
β [OK] HOW IT WORKS: β
β - Buffer = Content (H+V) + Padding (V) β
β - Padding is always viewport-sized β
β - scrollArea height matches buffer length β
β β
β [OK] WHY IT'S SAFE: β
β - Max access: H + V - 1 β
β - Buffer size: H + 2V β
β - H + V - 1 < H + 2V (always true for V > 0) β
β β
β [OK] WHY IT'S EFFICIENT: β
β - Padding = V (constant ~40 lines) β
β - Not H (could be 100,000 lines!) β
β - Memory grows linearly with content, not doubled β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Memory Efficiency
Constant padding of ~40 lines regardless of scrollback size. With 100K history: saves 99,960 empty lines compared to alternative models.