package tui import ( "fmt" "get-container/cmd/hytop/backend" "maps" "slices" "strings" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) type ModelProcessInfo struct { Title [2]string DoubleMiddleLine string MiddleLine string BottomLine string NoProceseLine string // 没有进程时显示的行 Cache map[int][]backend.DCUProcessInfo width int style lipgloss.Style modMsg *ModelMsg actionMsg *ActionMsg } const ( Processes = " Processes:" ModelProcessInfoTitle = " DCU PID USER DCU-MEM SDMA %CPU %MEM TIME Docker Command" ModelProcessInfoNoPro = " No running processes found" ) func NewModelProcessInfo(width int) *ModelProcessInfo { result := ModelProcessInfo{width: width, Cache: make(map[int][]backend.DCUProcessInfo), style: lipgloss.NewStyle()} return &result } func (m *ModelProcessInfo) Init() tea.Cmd { sb := strings.Builder{} sb.WriteString(myBorder.Left) sb.WriteString(Processes) uah := fmt.Sprintf("%s@%s ", m.style.Foreground(lipgloss.Color("#edff2cff")).SetString(backend.User).String(), m.style.Foreground(lipgloss.Color("#a3ff2bff")).SetString(backend.HostName).String()) space := strings.Repeat(" ", m.width-lipgloss.Width(Processes)-lipgloss.Width(uah)-2) sb.WriteString(space) sb.WriteString(uah) sb.WriteString(myBorder.Right) sb.WriteByte('\n') sb.WriteString(myBorder.Left) sb.WriteString(ModelProcessInfoTitle) sb.WriteString(strings.Repeat(" ", m.width-2-lipgloss.Width(ModelProcessInfoTitle))) sb.WriteString(myBorder.Right) sb.WriteByte('\n') m.Title[0] = sb.String() sb.Reset() sb.WriteString(myBorder.Left) sb.WriteString(Processes) uah = fmt.Sprintf("%s@%s ", backend.User, backend.HostName) space = strings.Repeat(" ", m.width-lipgloss.Width(Processes)-lipgloss.Width(uah)-2) sb.WriteString(space) sb.WriteString(uah) sb.WriteString(myBorder.Right) sb.WriteByte('\n') sb.WriteString(myBorder.Left) sb.WriteString(ModelProcessInfoTitle) sb.WriteString(strings.Repeat(" ", m.width-2-lipgloss.Width(ModelProcessInfoTitle))) sb.WriteString(myBorder.Right) m.Title[1] = LowLeightStyle.Render(sb.String()) + "\n" m.DoubleMiddleLine = "╞" + strings.Repeat("═", m.width-2) + "╡\n" m.MiddleLine = myBorder.MiddleLeft + strings.Repeat("─", m.width-2) + myBorder.MiddleRight + "\n" m.BottomLine = myBorder.BottomLeft + strings.Repeat("═", m.width-2) + myBorder.BottomRight m.NoProceseLine = myBorder.Left + ModelProcessInfoNoPro + strings.Repeat(" ", m.width-2-lipgloss.Width(ModelProcessInfoNoPro)) + myBorder.Right + "\n" return nil } func (m *ModelProcessInfo) View() string { darkMode := false if m.actionMsg != nil && m.actionMsg.Action != nil && m.actionMsg.VM == VMMain { darkMode = true } haveProcess := false var heightLightPid int32 = 0 if m.actionMsg != nil && m.actionMsg.PointPid != nil { heightLightPid = *m.actionMsg.PointPid } lines := make([]string, 0) sb := strings.Builder{} sbInner := strings.Builder{} keys := make([]int, 0, len(m.Cache)) for k := range m.Cache { keys = append(keys, k) } slices.Sort(keys) for _, index := range keys { processes := m.Cache[index] for _, process := range processes { haveProcess = true sb.WriteString(myBorder.Left) sbInner.WriteString(FormatStr(fmt.Sprintf("%d", process.DCU), 4, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(fmt.Sprintf("%d", process.Info.Pid), 7, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(process.Info.User, 8, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(process.DCUMem.HumanReadStr(1), 8, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(fmt.Sprintf("%d", process.SDMA), 4, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(fmt.Sprintf("%.1f", process.Info.CPU), 5, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(fmt.Sprintf("%.1f", process.Info.Mem), 5, lipgloss.Right)) sbInner.WriteByte(' ') sbInner.WriteString(FormatStr(process.Info.Time, 9, lipgloss.Right)) sbInner.WriteByte(' ') if process.Info.ContInfo != nil { sbInner.WriteString(FormatStr(process.Info.ContInfo.Name, 20, lipgloss.Left)) } else { sbInner.WriteString(FormatStr(" - ", 20, lipgloss.Right)) } sbInner.WriteByte(' ') w := m.width - lipgloss.Width(sbInner.String()) - 3 tw := lipgloss.Width(process.Info.Cmd) if w >= tw { sbInner.WriteString(process.Info.Cmd) sbInner.WriteString(strings.Repeat(" ", w-tw)) } else { sbInner.WriteString(FormatStr(process.Info.Cmd, w-1, lipgloss.Left)) sbInner.WriteString("..") } sbInner.WriteByte(' ') selected := false if m.actionMsg != nil && m.actionMsg.SelectPids != nil { b, have := m.actionMsg.SelectPids[process.Info.Pid] if have && b { selected = true } } if darkMode { selected = false } if heightLightPid == process.Info.Pid && !darkMode { if selected { sb.WriteString(HeightSelectedStyle.Render(sbInner.String())) } else { sb.WriteString(HeightLightStyle.Render(sbInner.String())) } } else { if selected { sb.WriteString(SelectedStyle.Render(sbInner.String())) } else { sb.WriteString(sbInner.String()) } } sbInner.Reset() sb.WriteString(myBorder.Right) sb.WriteByte('\n') lines = append(lines, sb.String()) sb.Reset() } lines = append(lines, m.MiddleLine) } if darkMode { sb.WriteString(m.Title[1]) sb.WriteString(m.DoubleMiddleLine) if !haveProcess { sb.WriteString(m.NoProceseLine) } else { for _, v := range lines[:len(lines)-1] { sb.WriteString(v) } } sb.WriteString(m.BottomLine) return LowLeightStyle.Render(sb.String()) } else { sb.WriteString(m.Title[0]) sb.WriteString(m.DoubleMiddleLine) if !haveProcess { sb.WriteString(m.NoProceseLine) } else { for _, v := range lines[:len(lines)-1] { sb.WriteString(v) } } sb.WriteString(m.BottomLine) return sb.String() } } func (m *ModelProcessInfo) Update(inputMsg tea.Msg) (tea.Model, tea.Cmd) { switch msg := inputMsg.(type) { case *ModelMsg: clear(m.Cache) maps.Copy(m.Cache, msg.DCUPidInfo) m.modMsg = msg return m, nil case *ActionMsg: m.actionMsg = msg return m, nil } return m, nil }