output.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // +build linux darwin openbsd freebsd netbsd
  2. package liner
  3. import (
  4. "fmt"
  5. "os"
  6. "strings"
  7. "syscall"
  8. "unsafe"
  9. )
  10. func (s *State) cursorPos(x int) {
  11. if s.useCHA {
  12. // 'G' is "Cursor Character Absolute (CHA)"
  13. fmt.Printf("\x1b[%dG", x+1)
  14. } else {
  15. // 'C' is "Cursor Forward (CUF)"
  16. fmt.Print("\r")
  17. if x > 0 {
  18. fmt.Printf("\x1b[%dC", x)
  19. }
  20. }
  21. }
  22. func (s *State) eraseLine() {
  23. fmt.Print("\x1b[0K")
  24. }
  25. func (s *State) eraseScreen() {
  26. fmt.Print("\x1b[H\x1b[2J")
  27. }
  28. func (s *State) moveUp(lines int) {
  29. fmt.Printf("\x1b[%dA", lines)
  30. }
  31. func (s *State) moveDown(lines int) {
  32. fmt.Printf("\x1b[%dB", lines)
  33. }
  34. func (s *State) emitNewLine() {
  35. fmt.Print("\n")
  36. }
  37. type winSize struct {
  38. row, col uint16
  39. xpixel, ypixel uint16
  40. }
  41. func (s *State) getColumns() bool {
  42. var ws winSize
  43. ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout),
  44. syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws)))
  45. if int(ok) < 0 {
  46. return false
  47. }
  48. s.columns = int(ws.col)
  49. return true
  50. }
  51. func (s *State) checkOutput() {
  52. // xterm is known to support CHA
  53. if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") {
  54. s.useCHA = true
  55. return
  56. }
  57. // The test for functional ANSI CHA is unreliable (eg the Windows
  58. // telnet command does not support reading the cursor position with
  59. // an ANSI DSR request, despite setting TERM=ansi)
  60. // Assume CHA isn't supported (which should be safe, although it
  61. // does result in occasional visible cursor jitter)
  62. s.useCHA = false
  63. }