Finish support for a fake cursor

This commit is contained in:
Zachary Yedidia 2020-01-01 22:40:51 -05:00
parent d6dd838abd
commit 6d0128059b
8 changed files with 86 additions and 35 deletions

View file

@ -102,7 +102,7 @@ func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tcell.Style)
func (w *BufWindow) Clear() { func (w *BufWindow) Clear() {
for y := 0; y < w.Height; y++ { for y := 0; y < w.Height; y++ {
for x := 0; x < w.Width; x++ { for x := 0; x < w.Width; x++ {
screen.Screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle) screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle)
} }
} }
} }
@ -298,9 +298,9 @@ func (w *BufWindow) drawGutter(vloc *buffer.Loc, bloc *buffer.Loc) {
break break
} }
} }
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s)
vloc.X++ vloc.X++
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, char, nil, s)
vloc.X++ vloc.X++
} }
@ -309,21 +309,21 @@ func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped bool, maxL
// Write the spaces before the line number if necessary // Write the spaces before the line number if necessary
for i := 0; i < maxLineNumLength-len(lineNum); i++ { for i := 0; i < maxLineNumLength-len(lineNum); i++ {
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
vloc.X++ vloc.X++
} }
// Write the actual line number // Write the actual line number
for _, ch := range lineNum { for _, ch := range lineNum {
if softwrapped { if softwrapped {
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
} else { } else {
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ch, nil, lineNumStyle) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ch, nil, lineNumStyle)
} }
vloc.X++ vloc.X++
} }
// Write the extra space // Write the extra space
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, ' ', nil, lineNumStyle)
vloc.X++ vloc.X++
} }
@ -342,7 +342,7 @@ func (w *BufWindow) showCursor(x, y int, main bool) {
if main { if main {
screen.ShowCursor(x, y) screen.ShowCursor(x, y)
} else { } else {
screen.ShowFakeCursor(x, y) screen.ShowFakeCursorMulti(x, y)
} }
} }
} }
@ -513,7 +513,7 @@ func (w *BufWindow) displayBuffer() {
} }
} }
screen.Screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style) screen.SetContent(w.X+vloc.X, w.Y+vloc.Y, r, nil, style)
if showcursor { if showcursor {
for _, c := range cursors { for _, c := range cursors {
@ -591,7 +591,7 @@ func (w *BufWindow) displayBuffer() {
curStyle = style.Background(fg) curStyle = style.Background(fg)
} }
} }
screen.Screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle) screen.SetContent(i+w.X, vloc.Y+w.Y, ' ', nil, curStyle)
} }
draw(' ', curStyle, true) draw(' ', curStyle, true)
@ -617,7 +617,7 @@ func (w *BufWindow) displayStatusLine() {
} else if w.Y+w.Height != infoY { } else if w.Y+w.Height != infoY {
w.drawStatus = true w.drawStatus = true
for x := w.X; x < w.X+w.Width; x++ { for x := w.X; x < w.X+w.Width; x++ {
screen.Screen.SetContent(x, w.Y+w.Height-1, '-', nil, config.DefStyle.Reverse(true)) screen.SetContent(x, w.Y+w.Height-1, '-', nil, config.DefStyle.Reverse(true))
} }
} else { } else {
w.drawStatus = false w.drawStatus = false
@ -637,7 +637,7 @@ func (w *BufWindow) displayScrollBar() {
} }
barstart := w.Y + int(float64(w.StartLine)/float64(w.Buf.LinesNum())*float64(w.Height)) barstart := w.Y + int(float64(w.StartLine)/float64(w.Buf.LinesNum())*float64(w.Height))
for y := barstart; y < util.Min(barstart+barsize, w.Y+bufHeight); y++ { for y := barstart; y < util.Min(barstart+barsize, w.Y+bufHeight); y++ {
screen.Screen.SetContent(scrollX, y, '|', nil, config.DefStyle.Reverse(true)) screen.SetContent(scrollX, y, '|', nil, config.DefStyle.Reverse(true))
} }
} }
} }

View file

@ -74,7 +74,7 @@ func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
func (i *InfoWindow) Clear() { func (i *InfoWindow) Clear() {
for x := 0; x < i.Width; x++ { for x := 0; x < i.Width; x++ {
screen.Screen.SetContent(x, i.Y, ' ', nil, i.defStyle()) screen.SetContent(x, i.Y, ' ', nil, i.defStyle())
} }
} }
@ -111,7 +111,7 @@ func (i *InfoWindow) displayBuffer() {
if j > 0 { if j > 0 {
c = ' ' c = ' '
} }
screen.Screen.SetContent(vlocX, i.Y, c, nil, style) screen.SetContent(vlocX, i.Y, c, nil, style)
} }
vlocX++ vlocX++
} }
@ -167,9 +167,9 @@ func (i *InfoWindow) displayKeyMenu() {
for y := 0; y < len(keydisplay); y++ { for y := 0; y < len(keydisplay); y++ {
for x := 0; x < i.Width; x++ { for x := 0; x < i.Width; x++ {
if x < len(keydisplay[y]) { if x < len(keydisplay[y]) {
screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, i.defStyle()) screen.SetContent(x, i.Y-len(keydisplay)+y, rune(keydisplay[y][x]), nil, i.defStyle())
} else { } else {
screen.Screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, i.defStyle()) screen.SetContent(x, i.Y-len(keydisplay)+y, ' ', nil, i.defStyle())
} }
} }
} }
@ -194,7 +194,7 @@ func (i *InfoWindow) Display() {
display := i.Msg display := i.Msg
for _, c := range display { for _, c := range display {
screen.Screen.SetContent(x, i.Y, c, nil, style) screen.SetContent(x, i.Y, c, nil, style)
x += runewidth.RuneWidth(c) x += runewidth.RuneWidth(c)
} }
@ -219,13 +219,13 @@ func (i *InfoWindow) Display() {
style = style.Reverse(true) style = style.Reverse(true)
} }
for _, r := range s { for _, r := range s {
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style) screen.SetContent(x, i.Y-keymenuOffset-1, r, nil, style)
x++ x++
if x >= i.Width { if x >= i.Width {
return return
} }
} }
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle) screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
x++ x++
if x >= i.Width { if x >= i.Width {
return return
@ -233,7 +233,7 @@ func (i *InfoWindow) Display() {
} }
for x < i.Width { for x < i.Width {
screen.Screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle) screen.SetContent(x, i.Y-keymenuOffset-1, ' ', nil, statusLineStyle)
x++ x++
} }
} }

View file

@ -118,13 +118,13 @@ func (s *StatusLine) Display() {
style = style.Reverse(true) style = style.Reverse(true)
} }
for _, r := range sug { for _, r := range sug {
screen.Screen.SetContent(x, y-keymenuOffset, r, nil, style) screen.SetContent(x, y-keymenuOffset, r, nil, style)
x++ x++
if x >= s.win.Width { if x >= s.win.Width {
return return
} }
} }
screen.Screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle) screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
x++ x++
if x >= s.win.Width { if x >= s.win.Width {
return return
@ -132,7 +132,7 @@ func (s *StatusLine) Display() {
} }
for x < s.win.Width { for x < s.win.Width {
screen.Screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle) screen.SetContent(x, y-keymenuOffset, ' ', nil, statusLineStyle)
x++ x++
} }
return return
@ -184,7 +184,7 @@ func (s *StatusLine) Display() {
c = ' ' c = ' '
x++ x++
} }
screen.Screen.SetContent(winX+x, y, c, nil, statusLineStyle) screen.SetContent(winX+x, y, c, nil, statusLineStyle)
} }
} else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen { } else if x >= s.win.Width-rightLen && x < rightLen+s.win.Width-rightLen {
r, size := utf8.DecodeRune(rightText) r, size := utf8.DecodeRune(rightText)
@ -196,10 +196,10 @@ func (s *StatusLine) Display() {
c = ' ' c = ' '
x++ x++
} }
screen.Screen.SetContent(winX+x, y, c, nil, statusLineStyle) screen.SetContent(winX+x, y, c, nil, statusLineStyle)
} }
} else { } else {
screen.Screen.SetContent(winX+x, y, ' ', nil, statusLineStyle) screen.SetContent(winX+x, y, ' ', nil, statusLineStyle)
} }
} }
} }

View file

@ -91,13 +91,13 @@ func (w *TabWindow) Display() {
c = ' ' c = ' '
} }
if x == w.width-1 && !done { if x == w.width-1 && !done {
screen.Screen.SetContent(w.width-1, w.Y, '>', nil, config.DefStyle.Reverse(true)) screen.SetContent(w.width-1, w.Y, '>', nil, config.DefStyle.Reverse(true))
x++ x++
break break
} else if x == 0 && w.hscroll > 0 { } else if x == 0 && w.hscroll > 0 {
screen.Screen.SetContent(0, w.Y, '<', nil, config.DefStyle.Reverse(true)) screen.SetContent(0, w.Y, '<', nil, config.DefStyle.Reverse(true))
} else if x >= 0 && x < w.width { } else if x >= 0 && x < w.width {
screen.Screen.SetContent(x, w.Y, c, nil, config.DefStyle.Reverse(true)) screen.SetContent(x, w.Y, c, nil, config.DefStyle.Reverse(true))
} }
x++ x++
} }

View file

@ -51,7 +51,7 @@ func (w *TermWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
func (w *TermWindow) Clear() { func (w *TermWindow) Clear() {
for y := 0; y < w.Height; y++ { for y := 0; y < w.Height; y++ {
for x := 0; x < w.Width; x++ { for x := 0; x < w.Width; x++ {
screen.Screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle) screen.SetContent(w.X+x, w.Y+y, ' ', nil, config.DefStyle)
} }
} }
} }
@ -88,7 +88,7 @@ func (w *TermWindow) Display() {
st = st.Reverse(true) st = st.Reverse(true)
} }
screen.Screen.SetContent(w.X+x, w.Y+y, c, nil, st) screen.SetContent(w.X+x, w.Y+y, c, nil, st)
} }
} }
if config.GetGlobalOption("statusline").(bool) { if config.GetGlobalOption("statusline").(bool) {
@ -103,9 +103,9 @@ func (w *TermWindow) Display() {
if x < textLen { if x < textLen {
r, size := utf8.DecodeRune(text) r, size := utf8.DecodeRune(text)
text = text[size:] text = text[size:]
screen.Screen.SetContent(w.X+x, w.Y+w.Height, r, nil, statusLineStyle) screen.SetContent(w.X+x, w.Y+w.Height, r, nil, statusLineStyle)
} else { } else {
screen.Screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle) screen.SetContent(w.X+x, w.Y+w.Height, ' ', nil, statusLineStyle)
} }
} }
} }

View file

@ -28,7 +28,7 @@ func (w *UIWindow) drawNode(n *views.Node) {
if c.IsLeaf() && c.Kind == views.STVert { if c.IsLeaf() && c.Kind == views.STVert {
if i != len(cs)-1 { if i != len(cs)-1 {
for h := 0; h < c.H; h++ { for h := 0; h < c.H; h++ {
screen.Screen.SetContent(c.X+c.W, c.Y+h, '|', nil, dividerStyle.Reverse(true)) screen.SetContent(c.X+c.W, c.Y+h, '|', nil, dividerStyle.Reverse(true))
} }
} }
} else { } else {

View file

@ -17,26 +17,66 @@ import (
// screen. TODO: maybe we should worry about polling and drawing at the // screen. TODO: maybe we should worry about polling and drawing at the
// same time too. // same time too.
var Screen tcell.Screen var Screen tcell.Screen
// The lock is necessary since the screen is polled on a separate thread
var lock sync.Mutex var lock sync.Mutex
// DrawChan is a channel that will cause the screen to redraw when
// written to even if no event user event has occurred
var DrawChan chan bool var DrawChan chan bool
// Lock locks the screen lock
func Lock() { func Lock() {
lock.Lock() lock.Lock()
} }
// Unlock unlocks the screen lock
func Unlock() { func Unlock() {
lock.Unlock() lock.Unlock()
} }
// Redraw schedules a redraw with the draw channel
func Redraw() { func Redraw() {
DrawChan <- true DrawChan <- true
} }
type screenCell struct {
x, y int
r rune
combc []rune
style tcell.Style
}
var lastCursor screenCell
// ShowFakeCursor displays a cursor at the given position by modifying the
// style of the given column instead of actually using the terminal cursor
// This can be useful in certain terminals such as the windows console where
// modifying the cursor location is slow and frequent modifications cause flashing
// This keeps track of the most recent fake cursor location and resets it when
// a new fake cursor location is specified
func ShowFakeCursor(x, y int) { func ShowFakeCursor(x, y int) {
r, combc, style, _ := Screen.GetContent(x, y)
Screen.SetContent(lastCursor.x, lastCursor.y, lastCursor.r, lastCursor.combc, lastCursor.style)
Screen.SetContent(x, y, r, combc, config.DefStyle.Reverse(true))
lastCursor.x, lastCursor.y = x, y
lastCursor.r = r
lastCursor.combc = combc
lastCursor.style = style
}
// ShowFakeCursorMulti is the same as ShowFakeCursor except it does not
// reset previous locations of the cursor
// Fake cursors are also necessary to display multiple cursors
func ShowFakeCursorMulti(x, y int) {
r, _, _, _ := Screen.GetContent(x, y) r, _, _, _ := Screen.GetContent(x, y)
Screen.SetContent(x, y, r, nil, config.DefStyle.Reverse(true)) Screen.SetContent(x, y, r, nil, config.DefStyle.Reverse(true))
} }
// ShowCursor puts the cursor at the given location using a fake cursor
// if enabled or using the terminal cursor otherwise
// By default only the windows console will use a fake cursor
func ShowCursor(x, y int) { func ShowCursor(x, y int) {
if util.FakeCursor { if util.FakeCursor {
ShowFakeCursor(x, y) ShowFakeCursor(x, y)
@ -45,6 +85,17 @@ func ShowCursor(x, y int) {
} }
} }
// SetContent sets a cell at a point on the screen and makes sure that it is
// synced with the last cursor location
func SetContent(x, y int, mainc rune, combc []rune, style tcell.Style) {
Screen.SetContent(x, y, mainc, combc, style)
if util.FakeCursor && lastCursor.x == x && lastCursor.y == y {
lastCursor.r = mainc
lastCursor.style = style
lastCursor.combc = combc
}
}
// TempFini shuts the screen down temporarily // TempFini shuts the screen down temporarily
func TempFini() bool { func TempFini() bool {
screenWasNil := Screen == nil screenWasNil := Screen == nil

View file

@ -33,7 +33,7 @@ var (
Debug = "ON" Debug = "ON"
// FakeCursor is used to disable the terminal cursor and have micro // FakeCursor is used to disable the terminal cursor and have micro
// draw its own (enabled for windows consoles where the cursor is slow) // draw its own (enabled for windows consoles where the cursor is slow)
FakeCursor = true FakeCursor = false
) )
func init() { func init() {