Skip to content

Commit

Permalink
fixes #356 Vim cursors shapes?
Browse files Browse the repository at this point in the history
This adds a new method, SetCursorStyle() to the screen API.
It also automatically restores the cursor when disengaging to
the default cursor.  Modern terminals (and Windows console) support
this.
  • Loading branch information
gdamore committed Sep 29, 2021
1 parent 8d48900 commit 761abf6
Show file tree
Hide file tree
Showing 7 changed files with 276 additions and 71 deletions.
91 changes: 91 additions & 0 deletions _demos/cursors.go
@@ -0,0 +1,91 @@
// +build ignore

// Copyright 2021 The TCell Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// 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 (
"fmt"
"github.com/gdamore/tcell/v2"
"os"
)

func main() {
tcell.SetEncodingFallback(tcell.EncodingFallbackASCII)
s, e := tcell.NewScreen()
if e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(1)
}
if e = s.Init(); e != nil {
fmt.Fprintf(os.Stderr, "%v\n", e)
os.Exit(1)
}

s.SetStyle(tcell.StyleDefault)
s.Clear()

s.SetCell(2, 2, tcell.StyleDefault, '0')
s.SetCursorStyle(tcell.CursorStyleDefault)
s.ShowCursor(3, 2)
quit := make(chan struct{})
style := tcell.StyleDefault
go func() {
for {
ev := s.PollEvent()
switch ev := ev.(type) {
case *tcell.EventKey:
switch ev.Key() {
case tcell.KeyRune:
switch ev.Rune() {
case '0':
s.SetContent(2, 2, '0', nil, style)
s.SetCursorStyle(tcell.CursorStyleDefault)
case '1':
s.SetContent(2, 2, '1', nil, style)
s.SetCursorStyle(tcell.CursorStyleBlinkingBlock)
case '2':
s.SetCell(2, 2, tcell.StyleDefault, '2')
s.SetCursorStyle(tcell.CursorStyleSteadyBlock)
case '3':
s.SetCell(2, 2, tcell.StyleDefault, '3')
s.SetCursorStyle(tcell.CursorStyleBlinkingUnderline)
case '4':
s.SetCell(2, 2, tcell.StyleDefault, '4')
s.SetCursorStyle(tcell.CursorStyleSteadyUnderline)
case '5':
s.SetCell(2, 2, tcell.StyleDefault, '5')
s.SetCursorStyle(tcell.CursorStyleBlinkingBar)
case '6':
s.SetCell(2, 2, tcell.StyleDefault, '6')
s.SetCursorStyle(tcell.CursorStyleSteadyBar)
}
s.Show()

case tcell.KeyEscape, tcell.KeyEnter, tcell.KeyCtrlC:
close(quit)
return
case tcell.KeyCtrlL:
s.Sync()
}
case *tcell.EventResize:
s.Sync()
}
}
}()
<-quit
s.Fini()
}
67 changes: 50 additions & 17 deletions console_win.go
Expand Up @@ -46,11 +46,12 @@ type cScreen struct {
w int
h int

oscreen consoleInfo
ocursor cursorInfo
oimode uint32
oomode uint32
cells CellBuffer
oscreen consoleInfo
ocursor cursorInfo
cursorStyle CursorStyle
oimode uint32
oomode uint32
cells CellBuffer

finiOnce sync.Once

Expand Down Expand Up @@ -138,20 +139,37 @@ const (

const (
// VT100/XTerm escapes understood by the console
vtShowCursor = "\x1b[?25h"
vtHideCursor = "\x1b[?25l"
vtCursorPos = "\x1b[%d;%dH" // Note that it is Y then X
vtSgr0 = "\x1b[0m"
vtBold = "\x1b[1m"
vtUnderline = "\x1b[4m"
vtBlink = "\x1b[5m" // Not sure this is processed
vtReverse = "\x1b[7m"
vtSetFg = "\x1b[38;5;%dm"
vtSetBg = "\x1b[48;5;%dm"
vtSetFgRGB = "\x1b[38;2;%d;%d;%dm" // RGB
vtSetBgRGB = "\x1b[48;2;%d;%d;%dm" // RGB
vtShowCursor = "\x1b[?25h"
vtHideCursor = "\x1b[?25l"
vtCursorPos = "\x1b[%d;%dH" // Note that it is Y then X
vtSgr0 = "\x1b[0m"
vtBold = "\x1b[1m"
vtUnderline = "\x1b[4m"
vtBlink = "\x1b[5m" // Not sure this is processed
vtReverse = "\x1b[7m"
vtSetFg = "\x1b[38;5;%dm"
vtSetBg = "\x1b[48;5;%dm"
vtSetFgRGB = "\x1b[38;2;%d;%d;%dm" // RGB
vtSetBgRGB = "\x1b[48;2;%d;%d;%dm" // RGB
vtCursorDefault = "\x1b[0 q"
vtCursorBlinkingBlock = "\x1b[1 q"
vtCursorSteadyBlock = "\x1b[2 q"
vtCursorBlinkingUnderline = "\x1b[3 q"
vtCursorSteadyUnderline = "\x1b[4 q"
vtCursorBlinkingBar = "\x1b[5 q"
vtCursorSteadyBar = "\x1b[6 q"
)

var vtCursorStyles = map[CursorStyle]string{
CursorStyleDefault: vtCursorDefault,
CursorStyleBlinkingBlock: vtCursorBlinkingBlock,
CursorStyleSteadyBlock: vtCursorSteadyBlock,
CursorStyleBlinkingUnderline: vtCursorBlinkingUnderline,
CursorStyleSteadyUnderline: vtCursorSteadyUnderline,
CursorStyleBlinkingBar: vtCursorBlinkingBar,
CursorStyleSteadyBar: vtCursorSteadyBar,
}

// NewConsoleScreen returns a Screen for the Windows console associated
// with the current process. The Screen makes use of the Windows Console
// API to display content and read events.
Expand Down Expand Up @@ -280,6 +298,9 @@ func (s *cScreen) disengage() {

s.wg.Wait()

if s.vten {
s.emitVtString(vtCursorStyles[CursorStyleDefault])
}
s.setInMode(s.oimode)
s.setOutMode(s.oomode)
s.setBufferSize(int(s.oscreen.size.x), int(s.oscreen.size.y))
Expand Down Expand Up @@ -406,6 +427,7 @@ func (s *cScreen) emitVtString(vs string) {
func (s *cScreen) showCursor() {
if s.vten {
s.emitVtString(vtShowCursor)
s.emitVtString(vtCursorStyles[s.cursorStyle])
} else {
s.setCursorInfo(&cursorInfo{size: 100, visible: 1})
}
Expand All @@ -429,6 +451,17 @@ func (s *cScreen) ShowCursor(x, y int) {
s.Unlock()
}

func (s *cScreen) SetCursorStyle(cs CursorStyle) {
s.Lock()
if !s.fini {
if _, ok := vtCursorStyles[cs]; ok {
s.cursorStyle = cs
s.doCursor()
}
}
s.Unlock()
}

func (s *cScreen) doCursor() {
x, y := s.curx, s.cury

Expand Down
21 changes: 20 additions & 1 deletion screen.go
Expand Up @@ -71,9 +71,14 @@ type Screen interface {
ShowCursor(x int, y int)

// HideCursor is used to hide the cursor. Its an alias for
// ShowCursor(-1, -1).
// ShowCursor(-1, -1).sim
HideCursor()

// 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)

// Size returns the screen size as width, height. This changes in
// response to a call to Clear or Flush.
Size() (width, height int)
Expand Down Expand Up @@ -258,3 +263,17 @@ const (
MouseDragEvents = MouseFlags(2) // Click-drag events (includes button events)
MouseMotionEvents = MouseFlags(4) // All mouse events (includes click and drag events)
)

// CursorStyle represents a given cursor style, which can include the shape and
// whether the cursor blinks or is solid. Support for changing these is not universal.
type CursorStyle int

const (
CursorStyleDefault = CursorStyle(iota) // The default
CursorStyleBlinkingBlock
CursorStyleSteadyBlock
CursorStyleBlinkingUnderline
CursorStyleSteadyUnderline
CursorStyleBlinkingBar
CursorStyleSteadyBar
)
2 changes: 2 additions & 0 deletions simulation.go
Expand Up @@ -281,6 +281,8 @@ func (s *simscreen) hideCursor() {
s.cursorvis = false
}

func (s *simscreen) SetCursorStyle(CursorStyle) {}

func (s *simscreen) Show() {
s.Lock()
s.resize()
Expand Down
7 changes: 7 additions & 0 deletions terminfo/mkinfo.go
Expand Up @@ -609,6 +609,13 @@ func dotGoInfo(w io.Writer, terms []*TData) {
dotGoAddFlag(w, "TrueColor", t.TrueColor)
dotGoAddFlag(w, "AutoMargin", t.AutoMargin)
dotGoAddStr(w, "InsertChar", t.InsertChar)
dotGoAddStr(w, "CursorDefault", t.CursorDefault)
dotGoAddStr(w, "CursorBlinkingBlock", t.CursorBlinkingBlock)
dotGoAddStr(w, "CursorSteadyBlock", t.CursorSteadyBlock)
dotGoAddStr(w, "CursorBlinkingUnderline", t.CursorBlinkingUnderline)
dotGoAddStr(w, "CursorSteadyUnderline", t.CursorSteadyUnderline)
dotGoAddStr(w, "CursorBlinkingBar", t.CursorBlinkingBar)
dotGoAddStr(w, "CursorSteadyBar", t.CursorSteadyBar)
fmt.Fprintln(w, "\t})")
}
fmt.Fprintln(w, "}")
Expand Down
113 changes: 60 additions & 53 deletions terminfo/terminfo.go
Expand Up @@ -167,59 +167,66 @@ type Terminfo struct {
// Terminal support for these are going to vary amongst XTerm
// emulations, so don't depend too much on them in your application.

StrikeThrough string // smxx
SetFgBg string // setfgbg
SetFgBgRGB string // setfgbgrgb
SetFgRGB string // setfrgb
SetBgRGB string // setbrgb
KeyShfUp string // shift-up
KeyShfDown string // shift-down
KeyShfPgUp string // shift-kpp
KeyShfPgDn string // shift-knp
KeyCtrlUp string // ctrl-up
KeyCtrlDown string // ctrl-left
KeyCtrlRight string // ctrl-right
KeyCtrlLeft string // ctrl-left
KeyMetaUp string // meta-up
KeyMetaDown string // meta-left
KeyMetaRight string // meta-right
KeyMetaLeft string // meta-left
KeyAltUp string // alt-up
KeyAltDown string // alt-left
KeyAltRight string // alt-right
KeyAltLeft string // alt-left
KeyCtrlHome string
KeyCtrlEnd string
KeyMetaHome string
KeyMetaEnd string
KeyAltHome string
KeyAltEnd string
KeyAltShfUp string
KeyAltShfDown string
KeyAltShfLeft string
KeyAltShfRight string
KeyMetaShfUp string
KeyMetaShfDown string
KeyMetaShfLeft string
KeyMetaShfRight string
KeyCtrlShfUp string
KeyCtrlShfDown string
KeyCtrlShfLeft string
KeyCtrlShfRight string
KeyCtrlShfHome string
KeyCtrlShfEnd string
KeyAltShfHome string
KeyAltShfEnd string
KeyMetaShfHome string
KeyMetaShfEnd string
EnablePaste string // bracketed paste mode
DisablePaste string
PasteStart string
PasteEnd string
Modifiers int
InsertChar string // string to insert a character (ich1)
AutoMargin bool // true if writing to last cell in line advances
TrueColor bool // true if the terminal supports direct color
StrikeThrough string // smxx
SetFgBg string // setfgbg
SetFgBgRGB string // setfgbgrgb
SetFgRGB string // setfrgb
SetBgRGB string // setbrgb
KeyShfUp string // shift-up
KeyShfDown string // shift-down
KeyShfPgUp string // shift-kpp
KeyShfPgDn string // shift-knp
KeyCtrlUp string // ctrl-up
KeyCtrlDown string // ctrl-left
KeyCtrlRight string // ctrl-right
KeyCtrlLeft string // ctrl-left
KeyMetaUp string // meta-up
KeyMetaDown string // meta-left
KeyMetaRight string // meta-right
KeyMetaLeft string // meta-left
KeyAltUp string // alt-up
KeyAltDown string // alt-left
KeyAltRight string // alt-right
KeyAltLeft string // alt-left
KeyCtrlHome string
KeyCtrlEnd string
KeyMetaHome string
KeyMetaEnd string
KeyAltHome string
KeyAltEnd string
KeyAltShfUp string
KeyAltShfDown string
KeyAltShfLeft string
KeyAltShfRight string
KeyMetaShfUp string
KeyMetaShfDown string
KeyMetaShfLeft string
KeyMetaShfRight string
KeyCtrlShfUp string
KeyCtrlShfDown string
KeyCtrlShfLeft string
KeyCtrlShfRight string
KeyCtrlShfHome string
KeyCtrlShfEnd string
KeyAltShfHome string
KeyAltShfEnd string
KeyMetaShfHome string
KeyMetaShfEnd string
EnablePaste string // bracketed paste mode
DisablePaste string
PasteStart string
PasteEnd string
Modifiers int
InsertChar string // string to insert a character (ich1)
AutoMargin bool // true if writing to last cell in line advances
TrueColor bool // true if the terminal supports direct color
CursorDefault string
CursorBlinkingBlock string
CursorSteadyBlock string
CursorBlinkingUnderline string
CursorSteadyUnderline string
CursorBlinkingBar string
CursorSteadyBar string
}

const (
Expand Down

0 comments on commit 761abf6

Please sign in to comment.