process.go 6.29 KB
Newer Older
1
2
3
4
package tui

import (
	"fmt"
5
	"get-container/cmd/hytop/backend"
6
	"maps"
liming6's avatar
liming6 committed
7
	"slices"
8
9
10
11
12
13
14
	"strings"

	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
)

type ModelProcessInfo struct {
15
	Title            [2]string
16
17
18
19
20
21
22
	DoubleMiddleLine string
	MiddleLine       string
	BottomLine       string
	NoProceseLine    string // 没有进程时显示的行
	Cache            map[int][]backend.DCUProcessInfo
	width            int
	style            lipgloss.Style
23
	modMsg           *ModelMsg
liming6's avatar
liming6 committed
24
	actionMsg        *ActionMsg
25
26
27
28
}

const (
	Processes             = " Processes:"
29
	ModelProcessInfoTitle = " DCU     PID     USER  DCU-MEM SDMA  %CPU  %MEM      TIME Docker               Command"
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
	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')
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
	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"
72
73
74
75
76
77
78
79
	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 {
80
	darkMode := false
liming6's avatar
liming6 committed
81
	if m.actionMsg != nil && m.actionMsg.Action != nil && m.actionMsg.VM == VMMain {
82
83
		darkMode = true
	}
84
	haveProcess := false
liming6's avatar
liming6 committed
85
86
87
88
	var heightLightPid int32 = 0
	if m.actionMsg != nil && m.actionMsg.PointPid != nil {
		heightLightPid = *m.actionMsg.PointPid
	}
89
90
	lines := make([]string, 0)
	sb := strings.Builder{}
liming6's avatar
liming6 committed
91
	sbInner := strings.Builder{}
liming6's avatar
liming6 committed
92
93
94
95
96
97
98
99

	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]
100
101
102
		for _, process := range processes {
			haveProcess = true
			sb.WriteString(myBorder.Left)
liming6's avatar
liming6 committed
103
104
105
106
107
108
109

			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(' ')
liming6's avatar
liming6 committed
110
			sbInner.WriteString(FormatStr(process.DCUMem.HumanReadStr(1), 8, lipgloss.Right))
liming6's avatar
liming6 committed
111
112
113
114
115
116
117
118
119
			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(' ')
120
			if process.Info.ContInfo != nil {
liming6's avatar
liming6 committed
121
				sbInner.WriteString(FormatStr(process.Info.ContInfo.Name, 20, lipgloss.Left))
122
			} else {
liming6's avatar
liming6 committed
123
				sbInner.WriteString(FormatStr("  -  ", 20, lipgloss.Right))
124
			}
liming6's avatar
liming6 committed
125
126
			sbInner.WriteByte(' ')
			w := m.width - lipgloss.Width(sbInner.String()) - 3
127
128
			tw := lipgloss.Width(process.Info.Cmd)
			if w >= tw {
liming6's avatar
liming6 committed
129
130
				sbInner.WriteString(process.Info.Cmd)
				sbInner.WriteString(strings.Repeat(" ", w-tw))
131
			} else {
liming6's avatar
liming6 committed
132
133
				sbInner.WriteString(FormatStr(process.Info.Cmd, w-1, lipgloss.Left))
				sbInner.WriteString("..")
134
			}
liming6's avatar
liming6 committed
135
136
137
138
139
140
141
142
			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
				}
			}
143
144
145
146
			if darkMode {
				selected = false
			}
			if heightLightPid == process.Info.Pid && !darkMode {
liming6's avatar
liming6 committed
147
148
149
150
151
152
153
154
155
156
157
158
159
				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()
160
161
162
163
164
165
166
			sb.WriteString(myBorder.Right)
			sb.WriteByte('\n')
			lines = append(lines, sb.String())
			sb.Reset()
		}
		lines = append(lines, m.MiddleLine)
	}
167

168
169
170
171
172
173
174
175
176
177
178
179
	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())
180
	} else {
181
182
183
184
185
186
187
188
		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)
			}
189
		}
190
191
		sb.WriteString(m.BottomLine)
		return sb.String()
192
193
194
195
196
197
198
199
	}
}

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)
200
201
		m.modMsg = msg
		return m, nil
liming6's avatar
liming6 committed
202
203
204
	case *ActionMsg:
		m.actionMsg = msg
		return m, nil
205
206
207
	}
	return m, nil
}