Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: cursor position adjustment after exiting alt screen #1241

Merged
merged 2 commits into from
Nov 19, 2024

Conversation

semihbkgr
Copy link
Contributor

When exiting alternate screen mode, the cursor was not properly adjusted, which caused terminal content to be either overwritten (if the current line count was greater than before entering alt screen) or leftover lines to remain at the top (if the current line count was smaller). To fix this, we save the number of lines rendered before entering alternate screen mode. When exiting, we compare the current line count with the saved value and adjust the cursor position accordingly, ensuring correct positioning and preventing both overwriting and leftover lines.

fixes #1013

@semihbkgr
Copy link
Contributor Author

In my understanding, the source of this issue appears to be that the terminal automatically moves the cursor back to its position, where it was before entering alt screen mode, when exiting.

@meowgorithm
Copy link
Member

Thanks for this, @semihbkgr. Can you also paste in some code for a minimally reproducible example? It would also be good to know if this is a regression in v1.2.0.

@semihbkgr
Copy link
Contributor Author

Hi @meowgorithm

Can you also paste in some code for a minimally reproducible example?

There is already an example in the issue mentioned in the description. It was a real case we encountered in kubectl-klock. However, I will share a simplified example to reproduce the bug more easily, which directly highlights the problematic situation 👍

It would also be good to know if this is a regression in v1.2.0.

The issue dates back to older versions. The issue was created on May 10, indicating it was first observed in v0.26.2 or earlier.

@semihbkgr
Copy link
Contributor Author

Operations

  • j: increments line count
  • k: decrements line count
  • <space>: toggle alt screen

The issue occurs when the number of lines rendered in alt screen mode differs from the lines rendered before entering alt screen mode — either fewer lines (leaving leftover lines) or more lines (overwriting old lines).

Reproducing the Overwriting Old Lines Bug:

  1. Start the program and render some initial content in the terminal (e.g., lines 1 to 5).
  2. Press <space> to toggle into alt screen mode.
  3. Press j multiple times to increment the line count and render additional lines in the alt screen.
  4. Press <space> again to exit alt screen mode.
  5. Observe that the additional lines rendered in the alt screen overwrite the existing terminal content (lines 1 to 5).

Reproducing the Keeping Leftover Lines Bug:

  1. Start the program and render some initial content in the terminal (e.g., lines 1 to 5).
  2. Press <space> to toggle into alt screen mode.
  3. Press k multiple times to decrement the line count and reduce the number of rendered lines.
  4. Press <space> again to exit alt screen mode.
  5. Observe that the leftover lines from the initial content remain visible above the current lines rendered in the alt screen.
package main

import (
	"fmt"
	"os"
	"strings"

	tea "github.com/charmbracelet/bubbletea"
)

type model struct {
	altscreen bool
	n         int
}

func (m model) Init() tea.Cmd {
	return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch msg.String() {
		case "q", "ctrl+c", "esc":
			return m, tea.Quit
		case "j":
			m.n += 1
		case "k":
			m.n -= 1
		case " ":
			var cmd tea.Cmd
			if m.altscreen {
				cmd = tea.ExitAltScreen
			} else {
				cmd = tea.EnterAltScreen
			}
			m.altscreen = !m.altscreen
			return m, cmd
		}
	}
	return m, nil
}

func (m model) View() string {
	b := strings.Builder{}
	if m.altscreen {
		b.WriteString("alt screen\n")
	} else {
		b.WriteString("normal screen\n")
	}
	for i := 0; i < m.n; i++ {
		b.WriteString(fmt.Sprintf("%d. line\n", i))
	}
	return b.String()
}

func main() {
	if _, err := tea.NewProgram(model{}).Run(); err != nil {
		fmt.Println("Error running program:", err)
		os.Exit(1)
	}
}

@meowgorithm
Copy link
Member

Thanks for that; we're taking a look.

Copy link
Member

@aymanbagabas aymanbagabas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you, @semihbkgr!

@meowgorithm meowgorithm merged commit 4ad0792 into charmbracelet:main Nov 19, 2024
21 of 22 checks passed
@meowgorithm
Copy link
Member

Awesome fix, @semihbkgr: thank you. We'll get a patch release out today.

meowgorithm pushed a commit that referenced this pull request Nov 19, 2024
* fix cursor position handling after exiting alt screen mode

* avoid moving cursor when lines rendered before alt screen is zero
@meowgorithm
Copy link
Member

Alright, v1.2.3, containing the fix, is available now. Thanks for the fix @semihbkgr!

@unitsvc
Copy link

unitsvc commented Nov 21, 2024

clear screen , then tea.EnterAltScreen -> tea.ExitAltScreen, sometimes it does not work on mac or linux systems, the screen cannot exit full screen, or flickers.
@semihbkgr @meowgorithm

aymanbagabas added a commit that referenced this pull request Nov 22, 2024
aymanbagabas added a commit that referenced this pull request Nov 22, 2024
We need to keep a separate count of lines rendered in the alt screen and
inline mode. This is because when we enter alt screen mode, the cursor
position is saved and the alt screen is cleared. Now when we exit the
alt screen mode, the cursor position is restored so we don't need to
move the cursor to the beginning of the section that we rendered.

To fix this, we keep a separate count of lines rendered in the alt screen
mode and inline mode.

Related: #1013
Fixes: #1241
Fixes: #1248
aymanbagabas added a commit that referenced this pull request Nov 25, 2024
aymanbagabas added a commit that referenced this pull request Nov 25, 2024
We need to keep a separate count of lines rendered in the alt screen and
inline mode. This is because when we enter alt screen mode, the cursor
position is saved and the alt screen is cleared. Now when we exit the
alt screen mode, the cursor position is restored so we don't need to
move the cursor to the beginning of the section that we rendered.

To fix this, we keep a separate count of lines rendered in the alt screen
mode and inline mode.

Related: #1013
Fixes: #1241
Fixes: #1248
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exiting fullscreen glitch when also removing a line in output
4 participants