setup_unix.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. //go:build !windows && !plan9
  2. package term
  3. import (
  4. "fmt"
  5. "os"
  6. "golang.org/x/sys/unix"
  7. "src.elv.sh/pkg/diag"
  8. "src.elv.sh/pkg/sys/eunix"
  9. )
  10. func setup(in, out *os.File) (func() error, error) {
  11. // On Unix, use input file for changing termios. All fds pointing to the
  12. // same terminal are equivalent.
  13. fd := int(in.Fd())
  14. term, err := eunix.TermiosForFd(fd)
  15. if err != nil {
  16. return nil, fmt.Errorf("can't get terminal attribute: %s", err)
  17. }
  18. savedTermios := term.Copy()
  19. term.SetICanon(false)
  20. term.SetIExten(false)
  21. term.SetEcho(false)
  22. term.SetVMin(1)
  23. term.SetVTime(0)
  24. // Enforcing crnl translation on readline. Assuming user won't set
  25. // inlcr or -onlcr, otherwise we have to hardcode all of them here.
  26. term.SetICRNL(true)
  27. err = term.ApplyToFd(fd)
  28. if err != nil {
  29. return nil, fmt.Errorf("can't set up terminal attribute: %s", err)
  30. }
  31. var errSetupVT error
  32. err = setupVT(out)
  33. if err != nil {
  34. errSetupVT = fmt.Errorf("can't setup VT: %s", err)
  35. }
  36. restore := func() error {
  37. return diag.Errors(savedTermios.ApplyToFd(fd), restoreVT(out))
  38. }
  39. return restore, errSetupVT
  40. }
  41. func setupForEval(in, out *os.File) func() {
  42. // There is nothing to set up on UNIX, but we try to sanitize the terminal
  43. // when evaluation finishes.
  44. return func() { sanitize(in, out) }
  45. }
  46. func sanitize(in, out *os.File) {
  47. // Some programs use non-blocking IO but do not correctly clear the
  48. // non-blocking flags after exiting, so we always clear the flag. See #822
  49. // for an example.
  50. unix.SetNonblock(int(in.Fd()), false)
  51. unix.SetNonblock(int(out.Fd()), false)
  52. }