turbo-editors/turbo-corepublic Fork 0
v1.0.2
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

session_unix.go · 79 lines · 2.2 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 18h ago1//go:build linux || darwin
2
3package terminal
4
5import (
6 "os"
7 "os/exec"
8 "path/filepath"
9)
10
11// unixChild is a shell behind a Unix pseudo-terminal: the master end this side
12// holds, and the process that has the slave as its controlling terminal.
13type unixChild struct {
14 master *os.File
15 command *exec.Cmd
16}
17
18// startChild opens a pseudo-terminal and starts the shell in it.
19func startChild(options Options) (child, error) {
20 master, slave, err := openPTY()
21 if err != nil {
22 return nil, err
23 }
24 // The child keeps the slave as its own standard input, output and error;
25 // this process has no further use for it once the child has started.
26 defer slave.Close()
27
28 command := exec.Command(shellOrDefault(options.Shell), options.Args...)
29 command.Dir = options.Dir
30 command.Env = environment(options.Env)
31 command.Stdin, command.Stdout, command.Stderr = slave, slave, slave
32 command.SysProcAttr = childAttributes()
33
34 if err := command.Start(); err != nil {
35 master.Close()
36 return nil, err
37 }
38
39 c := &unixChild{master: master, command: command}
40 if err := c.Resize(max(options.Width, 1), max(options.Height, 1)); err != nil {
41 c.Close()
42 return nil, err
43 }
44 return c, nil
45}
46
47// defaultShell returns the user's own shell, or a last-resort fallback that
48// exists on every Unix.
49func defaultShell() string {
50 if fromEnvironment := os.Getenv("SHELL"); fromEnvironment != "" {
51 return fromEnvironment
52 }
53 return "/bin/sh"
54}
55
56func (c *unixChild) Read(b []byte) (int, error) { return c.master.Read(b) }
57func (c *unixChild) Write(b []byte) (int, error) { return c.master.Write(b) }
58
59// Resize sets the pseudo-terminal's size, which the kernel passes on to the
60// shell as SIGWINCH.
61func (c *unixChild) Resize(width, height int) error {
62 return setWinsize(c.master, width, height)
63}
64
65// Close closes the master — the shell sees its input end — then kills and
66// reaps the process, so that closing cannot hang on a shell that ignores the
67// hint.
68func (c *unixChild) Close() error {
69 closeErr := c.master.Close()
70
71 if c.command.Process != nil {
72 _ = c.command.Process.Kill()
73 _, _ = c.command.Process.Wait()
74 }
75 return closeErr
76}
77
78// Command returns the shell's name without its path.
79func (c *unixChild) Command() string { return filepath.Base(c.command.Path) }