fixes #710 Add support for setting the window title

This commit is contained in:
Garrett D'Amore 2024-03-09 10:05:58 -08:00
parent 887cf2766e
commit c9ba0cf327
10 changed files with 96 additions and 4 deletions

View File

@ -123,6 +123,7 @@ func main() {
fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(1)
}
s.SetTitle("Tcell Mouse Demonstration")
defStyle = tcell.StyleDefault.
Background(tcell.ColorReset).
Foreground(tcell.ColorReset)

View File

@ -109,6 +109,9 @@ func main() {
Background(tcell.ColorWhite))
s.Clear()
// we can even try to use unicode window titles!
s.SetTitle("Unicode Demonstration -- 🤯")
quit := make(chan struct{})
style = bold

View File

@ -42,6 +42,7 @@ type cScreen struct {
truecolor bool
running bool
disableAlt bool // disable the alternate screen
title string
w int
h int
@ -176,6 +177,9 @@ const (
vtExitUrl = "\x1b]8;;\x1b\\"
vtCursorColorRGB = "\x1b]12;#%02x%02x%02x\007"
vtCursorColorReset = "\x1b]112\007"
vtSaveTitle = "\x1b[22;2t"
vtRestoreTitle = "\x1b[23;2t"
vtSetTitle = "\x1b]2;%s\x1b\\"
)
var vtCursorStyles = map[CursorStyle]string{
@ -350,6 +354,7 @@ func (s *cScreen) disengage() {
s.emitVtString(vtCursorColorReset)
s.emitVtString(vtEnableAm)
if !s.disableAlt {
s.emitVtString(vtRestoreTitle)
s.emitVtString(vtExitCA)
}
} else if !s.disableAlt {
@ -387,9 +392,13 @@ func (s *cScreen) engage() error {
if s.vten {
s.setOutMode(modeVtOutput | modeNoAutoNL | modeCookedOut | modeUnderline)
if !s.disableAlt {
s.emitVtString(vtSaveTitle)
s.emitVtString(vtEnterCA)
}
s.emitVtString(vtDisableAm)
if s.title != "" {
s.emitVtString(fmt.Sprintf(vtSetTitle, s.title))
}
} else {
s.setOutMode(0)
}
@ -1275,6 +1284,15 @@ func (s *cScreen) SetStyle(style Style) {
s.Unlock()
}
func (s *cScreen) SetTitle(title string) {
s.Lock()
s.title = title
if s.vten {
s.emitVtString(fmt.Sprintf(vtSetTitle, title))
}
s.Unlock()
}
// No fallback rune support, since we have Unicode. Yay!
func (s *cScreen) RegisterRuneFallback(_ rune, _ string) {

View File

@ -266,6 +266,12 @@ type Screen interface {
// Tty returns the underlying Tty. If the screen is not a terminal, the
// returned bool will be false
Tty() (Tty, bool)
// SetTitle sets a window title on the screen.
// Terminals may be configured to ignore this, or unable to.
// Tcell may attempt to save and restore the window title on entry and exit, but
// the results may vary. Use of unicode characters may not be supported.
SetTitle(string)
}
// NewScreen returns a default Screen suitable for the user's terminal
@ -335,6 +341,7 @@ type screenImpl interface {
Resume() error
Beep() error
SetSize(int, int)
SetTitle(string)
Tty() (Tty, bool)
// Following methods are not part of the Screen api, but are used for interaction with

View File

@ -150,3 +150,13 @@ func TestBeep(t *testing.T) {
}
}
}
func TestTitle(t *testing.T) {
s := mkTestScreen(t, "")
defer s.Fini()
s.SetTitle("My Title")
s.Show()
if s.GetTitle() != "My Title" {
t.Errorf("Title mismatched")
}
}

View File

@ -60,6 +60,9 @@ type SimulationScreen interface {
// GetCursor returns the cursor details.
GetCursor() (x int, y int, visible bool)
// GetTitle gets the set title
GetTitle() string
}
// SimCell represents a simulated screen cell. The purpose of this
@ -98,6 +101,7 @@ type simscreen struct {
fillchar rune
fillstyle Style
fallback map[rune]string
title string
Screen
sync.Mutex
@ -495,3 +499,11 @@ func (s *simscreen) EventQ() chan Event {
func (s *simscreen) StopQ() <-chan struct{} {
return s.quit
}
func (s *simscreen) SetTitle(title string) {
s.title = title
}
func (s *simscreen) GetTitle() string {
return s.title
}

View File

@ -233,6 +233,7 @@ type Terminfo struct {
EnterUrl string
ExitUrl string
SetWindowSize string
SetWindowTitle string // no terminfo extension
EnableFocusReporting string
DisableFocusReporting string
DisableAutoMargin string // smam

View File

@ -171,6 +171,10 @@ type tScreen struct {
mouseFlags MouseFlags
pasteEnabled bool
focusEnabled bool
setTitle string
saveTitle string
restoreTitle string
title string
sync.Mutex
}
@ -414,27 +418,37 @@ func (t *tScreen) prepareExtendedOSC() {
if t.ti.EnterUrl != "" {
t.enterUrl = t.ti.EnterUrl
t.exitUrl = t.ti.ExitUrl
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enterUrl = "\x1b]8;%p2%s;%p1%s\x1b\\"
t.exitUrl = "\x1b]8;;\x1b\\"
}
if t.ti.SetWindowSize != "" {
t.setWinSize = t.ti.SetWindowSize
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.setWinSize = "\x1b[8;%p1%p2%d;%dt"
}
if t.ti.EnableFocusReporting != "" {
t.enableFocus = t.ti.EnableFocusReporting
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.enableFocus = "\x1b[?1004h"
}
if t.ti.DisableFocusReporting != "" {
t.disableFocus = t.ti.DisableFocusReporting
} else if t.ti.Mouse != "" {
} else if t.ti.Mouse != "" || t.ti.XTermLike {
t.disableFocus = "\x1b[?1004l"
}
if t.ti.SetWindowTitle != "" {
t.setTitle = t.ti.SetWindowTitle
} else if t.ti.XTermLike {
t.saveTitle = "\x1b[22;2t"
t.restoreTitle = "\x1b[23;2t"
// this also tries to request that UTF-8 is allowed in the title
t.setTitle = "\x1b[>2t\x1b]2;%p1%s\x1b\\"
}
}
func (t *tScreen) prepareCursorStyles() {
@ -1938,12 +1952,18 @@ func (t *tScreen) engage() error {
// (In theory there could be terminals that don't support X,Y cursor
// positions without a setup command, but we don't support them.)
t.TPuts(ti.EnterCA)
if t.saveTitle != "" {
t.TPuts(t.saveTitle)
}
}
t.TPuts(ti.EnterKeypad)
t.TPuts(ti.HideCursor)
t.TPuts(ti.EnableAcs)
t.TPuts(ti.DisableAutoMargin)
t.TPuts(ti.Clear)
if t.title != "" && t.setTitle != "" {
t.TPuts(t.ti.TParm(t.setTitle, t.title))
}
t.wg.Add(2)
go t.inputLoop(stopQ)
@ -1987,6 +2007,9 @@ func (t *tScreen) disengage() {
t.TPuts(ti.ExitKeypad)
t.TPuts(ti.EnableAutoMargin)
if os.Getenv("TCELL_ALTSCREEN") != "disable" {
if t.restoreTitle != "" {
t.TPuts(t.restoreTitle)
}
t.TPuts(ti.Clear) // only needed if ExitCA is empty
t.TPuts(ti.ExitCA)
}
@ -2021,3 +2044,12 @@ func (t *tScreen) EventQ() chan Event {
func (t *tScreen) GetCells() *CellBuffer {
return &t.cells
}
func (t *tScreen) SetTitle(title string) {
t.Lock()
t.title = title
if t.setTitle != "" && t.running {
t.TPuts(t.ti.TParm(t.setTitle, title))
}
t.Unlock()
}

View File

@ -222,6 +222,10 @@ function beep() {
beepAudio.play();
}
function setTitle(title) {
document.title = title;
}
function intToHex(n) {
return "#" + n.toString(16).padStart(6, "0");
}

View File

@ -523,6 +523,10 @@ func (t *wScreen) StopQ() <-chan struct{} {
return t.quit
}
func (t *wScreen) SetTitle(title string) {
js.Global().Call("setTitle", title)
}
// WebKeyNames maps string names reported from HTML
// (KeyboardEvent.key) to tcell accepted keys.
var WebKeyNames = map[string]Key{