output.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. if cursorColumn && s.columns > 1 {
  50. s.columns--
  51. }
  52. return true
  53. }
  54. func (s *State) checkOutput() {
  55. // xterm is known to support CHA
  56. if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") {
  57. s.useCHA = true
  58. return
  59. }
  60. // The test for functional ANSI CHA is unreliable (eg the Windows
  61. // telnet command does not support reading the cursor position with
  62. // an ANSI DSR request, despite setting TERM=ansi)
  63. // Assume CHA isn't supported (which should be safe, although it
  64. // does result in occasional visible cursor jitter)
  65. s.useCHA = false
  66. }