Documentation
¶
Overview ¶
Package screen is a tcell.Screen whose terminal is somewhere else.
It holds cells, turns what was drawn into frames, and accepts the events a terminal would have produced. It does not know how a frame reaches a terminal, and it does not know that the interface drawing on it is a database client — which is what lets all of it be tested without either.
Capabilities are reported from the Caps it was built with rather than guessed. Whatever is holding the real terminal is the only thing that can answer how many colours it has, and a screen that understates that makes the interface degrade itself somewhere no later stage can repair.
Index ¶
- type Caps
- type Cell
- type Cursor
- type Frame
- type Screen
- func (s *Screen) Attach(sink Sink)
- func (s *Screen) Beep() error
- func (s *Screen) CanDisplay(r rune, _ bool) bool
- func (s *Screen) ChannelEvents(ch chan<- tcell.Event, quit <-chan struct{})
- func (s *Screen) CharacterSet() string
- func (s *Screen) Clear()
- func (s *Screen) Colors() int
- func (s *Screen) Detach()
- func (s *Screen) DisableFocus()
- func (s *Screen) DisableMouse()
- func (s *Screen) DisablePaste()
- func (s *Screen) EnableFocus()
- func (s *Screen) EnableMouse(...tcell.MouseFlags)
- func (s *Screen) EnablePaste()
- func (s *Screen) Fill(r rune, style tcell.Style)
- func (s *Screen) Fini()
- func (s *Screen) Get(x, y int) (string, tcell.Style, int)
- func (s *Screen) GetClipboard()
- func (s *Screen) GetContent(x, y int) (rune, []rune, tcell.Style, int)
- func (s *Screen) HasKey(tcell.Key) bool
- func (s *Screen) HasMouse() bool
- func (s *Screen) HasPendingEvent() bool
- func (s *Screen) HideCursor()
- func (s *Screen) Init() error
- func (s *Screen) LockRegion(int, int, int, int, bool)
- func (s *Screen) PollEvent() tcell.Event
- func (s *Screen) PostEvent(ev tcell.Event) error
- func (s *Screen) PostEventWait(ev tcell.Event)
- func (s *Screen) Put(x, y int, str string, style tcell.Style) (string, int)
- func (s *Screen) PutStr(x, y int, str string)
- func (s *Screen) PutStrStyled(x, y int, str string, style tcell.Style)
- func (s *Screen) RegisterRuneFallback(rune, string)
- func (s *Screen) Resize(int, int, int, int)
- func (s *Screen) Resume() error
- func (s *Screen) SetCell(x, y int, style tcell.Style, ch ...rune)
- func (s *Screen) SetClipboard(data []byte)
- func (s *Screen) SetContent(x, y int, mainc rune, combc []rune, style tcell.Style)
- func (s *Screen) SetCursorStyle(cs tcell.CursorStyle, cc ...tcell.Color)
- func (s *Screen) SetSize(w, h int)
- func (s *Screen) SetStyle(style tcell.Style)
- func (s *Screen) SetTitle(title string)
- func (s *Screen) Show()
- func (s *Screen) ShowCursor(x, y int)
- func (s *Screen) Size() (int, int)
- func (s *Screen) Suspend() error
- func (s *Screen) Sync()
- func (s *Screen) Tty() (tcell.Tty, bool)
- func (s *Screen) UnregisterRuneFallback(rune)
- type Sink
- type Style
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Caps ¶
Caps is what the real terminal can do.
It is supplied rather than probed because the terminal is elsewhere. Every field here is a question only the process holding it can answer.
Width and Height are the size at the handshake and nothing keeps them current: SetSize resizes the buffer and leaves these alone, so Size is the authority on how big the screen is once a terminal has been resized.
type Cell ¶
Cell is one position on the screen and what belongs there.
Width travels with it so a wrong one can be seen rather than inferred. The client does not need it to place the next cell — every cell carries its own coordinates.
type Frame ¶
Frame is what changed since the last one, plus where the caret ended up.
func (Frame) Merge ¶
Merge folds next into f so one frame can be delivered where two were waiting.
It is sound because both are differences against the same picture — the one the reader is still showing, having applied neither. For any position the later cell wins; a position only f touched survives, which is the whole difference between merging and discarding. Discarding would leave whatever f was carrying stale on the screen for good.
The cursor is not a position on the screen but a single value, so the newer one is simply correct.
type Screen ¶
type Screen struct {
// contains filtered or unexported fields
}
Screen implements tcell.Screen against a cell buffer instead of a terminal.
func (*Screen) Attach ¶
Attach makes sink the destination and repaints everything into it.
The repaint is not politeness: Show clears dirty flags whether or not anyone was listening, so a screen drawn while detached has no record of what changed. Without the full frame, the first one after re-attaching is empty and the terminal keeps showing whatever it had.
func (*Screen) CanDisplay ¶
CanDisplay answers for the client's character set, because that is where the encoder actually lives. Under UTF-8 everything goes; under anything else only ASCII is safe to promise, and the client's own screen substitutes for the rest.
func (*Screen) ChannelEvents ¶
func (*Screen) CharacterSet ¶
func (*Screen) Clear ¶
func (s *Screen) Clear()
Clear fills with the default style rather than the one SetStyle last set, which is what tcell's own screens do.
func (*Screen) Detach ¶
func (s *Screen) Detach()
Detach stops emitting. The interface goes on drawing and does not learn that nobody is watching.
It waits on deliver so that a frame emit has already built cannot land in a sink this call has dropped.
func (*Screen) DisableFocus ¶
func (s *Screen) DisableFocus()
func (*Screen) DisableMouse ¶
func (s *Screen) DisableMouse()
func (*Screen) DisablePaste ¶
func (s *Screen) DisablePaste()
func (*Screen) EnableFocus ¶
func (s *Screen) EnableFocus()
func (*Screen) EnableMouse ¶
func (s *Screen) EnableMouse(...tcell.MouseFlags)
EnableMouse and friends record nothing, which makes them a requirement on whatever holds the terminal: it must enable mouse, paste and focus reporting on its own screen before it connects. The interface asking here cannot reach the terminal, so anything the client left off is never sent and nothing later can ask for it again.
func (*Screen) EnablePaste ¶
func (s *Screen) EnablePaste()
func (*Screen) Fini ¶
func (s *Screen) Fini()
Fini releases anything blocked in PollEvent. It is safe to call twice: the interface calls it on the way out, and so does whatever owns the screen.
func (*Screen) GetClipboard ¶
func (s *Screen) GetClipboard()
func (*Screen) HasKey ¶
HasKey answers for every key because the screen that decides which keys reach anyone is the real one on the client, and Caps carries no key set to answer from. Refusing here would suppress a key the terminal can send.
func (*Screen) HasPendingEvent ¶
func (*Screen) HideCursor ¶
func (s *Screen) HideCursor()
func (*Screen) LockRegion ¶
LockRegion marks cells the terminal must not touch during a redraw. There is no terminal here to hold off.
func (*Screen) PostEventWait ¶
PostEventWait is what whatever reads the transport should use: a key that arrived while the interface was busy should wait its turn rather than be refused.
func (*Screen) PutStr ¶
PutStr writes with the default style, which is what tcell.Screen promises. Substituting the SetStyle default here would make this screen draw text a real one would not, and the whole design rests on the two being the same screen.
func (*Screen) PutStrStyled ¶
func (*Screen) RegisterRuneFallback ¶
Rune fallbacks are the client's business: substitution happens where the encoder is, on the real screen. Recording them here would mean two substitution tables that can disagree.
func (*Screen) Resize ¶
Resize is tcell's vestigial window-resize request; no backend implements it.
func (*Screen) SetCell ¶
SetCell is tcell's deprecated spelling of Put, kept because the interface still carries it.
func (*Screen) SetClipboard ¶
func (*Screen) SetContent ¶
func (*Screen) SetCursorStyle ¶
func (s *Screen) SetCursorStyle(cs tcell.CursorStyle, cc ...tcell.Color)
func (*Screen) SetSize ¶
SetSize is what a client resize arrives as.
The order is load-bearing. tview relayouts when it sees the resize event and asks the screen how big it is while doing so; posting the event before the buffer has been resized lays the interface out at the size it just stopped being.
func (*Screen) Show ¶
func (s *Screen) Show()
Show clears the dirty flags whether or not a sink is listening, because the buffer is tview's and the interface draws on it either way. What that costs is the record of everything drawn while detached, which is why Attach repaints rather than waiting for the next Show.
func (*Screen) ShowCursor ¶
func (*Screen) Suspend ¶
Suspend and Resume put the terminal back in its original mode for a shell. The terminal is in another process, which suspends itself if it wants to.
func (*Screen) Sync ¶
func (s *Screen) Sync()
Sync emits every cell the buffer holds, skipping only the column behind a wide rune as Show does.
It does not go through the buffer's dirty flags. tcell marks a cell dirty by clearing the record of what was last drawn there, which leaves a cell nothing was ever written to indistinguishable from a clean one — so an invalidated blank screen reports nothing to send. A repaint has to mean every cell, because the terminal being repainted for may be showing anything at all.
func (*Screen) UnregisterRuneFallback ¶
type Sink ¶
type Sink interface {
Frame(Frame)
SetTitle(string)
SetClipboard([]byte)
// RequestClipboard asks the terminal for its contents. Most terminals
// refuse, so no reply is the ordinary case.
RequestClipboard()
Bell()
}
Sink is where a drawn screen goes.
It is an interface rather than a set of callbacks so that "attached" is one thing to hold and one thing to drop, and so a test can record every kind of output in one place.
No method may block. SetTitle, SetClipboard, GetClipboard and Beep are called from the goroutine that draws the interface, which is also the goroutine reading rows off the database connection; MySQL will not accept another statement until that result set is drained, so a sink that waits on a wedged terminal stalls the statement, its cancellation and the schema browser with it. Frame is called from that same goroutine for an ordinary draw, and from whichever goroutine attached the sink for the repaint that Attach sends. Frames have a bounded path for this in proto.FrameQueue — the other four methods have nothing behind them, and whatever implements them owns that.
An implementation must not call back into the screen — Detach, Show or Sync — from inside Frame. Delivery is serialised behind a single lock that Frame is called under, and Detach, Show and Sync all take that same lock, so a call back in from inside Frame blocks forever. "The write failed, drop the client" is the most natural thing to reach for in a transport, and it has to be done from somewhere other than inside Frame.
type Style ¶
type Style struct {
Fg, Bg tcell.Color
Attrs tcell.AttrMask
UnderlineStyle tcell.UnderlineStyle
UnderlineColor tcell.Color
}
Style is tcell.Style in a form an encoder can carry.
tcell.Style has no exported fields, and encoding/gob refuses a type that has none: "gob: type tcell.Style has no exported fields". A cell carrying one would not travel at all — the encode fails before a byte is written, and the reader waits for a frame that never comes. Nothing catches that at compile time, which is why this type exists and why a test pins the round trip.
The hyperlink a style can carry (OSC 8) is not here: tcell offers Url and UrlId as setters and no getters, so it cannot be read back out. dv writes no hyperlink markup — see the risk note in the spec — and a style that carried one would arrive without it.