Skip to content

Commit

Permalink
feat: cellrenderer: support setting cursor position
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Oct 17, 2024
1 parent 41dd3ab commit c3433b7
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 84 deletions.
112 changes: 31 additions & 81 deletions cell_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,59 +11,7 @@ import (
"github.com/charmbracelet/x/cellbuf"
)

// moveCursorMsg represents a message to move the cursor.
type moveCursorMsg struct {
x, y int
}

// MoveCursor moves the cursor to the given position.
func MoveCursor(x, y int) Msg {
return moveCursorMsg{x, y}
}

// cursorUpMsg represents a message to move the cursor up.
type cursorUpMsg int

// CursorUp moves the cursor up by n cells.
func CursorUp(n int) Msg {
if n <= 0 {
return nil
}
return cursorUpMsg(n)
}

// cursorDownMsg represents a message to move the cursor down.
type cursorDownMsg int

// CursorDown moves the cursor down by n cells.
func CursorDown(n int) Msg {
if n <= 0 {
return nil
}
return cursorDownMsg(n)
}

// cursorLeftMsg represents a message to move the cursor left.
type cursorLeftMsg int

// CursorLeft moves the cursor left by n cells.
func CursorLeft(n int) Msg {
if n <= 0 {
return nil
}
return cursorLeftMsg(n)
}

// cursorRightMsg represents a message to move the cursor right.
type cursorRightMsg int

// CursorRight moves the cursor right by n cells.
func CursorRight(n int) Msg {
if n <= 0 {
return nil
}
return cursorRightMsg(n)
}
var undefPoint = image.Pt(-1, -1)

// cursor represents a terminal cursor.
type cursor struct {
Expand Down Expand Up @@ -121,6 +69,8 @@ type cellRenderer struct {
scrs [2]screen // Both inline and alt-screen
scr *screen // Points to the current used screen

finalCur image.Point // The final cursor position

method cellbuf.WidthMethod
pen cellbuf.Style
link cellbuf.Link
Expand All @@ -139,7 +89,8 @@ type cellRenderer struct {
func newCellRenderer() *cellRenderer {
r := &cellRenderer{
// TODO: Update this if Grapheme Clustering is supported.
method: cellbuf.WcWidth,
method: cellbuf.WcWidth,
finalCur: undefPoint,
}
r.reset()
return r
Expand Down Expand Up @@ -199,7 +150,8 @@ func (c *cellRenderer) flush() error {
c.mtx.Lock()
defer c.mtx.Unlock()

if c.frame == *c.lastRender && c.lastHeight == c.scr.Height() {
if c.finalCur == c.scr.cur.Point && len(c.queueAbove) == 0 &&
c.frame == *c.lastRender && c.lastHeight == c.scr.Height() {
return nil
}

Expand Down Expand Up @@ -228,6 +180,17 @@ func (c *cellRenderer) flush() error {

c.changes()

// XXX: We need to move the cursor to the final position before rendering
// the frame to avoid flickering.
shouldHideCursor := !c.cursorHidden
if c.finalCur != image.Pt(-1, -1) {
shouldMove := c.finalCur != c.scr.cur.Point
shouldHideCursor = shouldHideCursor && shouldMove
if shouldMove {
c.moveCursor(c.finalCur.X, c.finalCur.Y)
}
}

c.scr.dirty = make(map[int]int)
c.lastHeight = cellbuf.Height(c.frame)
*c.lastRender = c.frame
Expand All @@ -237,7 +200,7 @@ func (c *cellRenderer) flush() error {
return nil
}

if !c.cursorHidden {
if shouldHideCursor {
// Hide the cursor while rendering to avoid flickering.
render = ansi.HideCursor + render + ansi.ShowCursor
}
Expand Down Expand Up @@ -270,7 +233,7 @@ func (c *cellRenderer) reset() {
// alt-screen buffer cursor always starts from where the main buffer cursor
// is. We need to set it to (-1,-1) to force the cursor to be moved to the
// origin on the first render.
c.scrs[1].cur.Point = image.Pt(-1, -1)
c.scrs[1].cur.Point = undefPoint
if c.altScreen {
c.scr = &c.scrs[1]
c.lastRender = &c.lastRenders[1]
Expand Down Expand Up @@ -377,32 +340,19 @@ func (c *cellRenderer) update(msg Msg) {
c.cursorHidden = true
}

case moveCursorMsg:
c.moveCursor(msg.x, msg.y)

case cursorUpMsg:
y := c.scr.cur.Y - int(msg)
if y >= 0 {
c.scr.cur.Y = y
}

case cursorDownMsg:
y := c.scr.cur.Y + int(msg)
if y < c.scr.Height() {
c.scr.cur.Y = y
}

case cursorLeftMsg:
x := c.scr.cur.X - int(msg)
if x >= 0 {
c.scr.cur.X = x
case setCursorPosMsg:
x, y := msg.x, msg.y
if x < 0 {
x = c.scr.cur.X
} else if x >= c.scr.Width() {
x = c.scr.Width() - 1
}

case cursorRightMsg:
x := c.scr.cur.X + int(msg)
if x < c.scr.Width() {
c.scr.cur.X = x
if y < 0 {
y = c.scr.cur.Y
} else if y >= c.scr.Height() {
y = c.scr.Height() - 1
}
c.finalCur = image.Pt(x, y)
}
}

Expand Down
14 changes: 14 additions & 0 deletions cursor.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,17 @@ func SetCursorStyle(style CursorStyle, steady bool) Cmd {
return setCursorStyle(style)
}
}

// setCursorPosMsg represents a message to set the cursor position.
type setCursorPosMsg struct {
x, y int
}

// SetCursorPosition sets the cursor position to the specified relative
// coordinates. Using -1 for either x or y will not change the cursor position
// for that axis.
func SetCursorPosition(x, y int) Cmd {
return func() Msg {
return setCursorPosMsg{x, y}
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/charmbracelet/x/ansi v0.3.2
github.com/charmbracelet/x/cellbuf v0.0.0-20241015153255-110a4e49aee6
github.com/charmbracelet/x/cellbuf v0.0.0-20241017161146-26fb54ba205f
github.com/charmbracelet/x/term v0.2.0
github.com/charmbracelet/x/windows v0.2.0
github.com/muesli/cancelreader v0.2.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY=
github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/cellbuf v0.0.0-20241015153255-110a4e49aee6 h1:z6Jq8MwJxOqzNSLEyAfRrHvUGFU7SgTFgZrqFHAJIu4=
github.com/charmbracelet/x/cellbuf v0.0.0-20241015153255-110a4e49aee6/go.mod h1:mFpvlGowTd0Fiv4TdoKyGZaZdigSUHtBJralbADonwE=
github.com/charmbracelet/x/cellbuf v0.0.0-20241017161146-26fb54ba205f h1:Am9Pfoi7x0XbXJiuQVc4MHDFb3oZeFHyN7JmgdHt0GM=
github.com/charmbracelet/x/cellbuf v0.0.0-20241017161146-26fb54ba205f/go.mod h1:mFpvlGowTd0Fiv4TdoKyGZaZdigSUHtBJralbADonwE=
github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0=
github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0=
github.com/charmbracelet/x/wcwidth v0.0.0-20241011142426-46044092ad91 h1:D5OO0lVavz7A+Swdhp62F9gbkibxmz9B2hZ/jVdMPf0=
Expand Down

0 comments on commit c3433b7

Please sign in to comment.