ANSI 이스케이프 시퀀스를 사용하여 터미널 내용을 "제자리"로 편집하는 올바른 방법은 무엇입니까?

ANSI 이스케이프 시퀀스를 사용하여 터미널 내용을 "제자리"로 편집하는 올바른 방법은 무엇입니까?

그래서 다음 동작을 사용하여 간단한 터미널 애플리케이션을 만들려고 했습니다.

  1. 시작 시 화면이 지워지고 빈 화면 상단에 일부 내용이 기록됩니다.

  2. "Enter"를 누를 때마다 화면이 지워지고 그 자리에 새 콘텐츠가 나타납니다.

ANSI 이스케이프 코드를 사용하여 화면을 지우고 커서를 이동하여 이를 달성하려고 합니다. 내 현재 접근 방식은 다음과 같습니다 (의사 코드)

func clearAndPrintContent() {
    printf("\x[2J")    // clear the entire screen
    printf("\x[1;1f")  // move the cursor to the top left corner of the screen
    printContent() // print some lines of content to the screen
}

main {
    while true {
        clearAndPrintContent() // do the clear and print
        readLine() // wait for enter key
    }
}

내가 기대하는 것은 여기에 있는 콘텐츠가 항상 그 자리에 작성된다는 것입니다. 즉, 새 콘텐츠가 작성되면 기존 콘텐츠를 덮어쓰게 됩니다. 내가 실제로 얻는 것은 내 모든 콘텐츠가 연속적으로 작성된다는 것입니다. 즉, 뒤로 스크롤하면 공백과 인쇄된 내용을 포함하여 프로그램이 인쇄하는 모든 "페이지"가 ​​표시됩니다.

예를 들어, 무언가를 두 번 인쇄하는 경우 스크롤백이 다음과 같이 나타나기를 원합니다.

- previous scrollback -
$ run my-app

   [result of second printContent from my-app (first has been over-written)]



-end of terminal output -

그러나 내가 실제로 얻는 것은 이것이다:

- previous scrollback -
$ run my-app

   [result of first printContent from my-app]





   [result of second printContent from my-app]



-end of terminal output -

이 결과를 어떻게 얻을 수 있습니까?

답변1

터미널마다 다르게 동작합니다 \e[2J. Xterm과 같은 일부는 예상한 대로 화면을 지웁니다. VTE(GNOME 터미널 및 기타 프런트엔드)와 같은 다른 것들은 사용자가 경험하는 대로 콘텐츠를 스크롤백 버퍼로 스크롤합니다.

첫 번째 단계에 있던 위치로 커서를 이동한 다음 \e[J("아래 지우기", 즉 커서가 있는 행 오른쪽에 있는 모든 항목과 그 아래 행에 있는 모든 항목)를 사용하여 지울 수 있습니다. 이는 모든 곳에서 동일합니다.

또 다른 방법은 스크롤백 기능 없이 대체 화면 버퍼로 전환하는 것이므로 \e[2J모든 터미널에서 동일한 작업을 수행합니다. 앱을 종료할 때 일반 화면으로 다시 전환해야 하며 앱이 시작되었을 때 있던 위치로 이동하게 됩니다.

관련 정보