newScreen creates a new screen-backed reconnecting PTY. It writes config settings and creates the socket directory. If we could, we would want to spawn the daemon here and attach each connection to it but since doing that spawns the daemon with a hardcoded 24x80 size it is not a very good user exp
(ctx context.Context, logger slog.Logger, execer agentexec.Execer, cmd *pty.Cmd, options *Options)
| 62 | // experience. Instead we will let the attach command spawn the daemon on its |
| 63 | // own which causes it to spawn with the specified size. |
| 64 | func newScreen(ctx context.Context, logger slog.Logger, execer agentexec.Execer, cmd *pty.Cmd, options *Options) *screenReconnectingPTY { |
| 65 | rpty := &screenReconnectingPTY{ |
| 66 | logger: logger, |
| 67 | execer: execer, |
| 68 | command: cmd, |
| 69 | metrics: options.Metrics, |
| 70 | state: newState(), |
| 71 | timeout: options.Timeout, |
| 72 | } |
| 73 | |
| 74 | // Socket paths are limited to around 100 characters on Linux and macOS which |
| 75 | // depending on the temporary directory can be a problem. To give more leeway |
| 76 | // use a short ID. |
| 77 | buf := make([]byte, 4) |
| 78 | _, err := rand.Read(buf) |
| 79 | if err != nil { |
| 80 | rpty.state.setState(StateDone, xerrors.Errorf("generate screen id: %w", err)) |
| 81 | return rpty |
| 82 | } |
| 83 | rpty.id = hex.EncodeToString(buf) |
| 84 | |
| 85 | settings := []string{ |
| 86 | // Disable the startup message that appears for five seconds. |
| 87 | "startup_message off", |
| 88 | // Some message are hard-coded, the best we can do is set msgwait to 0 |
| 89 | // which seems to hide them. This can happen for example if screen shows |
| 90 | // the version message when starting up. |
| 91 | "msgminwait 0", |
| 92 | "msgwait 0", |
| 93 | // Tell screen not to handle motion for xterm* terminals which allows |
| 94 | // scrolling the terminal via the mouse wheel or scroll bar (by default |
| 95 | // screen uses it to cycle through the command history). There does not |
| 96 | // seem to be a way to make screen itself scroll on mouse wheel. tmux can |
| 97 | // do it but then there is no scroll bar and it kicks you into copy mode |
| 98 | // where keys stop working until you exit copy mode which seems like it |
| 99 | // could be confusing. |
| 100 | "termcapinfo xterm* ti@:te@", |
| 101 | // Enable alternate screen emulation otherwise applications get rendered in |
| 102 | // the current window which wipes out visible output resulting in missing |
| 103 | // output when scrolling back with the mouse wheel (copy mode still works |
| 104 | // since that is screen itself scrolling). |
| 105 | "altscreen on", |
| 106 | // Match the background color erase capability advertised by xterm-256color. |
| 107 | "defbce on", |
| 108 | // Keep the shell environment aligned with the web terminal emulator. Some |
| 109 | // terminal applications, including tmux, render differently when they see |
| 110 | // screen.xterm-256color even though screen is only an implementation |
| 111 | // detail for reconnecting. |
| 112 | "term " + xterm256Color, |
| 113 | // Remap the control key to C-s since C-a may be used in applications. C-s |
| 114 | // is chosen because it cannot actually be used because by default it will |
| 115 | // pause and C-q to resume will just kill the browser window. We may not |
| 116 | // want people using the control key anyway since it will not be obvious |
| 117 | // they are in screen and doing things like switching windows makes mouse |
| 118 | // wheel scroll wonky due to the terminal doing the scrolling rather than |
| 119 | // screen itself (but again copy mode will work just fine). |
| 120 | "escape ^Ss", |
| 121 | } |