| 116 | } |
| 117 | |
| 118 | func (m runModel) View() string { |
| 119 | header := sectionStyle.Render("Run — start/stop the snix engine and watch logs") |
| 120 | controls := "\n" + |
| 121 | codeStyle.Render("s") + " start " + |
| 122 | codeStyle.Render("x") + " stop " + |
| 123 | codeStyle.Render("r") + " restart " + |
| 124 | codeStyle.Render("c") + " clear logs" |
| 125 | |
| 126 | state := mutedStyle.Render("stopped") |
| 127 | if m.isRunning() { |
| 128 | state = okStyle.Render("running") + " " + |
| 129 | mutedStyle.Render(fmt.Sprintf("(pid=%d, uptime=%s)", |
| 130 | m.pid(), time.Since(m.startTime()).Round(time.Second))) |
| 131 | } |
| 132 | |
| 133 | var warnings string |
| 134 | if runtime.GOOS == "windows" { |
| 135 | warnings = "\n" + hintStyle.Render( |
| 136 | "Note: on Windows the engine needs Administrator privilege. If the TUI was\n"+ |
| 137 | "launched non-elevated, pressing s will print the missing-privilege error\n"+ |
| 138 | "into the log panel; relaunch this TUI from an elevated shell to start.") |
| 139 | } |
| 140 | |
| 141 | status := sectionStyle.Render("Status") + "\n" + state + warnings |
| 142 | |
| 143 | w := m.app.width |
| 144 | if w < 20 { |
| 145 | w = 20 |
| 146 | } |
| 147 | m.vp.Width = w - 4 |
| 148 | |
| 149 | logPanel := panelStyle.Width(w - 2).Render( |
| 150 | sectionStyle.Render("Engine output") + "\n" + m.vp.View()) |
| 151 | |
| 152 | return lipgloss.JoinVertical(lipgloss.Left, |
| 153 | header, controls, status, "", logPanel, |
| 154 | ) |
| 155 | } |
| 156 | |
| 157 | func (m runModel) isRunning() bool { |
| 158 | m.st.mu.Lock() |