File: pty.go

package info (click to toggle)
golang-github-charmbracelet-x 0.0~git20240809.9ab0ca0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,004 kB
  • sloc: sh: 55; makefile: 5
file content (129 lines) | stat: -rw-r--r-- 2,509 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package xpty

import (
	"os"
	"os/exec"

	"github.com/creack/pty"
)

// UnixPty represents a classic Unix PTY (pseudo-terminal).
type UnixPty struct {
	master, slave *os.File
}

var _ Pty = &UnixPty{}

// NewUnixPty creates a new Unix PTY.
func NewUnixPty(width, height int, _ ...PtyOption) (*UnixPty, error) {
	ptm, pts, err := pty.Open()
	if err != nil {
		return nil, err
	}

	p := &UnixPty{
		master: ptm,
		slave:  pts,
	}

	if width >= 0 && height >= 0 {
		if err := p.Resize(width, height); err != nil {
			return nil, err
		}
	}

	return p, nil
}

// Close implements XPTY.
func (p *UnixPty) Close() (err error) {
	defer func() {
		serr := p.slave.Close()
		if err == nil {
			err = serr
		}
	}()
	if err := p.master.Close(); err != nil {
		return err
	}
	return
}

// Fd implements XPTY.
func (p *UnixPty) Fd() uintptr {
	return p.master.Fd()
}

// Name implements XPTY.
func (p *UnixPty) Name() string {
	return p.master.Name()
}

// SlaveName returns the name of the slave PTY.
// This is usually used for remote sessions to identify the running TTY. You
// can find this in SSH sessions defined as $SSH_TTY.
func (p *UnixPty) SlaveName() string {
	return p.slave.Name()
}

// Read implements XPTY.
func (p *UnixPty) Read(b []byte) (n int, err error) {
	return p.master.Read(b)
}

// Resize implements XPTY.
func (p *UnixPty) Resize(width int, height int) (err error) {
	return p.setWinsize(width, height, 0, 0)
}

// SetWinsize sets window size for the PTY.
func (p *UnixPty) SetWinsize(width, height, x, y int) error {
	return p.setWinsize(width, height, x, y)
}

// Size returns the size of the PTY.
func (p *UnixPty) Size() (width, height int, err error) {
	return p.size()
}

// Start implements XPTY.
func (p *UnixPty) Start(c *exec.Cmd) error {
	if c.Stdout == nil {
		c.Stdout = p.slave
	}
	if c.Stderr == nil {
		c.Stderr = p.slave
	}
	if c.Stdin == nil {
		c.Stdin = p.slave
	}
	if err := c.Start(); err != nil {
		return err
	}
	return nil
}

// Write implements XPTY.
func (p *UnixPty) Write(b []byte) (n int, err error) {
	return p.master.Write(b)
}

// Master returns the master end of the PTY.
func (p *UnixPty) Master() *os.File {
	return p.master
}

// Slave returns the slave end of the PTY.
func (p *UnixPty) Slave() *os.File {
	return p.slave
}

// Control runs the given function with the file descriptor of the master PTY.
func (p *UnixPty) Control(fn func(fd uintptr)) error {
	conn, err := p.master.SyscallConn()
	if err != nil {
		return err
	}

	return conn.Control(fn)
}