1
0
mirror of https://github.com/gdamore/tcell.git synced 2025-04-24 13:48:51 +08:00

Start of base screen refactoring.

A lot of functionality is duplicated across screen implementations,
and adding convenience methods is onerous because one needs to touch
each implementation with what is mostly copy-paste coding.

This represents the start of refactoring to eliminate redundant code
from each implemenation and provide for it in a common layer.
This commit is contained in:
Garrett D'Amore 2023-12-03 16:54:28 -08:00
parent fe52739ee8
commit ef4f9ccd96
4 changed files with 62 additions and 41 deletions

View File

@ -1,7 +1,7 @@
//go:build windows
// +build windows
// Copyright 2022 The TCell Authors
// Copyright 2023 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
@ -175,7 +175,7 @@ var vtCursorStyles = map[CursorStyle]string{
// with the current process. The Screen makes use of the Windows Console
// API to display content and read events.
func NewConsoleScreen() (Screen, error) {
return &cScreen{}, nil
return &baseScreen{screenImpl: &cScreen{}}, nil
}
func (s *cScreen) Init() error {
@ -894,14 +894,6 @@ func (s *cScreen) mapStyle(style Style) uint16 {
return attr
}
func (s *cScreen) SetCell(x, y int, style Style, ch ...rune) {
if len(ch) > 0 {
s.SetContent(x, y, ch[0], ch[1:], style)
} else {
s.SetContent(x, y, ' ', nil, style)
}
}
func (s *cScreen) SetContent(x, y int, primary rune, combining []rune, style Style) {
s.Lock()
if !s.fini {
@ -1154,10 +1146,6 @@ func (s *cScreen) resize() {
_ = s.PostEvent(NewEventResize(w, h))
}
func (s *cScreen) Clear() {
s.Fill(' ', s.style)
}
func (s *cScreen) Fill(r rune, style Style) {
s.cells.Fill(r, style)
}

View File

@ -263,7 +263,6 @@ type Screen interface {
// Tty returns the underlying Tty. If the screen is not a terminal, the
// returned bool will be false
Tty() (Tty, bool)
}
// NewScreen returns a default Screen suitable for the user's terminal
@ -302,3 +301,61 @@ const (
CursorStyleBlinkingBar
CursorStyleSteadyBar
)
// screenImpl is a subset of Screen that can be used with baseScreen to formulate
// a complete implementation of Screen. See Screen for doc comments about methods.
type screenImpl interface {
Init() error
Fini()
Fill(rune, Style)
GetContent(x, y int) (primary rune, combining []rune, style Style, width int)
SetContent(x int, y int, primary rune, combining []rune, style Style)
SetStyle(style Style)
ShowCursor(x int, y int)
HideCursor()
SetCursorStyle(CursorStyle)
Size() (width, height int)
ChannelEvents(ch chan<- Event, quit <-chan struct{})
PollEvent() Event
HasPendingEvent() bool
PostEvent(ev Event) error
PostEventWait(ev Event)
EnableMouse(...MouseFlags)
DisableMouse()
EnablePaste()
DisablePaste()
EnableFocus()
DisableFocus()
HasMouse() bool
Colors() int
Show()
Sync()
CharacterSet() string
RegisterRuneFallback(r rune, subst string)
UnregisterRuneFallback(r rune)
CanDisplay(r rune, checkFallbacks bool) bool
Resize(int, int, int, int)
HasKey(Key) bool
Suspend() error
Resume() error
Beep() error
SetSize(int, int)
LockRegion(x, y, width, height int, lock bool)
Tty() (Tty, bool)
}
type baseScreen struct {
screenImpl
}
func (b *baseScreen) SetCell(x int, y int, style Style, ch ...rune) {
if len(ch) > 0 {
b.SetContent(x, y, ch[0], ch[1:], style)
} else {
b.SetContent(x, y, ' ', nil, style)
}
}
func (b *baseScreen) Clear() {
b.Fill(' ', StyleDefault)
}

View File

@ -94,7 +94,7 @@ func NewTerminfoScreenFromTtyTerminfo(tty Tty, ti *terminfo.Terminfo) (s Screen,
t.fallback[k] = v
}
return t, nil
return &baseScreen{screenImpl: t}, nil
}
// NewTerminfoScreenFromTty returns a Screen using a custom Tty implementation.
@ -595,10 +595,6 @@ func (t *tScreen) SetStyle(style Style) {
t.Unlock()
}
func (t *tScreen) Clear() {
t.Fill(' ', t.style)
}
func (t *tScreen) Fill(r rune, style Style) {
t.Lock()
if !t.fini {
@ -622,14 +618,6 @@ func (t *tScreen) GetContent(x, y int) (rune, []rune, Style, int) {
return mainc, combc, style, width
}
func (t *tScreen) SetCell(x, y int, style Style, ch ...rune) {
if len(ch) > 0 {
t.SetContent(x, y, ch[0], ch[1:], style)
} else {
t.SetContent(x, y, ' ', nil, style)
}
}
func (t *tScreen) encodeRune(r rune, buf []byte) []byte {
nb := make([]byte, 6)

View File

@ -30,7 +30,7 @@ func NewTerminfoScreen() (Screen, error) {
t := &wScreen{}
t.fallback = make(map[rune]string)
return t, nil
return &baseScreen{screenImpl: t}, nil
}
type wScreen struct {
@ -79,10 +79,6 @@ func (t *wScreen) SetStyle(style Style) {
t.Unlock()
}
func (t *wScreen) Clear() {
t.Fill(' ', t.style)
}
func (t *wScreen) Fill(r rune, style Style) {
t.Lock()
t.cells.Fill(r, style)
@ -102,14 +98,6 @@ func (t *wScreen) GetContent(x, y int) (rune, []rune, Style, int) {
return mainc, combc, style, width
}
func (t *wScreen) SetCell(x, y int, style Style, ch ...rune) {
if len(ch) > 0 {
t.SetContent(x, y, ch[0], ch[1:], style)
} else {
t.SetContent(x, y, ' ', nil, style)
}
}
// paletteColor gives a more natural palette color actually matching
// typical XTerm. We might in the future want to permit styling these
// via CSS.