package tui import ( "fmt" "get-container/cmd/hytop/backend" "slices" "strings" "github.com/acarl005/stripansi" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/x/ansi" "github.com/shirou/gopsutil/v3/process" ) type ModelProcessEnv struct { w, h int // 屏幕宽、高 pid int // 显示的进程pid modelMsg *ModelMsg // 模型信息 lineNum int // 光标所在的行 xOffset, yOffset int // 偏移量 title string // 界面标题 line string // 分割线 proc *process.Process // 进程信息 envs []string styleW, styleH lipgloss.Style envW, envH int // 环境变量字符串的宽高 envStr string } func NewModelProcessEnv(w, h, pid int, modelMsg *ModelMsg) *ModelProcessEnv { var dev string if modelMsg == nil || modelMsg.DCUPidInfo == nil { dev = "CPU" } else { dev = "CPU" for _, v := range modelMsg.DCUPidInfo { for _, vv := range v { if vv.Info.Pid == int32(pid) { dev = "DCU" break } } if dev == "DCU" { break } } } style := lipgloss.NewStyle().Foreground(lipgloss.Color("#00fffb7a")) header := style.SetString(fmt.Sprintf("Environment of process %d (%s@%s: Compute): ", pid, backend.User, dev)).String() proc, err := process.NewProcess(int32(pid)) style = style.UnsetForeground().Foreground(lipgloss.Color("#6cff4eff")) result := &ModelProcessEnv{ w: w, h: h, pid: pid, lineNum: -1, line: style.Render(strings.Repeat("#", w)), title: header, modelMsg: modelMsg, proc: nil, envs: nil, styleW: lipgloss.NewStyle().MaxWidth(w), styleH: lipgloss.NewStyle().MaxHeight(h), } if err != nil { return result } cmd, err := proc.Cmdline() if err != nil { return result } result.title += cmd envs, err := proc.Environ() if err != nil { return result } slices.Sort(envs) result.envs = envs result.addEnvStyle() s := strings.Join(result.envs, "\n") result.envStr = lipgloss.NewStyle().Width(lipgloss.Width(s)).Render(s) result.envW, result.envH = lipgloss.Size(result.envStr) return result } func (pe *ModelProcessEnv) Init() tea.Cmd { return nil } // Update 处理光标移动 func (pe *ModelProcessEnv) Update(imsg tea.Msg) (tea.Model, tea.Cmd) { // 判断是否需要滚动 consider := false if pe.envH > (pe.h - 2) { consider = true } cW := false if pe.envW > pe.w { cW = true } switch msg := imsg.(type) { case tea.KeyType: switch msg.String() { case tea.KeyUp.String(): if pe.envH == 0 { return pe, nil } if pe.lineNum == -1 { if consider { pe.lineNum = pe.h - 2 pe.yOffset = pe.envH - pe.lineNum } else { pe.lineNum = pe.envH } return pe, nil } if consider { if pe.lineNum > 1 { pe.lineNum-- } else { if pe.yOffset > 0 { pe.yOffset-- } } return pe, nil } else { if pe.lineNum > 1 { pe.lineNum-- } return pe, nil } case tea.KeyDown.String(): if pe.envH == 0 { return pe, nil } if pe.lineNum == -1 { pe.lineNum = 1 return pe, nil } if consider { if pe.lineNum < (pe.h - 2) { pe.lineNum++ return pe, nil } else { if pe.yOffset+pe.lineNum < pe.envH { pe.yOffset++ } return pe, nil } } else { if pe.lineNum < pe.envH { pe.lineNum++ return pe, nil } } case tea.KeyLeft.String(): if !cW { return pe, nil } if pe.xOffset > 0 { pe.xOffset-- return pe, nil } case tea.KeyRight.String(): if !cW { return pe, nil } if pe.xOffset+pe.w < pe.envW { pe.xOffset++ return pe, nil } } } return pe, nil } func (pe *ModelProcessEnv) View() string { sb := strings.Builder{} sb.WriteString(pe.title) sb.WriteByte('\n') sb.WriteString(pe.line) sb.WriteByte('\n') lines := strings.Split(pe.envStr, "\n") l := len(lines[pe.yOffset:]) for k, line := range lines[pe.yOffset:] { if k+1 == pe.lineNum { sb.WriteString(pe.styleW.Render(ansi.TruncateLeft(HeightLightStyle.Render(stripansi.Strip(line)), pe.xOffset, ""))) } else { sb.WriteString(pe.styleW.Render(ansi.TruncateLeft(line, pe.xOffset, ""))) } if k+1 < l { sb.WriteByte('\n') } } return pe.styleH.Render(sb.String()) } func (pe *ModelProcessEnv) addEnvStyle() { if len(pe.envs) == 0 { return } keyStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#8a8af7ff")) equalStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("#f237ffff")) eq := equalStyle.Render("=") target := make([]string, 0, len(pe.envs)) for _, v := range pe.envs { if v == "" { continue } fields := strings.SplitN(v, "=", 2) if len(fields) != 2 { continue } target = append(target, keyStyle.Render(fields[0])+eq+fields[1]) } pe.envs = nil pe.envs = target }