github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/rty/render.go (about)

     1  package rty
     2  
     3  import (
     4  	"github.com/gdamore/tcell"
     5  )
     6  
     7  func NewRTY(screen tcell.Screen, handler ErrorHandler) RTY {
     8  	return &rty{
     9  		screen:  screen,
    10  		state:   make(renderState),
    11  		handler: handler,
    12  	}
    13  }
    14  
    15  type rty struct {
    16  	screen  tcell.Screen
    17  	state   renderState
    18  	handler ErrorHandler
    19  }
    20  
    21  type renderState map[string]interface{}
    22  
    23  func (r *rty) Render(c Component) {
    24  	g := &renderGlobals{
    25  		prev: r.state,
    26  		next: make(renderState),
    27  	}
    28  	f := renderFrame{
    29  		canvas:  newScreenCanvas(r.screen, r.handler),
    30  		globals: g,
    31  		handler: r.handler,
    32  	}
    33  
    34  	f.RenderChild(c)
    35  	r.screen.Show()
    36  	r.state = g.next
    37  }
    38  
    39  func (r *rty) RegisterElementScroll(name string, children []string) (l *ElementScrollLayout, selectedChild string) {
    40  	r.state[name], selectedChild = adjustElementScroll(r.state[name], children)
    41  	return &ElementScrollLayout{
    42  		name: name,
    43  	}, selectedChild
    44  }
    45  
    46  func (r *rty) ElementScroller(name string) ElementScroller {
    47  	st, ok := r.state[name]
    48  	if !ok {
    49  		st = &ElementScrollState{}
    50  		r.state[name] = st
    51  	}
    52  
    53  	return &ElementScrollController{state: st.(*ElementScrollState)}
    54  }
    55  
    56  func (r *rty) TextScroller(name string) TextScroller {
    57  	st, ok := r.state[name]
    58  	if !ok {
    59  		st = &TextScrollState{}
    60  		r.state[name] = st
    61  	}
    62  
    63  	return &TextScrollController{state: st.(*TextScrollState)}
    64  }
    65  
    66  type renderGlobals struct {
    67  	prev renderState
    68  	next renderState
    69  }
    70  
    71  func (g *renderGlobals) Get(key string) interface{} {
    72  	return g.prev[key]
    73  }
    74  
    75  func (g *renderGlobals) Set(key string, d interface{}) {
    76  	g.next[key] = d
    77  }
    78  
    79  type renderFrame struct {
    80  	canvas Canvas
    81  
    82  	style tcell.Style
    83  
    84  	globals *renderGlobals
    85  
    86  	handler ErrorHandler
    87  }
    88  
    89  var _ Writer = renderFrame{}
    90  
    91  func (f renderFrame) SetContent(x int, y int, mainc rune, combc []rune) {
    92  	if mainc == 0 {
    93  		mainc = ' '
    94  	}
    95  	f.canvas.SetContent(x, y, mainc, combc, f.style)
    96  }
    97  
    98  func (f renderFrame) Fill() (Writer, error) {
    99  	width, height := f.canvas.Size()
   100  	var err error
   101  	f.canvas, err = newSubCanvas(f.canvas, 0, 0, width, height, f.style, f.handler)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	return f, nil
   106  }
   107  
   108  func (f renderFrame) Divide(x, y, width, height int) (Writer, error) {
   109  	var err error
   110  	f.canvas, err = newSubCanvas(f.canvas, x, y, width, height, f.style, f.handler)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	return f, nil
   115  }
   116  
   117  func (f renderFrame) Foreground(c tcell.Color) Writer {
   118  	f.style = f.style.Foreground(c)
   119  	return f
   120  }
   121  
   122  func (f renderFrame) Background(c tcell.Color) Writer {
   123  	f.style = f.style.Background(c)
   124  	return f
   125  }
   126  
   127  func (f renderFrame) Invert() Writer {
   128  	f.style = f.style.Reverse(true)
   129  	return f
   130  }
   131  
   132  func (f renderFrame) error(err error) {
   133  	f.handler.Errorf("%v", err)
   134  }
   135  
   136  func (f renderFrame) RenderChild(c Component) int {
   137  	width, height := f.canvas.Size()
   138  	if err := c.Render(f, width, height); err != nil {
   139  		f.error(err)
   140  	}
   141  
   142  	_, height = f.canvas.Close()
   143  	return height
   144  }
   145  
   146  func (f renderFrame) RenderChildInTemp(c Component) Canvas {
   147  	width, _ := f.canvas.Size()
   148  	tmp := newTempCanvas(width, GROW, f.style, f.handler)
   149  	f.canvas = tmp
   150  
   151  	if err := c.Render(f, width, GROW); err != nil {
   152  		f.error(err)
   153  	}
   154  	tmp.Close()
   155  	return tmp
   156  }
   157  
   158  func (f renderFrame) Embed(src Canvas, srcY int, srcHeight int) error {
   159  	width, destLines := f.canvas.Size()
   160  
   161  	numLines := destLines
   162  	if srcHeight < destLines {
   163  		numLines = srcHeight
   164  	}
   165  
   166  	for i := 0; i < numLines; i++ {
   167  		for j := 0; j < width; j++ {
   168  			mainc, combc, style, _ := src.GetContent(j, srcY+i)
   169  			f.canvas.SetContent(j, i, mainc, combc, style)
   170  		}
   171  	}
   172  
   173  	return nil
   174  }
   175  
   176  func (f renderFrame) RenderStateful(c StatefulComponent, name string) {
   177  	prev := f.globals.Get(name)
   178  
   179  	width, height := f.canvas.Size()
   180  	next, err := c.RenderStateful(f, prev, width, height)
   181  	if err != nil {
   182  		f.error(err)
   183  	}
   184  
   185  	f.globals.Set(name, next)
   186  }