mirror of https://github.com/gdamore/tcell.git
fixes #666 cursor color
This adds a new optional parameter to screen.SetCursorStyle, which is a color. The cursors demo is enhanced to show this. This ability is supported on screen types, provided the underlying terminal supports the capability.
This commit is contained in:
parent
652ba11803
commit
887cf2766e
|
@ -15,7 +15,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// beep makes a beep every second until you press ESC
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -52,6 +51,7 @@ func main() {
|
|||
style := tcell.StyleDefault
|
||||
go func() {
|
||||
for {
|
||||
s.Show()
|
||||
ev := s.PollEvent()
|
||||
switch ev := ev.(type) {
|
||||
case *tcell.EventKey:
|
||||
|
@ -60,27 +60,26 @@ func main() {
|
|||
switch ev.Rune() {
|
||||
case '0':
|
||||
s.SetContent(2, 2, '0', nil, style)
|
||||
s.SetCursorStyle(tcell.CursorStyleDefault)
|
||||
s.SetCursorStyle(tcell.CursorStyleDefault, tcell.ColorReset)
|
||||
case '1':
|
||||
s.SetContent(2, 2, '1', nil, style)
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingBlock)
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingBlock, tcell.ColorGreen)
|
||||
case '2':
|
||||
s.SetCell(2, 2, tcell.StyleDefault, '2')
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyBlock)
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyBlock, tcell.ColorBlue)
|
||||
case '3':
|
||||
s.SetCell(2, 2, tcell.StyleDefault, '3')
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingUnderline)
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingUnderline, tcell.ColorRed)
|
||||
case '4':
|
||||
s.SetCell(2, 2, tcell.StyleDefault, '4')
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyUnderline)
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyUnderline, tcell.ColorOrange)
|
||||
case '5':
|
||||
s.SetCell(2, 2, tcell.StyleDefault, '5')
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingBar)
|
||||
s.SetCursorStyle(tcell.CursorStyleBlinkingBar, tcell.ColorYellow)
|
||||
case '6':
|
||||
s.SetCell(2, 2, tcell.StyleDefault, '6')
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyBar)
|
||||
s.SetCursorStyle(tcell.CursorStyleSteadyBar, tcell.ColorPink)
|
||||
}
|
||||
s.Show()
|
||||
|
||||
case tcell.KeyEscape, tcell.KeyEnter, tcell.KeyCtrlC:
|
||||
close(quit)
|
||||
|
|
|
@ -49,6 +49,7 @@ type cScreen struct {
|
|||
oscreen consoleInfo
|
||||
ocursor cursorInfo
|
||||
cursorStyle CursorStyle
|
||||
cursorColor Color
|
||||
oimode uint32
|
||||
oomode uint32
|
||||
cells CellBuffer
|
||||
|
@ -173,6 +174,8 @@ const (
|
|||
vtUnderColorReset = "\x1b[59m"
|
||||
vtEnterUrl = "\x1b]8;%s;%s\x1b\\" // NB arg 1 is id, arg 2 is url
|
||||
vtExitUrl = "\x1b]8;;\x1b\\"
|
||||
vtCursorColorRGB = "\x1b]12;#%02x%02x%02x\007"
|
||||
vtCursorColorReset = "\x1b]112\007"
|
||||
)
|
||||
|
||||
var vtCursorStyles = map[CursorStyle]string{
|
||||
|
@ -344,6 +347,7 @@ func (s *cScreen) disengage() {
|
|||
|
||||
if s.vten {
|
||||
s.emitVtString(vtCursorStyles[CursorStyleDefault])
|
||||
s.emitVtString(vtCursorColorReset)
|
||||
s.emitVtString(vtEnableAm)
|
||||
if !s.disableAlt {
|
||||
s.emitVtString(vtExitCA)
|
||||
|
@ -435,6 +439,12 @@ func (s *cScreen) showCursor() {
|
|||
if s.vten {
|
||||
s.emitVtString(vtShowCursor)
|
||||
s.emitVtString(vtCursorStyles[s.cursorStyle])
|
||||
if s.cursorColor == ColorReset {
|
||||
s.emitVtString(vtCursorColorReset)
|
||||
} else if s.cursorColor.Valid() {
|
||||
r, g, b := s.cursorColor.RGB()
|
||||
s.emitVtString(fmt.Sprintf(vtCursorColorRGB, r, g, b))
|
||||
}
|
||||
} else {
|
||||
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
|
||||
}
|
||||
|
@ -458,11 +468,12 @@ func (s *cScreen) ShowCursor(x, y int) {
|
|||
s.Unlock()
|
||||
}
|
||||
|
||||
func (s *cScreen) SetCursorStyle(cs CursorStyle) {
|
||||
func (s *cScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||
s.Lock()
|
||||
if !s.fini {
|
||||
if _, ok := vtCursorStyles[cs]; ok {
|
||||
s.cursorStyle = cs
|
||||
s.cursorColor = cc
|
||||
s.doCursor()
|
||||
}
|
||||
}
|
||||
|
@ -1100,7 +1111,6 @@ func (s *cScreen) setCursorInfo(info *cursorInfo) {
|
|||
_, _, _ = procSetConsoleCursorInfo.Call(
|
||||
uintptr(s.out),
|
||||
uintptr(unsafe.Pointer(info)))
|
||||
|
||||
}
|
||||
|
||||
func (s *cScreen) setCursorPos(x, y int, vtEnable bool) {
|
||||
|
|
17
screen.go
17
screen.go
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 The TCell Authors
|
||||
// Copyright 2024 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
|
@ -79,8 +79,9 @@ type Screen interface {
|
|||
|
||||
// SetCursorStyle is used to set the cursor style. If the style
|
||||
// is not supported (or cursor styles are not supported at all),
|
||||
// then this will have no effect.
|
||||
SetCursorStyle(CursorStyle)
|
||||
// then this will have no effect. Color will be changed if supplied,
|
||||
// and the terminal supports doing so.
|
||||
SetCursorStyle(CursorStyle, ...Color)
|
||||
|
||||
// Size returns the screen size as width, height. This changes in
|
||||
// response to a call to Clear or Flush.
|
||||
|
@ -312,7 +313,7 @@ type screenImpl interface {
|
|||
SetStyle(style Style)
|
||||
ShowCursor(x int, y int)
|
||||
HideCursor()
|
||||
SetCursorStyle(CursorStyle)
|
||||
SetCursor(CursorStyle, Color)
|
||||
Size() (width, height int)
|
||||
EnableMouse(...MouseFlags)
|
||||
DisableMouse()
|
||||
|
@ -464,3 +465,11 @@ func (b *baseScreen) PostEvent(ev Event) error {
|
|||
return ErrEventQFull
|
||||
}
|
||||
}
|
||||
|
||||
func (b *baseScreen) SetCursorStyle(cs CursorStyle, ccs ...Color) {
|
||||
if len(ccs) > 0 {
|
||||
b.SetCursor(cs, ccs[0])
|
||||
} else {
|
||||
b.SetCursor(cs, ColorNone)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 The TCell Authors
|
||||
// Copyright 2024 The TCell Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use file except in compliance with the License.
|
||||
|
@ -239,7 +239,7 @@ func (s *simscreen) hideCursor() {
|
|||
s.cursorvis = false
|
||||
}
|
||||
|
||||
func (s *simscreen) SetCursorStyle(CursorStyle) {}
|
||||
func (s *simscreen) SetCursor(CursorStyle, Color) {}
|
||||
|
||||
func (s *simscreen) Show() {
|
||||
s.Lock()
|
||||
|
|
|
@ -227,6 +227,9 @@ type Terminfo struct {
|
|||
CursorSteadyUnderline string
|
||||
CursorBlinkingBar string
|
||||
CursorSteadyBar string
|
||||
CursorColor string // nothing uses it yet
|
||||
CursorColorRGB string // Cs (but not really because Cs uses X11 color string)
|
||||
CursorColorReset string // Cr
|
||||
EnterUrl string
|
||||
ExitUrl string
|
||||
SetWindowSize string
|
||||
|
|
30
tscreen.go
30
tscreen.go
|
@ -160,6 +160,9 @@ type tScreen struct {
|
|||
underFg string
|
||||
cursorStyles map[CursorStyle]string
|
||||
cursorStyle CursorStyle
|
||||
cursorColor Color
|
||||
cursorRGB string
|
||||
cursorFg string
|
||||
saved *term.State
|
||||
stopQ chan struct{}
|
||||
eventQ chan Event
|
||||
|
@ -460,7 +463,20 @@ func (t *tScreen) prepareCursorStyles() {
|
|||
CursorStyleSteadyBar: "\x1b[6 q",
|
||||
}
|
||||
}
|
||||
if t.ti.CursorColorRGB != "" {
|
||||
// if it was X11 style with just a single %p1%s, then convert
|
||||
t.cursorRGB = t.ti.CursorColorRGB
|
||||
}
|
||||
if t.ti.CursorColorReset != "" {
|
||||
t.cursorFg = t.ti.CursorColorReset
|
||||
}
|
||||
if t.cursorRGB == "" {
|
||||
t.cursorRGB = "\x1b]12;%p1%s\007"
|
||||
t.cursorFg = "\x1b]112\007"
|
||||
}
|
||||
|
||||
// convert XTERM style color names to RGB color code. We have no way to do palette colors
|
||||
t.cursorRGB = strings.Replace(t.cursorRGB, "%p1%s", "#%p1%02x%p2%02x%p3%02x", 1)
|
||||
}
|
||||
|
||||
func (t *tScreen) prepareKey(key Key, val string) {
|
||||
|
@ -912,9 +928,10 @@ func (t *tScreen) ShowCursor(x, y int) {
|
|||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *tScreen) SetCursorStyle(cs CursorStyle) {
|
||||
func (t *tScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||
t.Lock()
|
||||
t.cursorStyle = cs
|
||||
t.cursorColor = cc
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
|
@ -937,6 +954,14 @@ func (t *tScreen) showCursor() {
|
|||
t.TPuts(esc)
|
||||
}
|
||||
}
|
||||
if t.cursorRGB != "" {
|
||||
if t.cursorColor == ColorReset {
|
||||
t.TPuts(t.cursorFg)
|
||||
} else if t.cursorColor.Valid() {
|
||||
r, g, b := t.cursorColor.RGB()
|
||||
t.TPuts(t.ti.TParm(t.cursorRGB, int(r), int(g), int(b)))
|
||||
}
|
||||
}
|
||||
t.cx = x
|
||||
t.cy = y
|
||||
}
|
||||
|
@ -1954,6 +1979,9 @@ func (t *tScreen) disengage() {
|
|||
if t.cursorStyles != nil && t.cursorStyle != CursorStyleDefault {
|
||||
t.TPuts(t.cursorStyles[CursorStyleDefault])
|
||||
}
|
||||
if t.cursorFg != "" && t.cursorColor.Valid() {
|
||||
t.TPuts(t.cursorFg)
|
||||
}
|
||||
t.TPuts(ti.ResetFgBg)
|
||||
t.TPuts(ti.AttrOff)
|
||||
t.TPuts(ti.ExitKeypad)
|
||||
|
|
|
@ -21,6 +21,7 @@ const beepAudio = new Audio("beep.wav");
|
|||
var cx = -1;
|
||||
var cy = -1;
|
||||
var cursorClass = "cursor-blinking-block";
|
||||
var cursorColor = "";
|
||||
|
||||
var content; // {data: row[height], dirty: bool}
|
||||
// row = {data: element[width], previous: span}
|
||||
|
@ -185,12 +186,18 @@ function displayCursor() {
|
|||
content.data[cy].data[cx] = span;
|
||||
}
|
||||
|
||||
if (cursorColor != "") {
|
||||
term.style.setProperty("--cursor-color", cursorColor);
|
||||
} else {
|
||||
term.style.setProperty("--cursor-color", "lightgrey");
|
||||
}
|
||||
|
||||
content.data[cy].data[cx].classList.add(cursorClass);
|
||||
}
|
||||
}
|
||||
|
||||
function setCursorStyle(newClass) {
|
||||
if (newClass == cursorClass) {
|
||||
function setCursorStyle(newClass, newColor) {
|
||||
if (newClass == cursorClass && newColor == cursorColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -207,6 +214,7 @@ function setCursorStyle(newClass) {
|
|||
}
|
||||
|
||||
cursorClass = newClass;
|
||||
cursorColor = newColor;
|
||||
}
|
||||
|
||||
function beep() {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
--cursor-color: lightgrey;
|
||||
}
|
||||
|
||||
/* Style attributes */
|
||||
|
@ -64,26 +65,26 @@
|
|||
/* Cursor styles */
|
||||
|
||||
.cursor-steady-block {
|
||||
background-color: lightgrey !important;
|
||||
background-color: var(--cursor-color) !important;
|
||||
}
|
||||
.cursor-blinking-block {
|
||||
animation: blinking-block 1s step-start infinite !important;
|
||||
}
|
||||
@keyframes blinking-block {
|
||||
50% {
|
||||
background-color: lightgrey;
|
||||
background-color: var(--cursor-color);
|
||||
}
|
||||
}
|
||||
|
||||
.cursor-steady-underline {
|
||||
text-decoration: underline lightgrey !important;
|
||||
text-decoration: underline var(--cursor-color) !important;
|
||||
}
|
||||
.cursor-blinking-underline {
|
||||
animation: blinking-underline 1s step-start infinite !important;
|
||||
}
|
||||
@keyframes blinking-underline {
|
||||
50% {
|
||||
text-decoration: underline lightgrey;
|
||||
text-decoration: underline var(--cursor-color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +94,7 @@
|
|||
.cursor-steady-bar:before {
|
||||
content: " ";
|
||||
width: 2px;
|
||||
background-color: lightgrey !important;
|
||||
background-color: var(--cursor-color) !important;
|
||||
display: inline-block;
|
||||
}
|
||||
.cursor-blinking-bar {
|
||||
|
@ -102,7 +103,7 @@
|
|||
.cursor-blinking-bar:before {
|
||||
content: " ";
|
||||
width: 2px;
|
||||
background-color: lightgrey !important;
|
||||
background-color: var(--cursor-color) !important;
|
||||
display: inline-block;
|
||||
animation: blinker 1s step-start infinite;
|
||||
}
|
||||
|
|
11
wscreen.go
11
wscreen.go
|
@ -19,11 +19,13 @@ package tcell
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gdamore/tcell/v2/terminfo"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall/js"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gdamore/tcell/v2/terminfo"
|
||||
)
|
||||
|
||||
func NewTerminfoScreen() (Screen, error) {
|
||||
|
@ -158,9 +160,12 @@ func (t *wScreen) ShowCursor(x, y int) {
|
|||
t.Unlock()
|
||||
}
|
||||
|
||||
func (t *wScreen) SetCursorStyle(cs CursorStyle) {
|
||||
func (t *wScreen) SetCursor(cs CursorStyle, cc Color) {
|
||||
if !cc.Valid() {
|
||||
cc = ColorLightGray
|
||||
}
|
||||
t.Lock()
|
||||
js.Global().Call("setCursorStyle", curStyleClasses[cs])
|
||||
js.Global().Call("setCursorStyle", curStyleClasses[cs], fmt.Sprintf("#%06x", cc.Hex()))
|
||||
t.Unlock()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue