fix: nvidia-smi field index mapping, TUI vertical layout to prevent scroll jump
This commit is contained in:
+28
-50
@@ -549,10 +549,7 @@ func (m model) viewMonitor() string {
|
|||||||
if tw < 60 {
|
if tw < 60 {
|
||||||
tw = 60
|
tw = 60
|
||||||
}
|
}
|
||||||
th := m.h
|
innerW := tw - 4
|
||||||
if th < 20 {
|
|
||||||
th = 20
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 顶栏 ──
|
// ── 顶栏 ──
|
||||||
wsDot := "○"
|
wsDot := "○"
|
||||||
@@ -572,47 +569,28 @@ func (m model) viewMonitor() string {
|
|||||||
)
|
)
|
||||||
sep := stDim.Render(strings.Repeat("─", tw))
|
sep := stDim.Render(strings.Repeat("─", tw))
|
||||||
|
|
||||||
// ── 列宽计算 ──
|
// ── 内容:全部垂直排列 ──
|
||||||
gap := 2
|
cpuBox := m.viewCPUBox(innerW)
|
||||||
var leftW, rightW int
|
memBox := m.viewMemBox(innerW)
|
||||||
if tw >= 100 {
|
histBox := m.viewHistBox(innerW)
|
||||||
leftW = (tw - gap) / 2
|
gpuBox := m.viewGPUBox(innerW)
|
||||||
rightW = tw - gap - leftW
|
|
||||||
} else {
|
|
||||||
leftW = tw
|
|
||||||
rightW = tw
|
|
||||||
gap = 0
|
|
||||||
}
|
|
||||||
innerL := leftW - 4
|
|
||||||
innerR := rightW - 4
|
|
||||||
|
|
||||||
// ── 左列: CPU + History ──
|
|
||||||
cpuBox := m.viewCPUBox(innerL)
|
|
||||||
histBox := m.viewHistBox(innerL)
|
|
||||||
leftCol := lipgloss.JoinVertical(lipgloss.Left, cpuBox, "", histBox)
|
|
||||||
|
|
||||||
// ── 右列: Memory + GPU ──
|
|
||||||
memBox := m.viewMemBox(innerR)
|
|
||||||
gpuBox := m.viewGPUBox(innerR)
|
|
||||||
rightCol := lipgloss.JoinVertical(lipgloss.Left, memBox, "", gpuBox)
|
|
||||||
|
|
||||||
// ── 合并列 ──
|
|
||||||
var mainContent string
|
|
||||||
if gap > 0 {
|
|
||||||
mainContent = lipgloss.JoinHorizontal(lipgloss.Top,
|
|
||||||
leftCol, strings.Repeat(" ", gap), rightCol,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
mainContent = lipgloss.JoinVertical(lipgloss.Left, leftCol, "", rightCol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── 底栏 ──
|
|
||||||
footer := stDim.Render(" q 退出 · r 重新配置 · 连接: " + m.cfg.Server)
|
|
||||||
|
|
||||||
full := lipgloss.JoinVertical(lipgloss.Left,
|
full := lipgloss.JoinVertical(lipgloss.Left,
|
||||||
header, sep, "", mainContent, "", sep, footer,
|
header, sep, "",
|
||||||
|
cpuBox, "",
|
||||||
|
memBox, "",
|
||||||
|
histBox, "",
|
||||||
|
gpuBox, "",
|
||||||
|
sep,
|
||||||
|
stDim.Render(" q 退出 · r 重新配置 · 连接: "+m.cfg.Server),
|
||||||
)
|
)
|
||||||
return lipgloss.Place(tw, th, lipgloss.Left, lipgloss.Top, full)
|
|
||||||
|
// 截断到终端高度,防止滚动
|
||||||
|
lines := strings.Split(full, "\n")
|
||||||
|
if len(lines) > m.h {
|
||||||
|
lines = lines[:m.h]
|
||||||
|
}
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── CPU 盒子 ──
|
// ── CPU 盒子 ──
|
||||||
@@ -1212,7 +1190,7 @@ func tryNvidiaSMI() []GPUInfo {
|
|||||||
var gpus []GPUInfo
|
var gpus []GPUInfo
|
||||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||||
parts := strings.Split(line, ",")
|
parts := strings.Split(line, ",")
|
||||||
if len(parts) < 11 {
|
if len(parts) < 17 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := range parts {
|
for i := range parts {
|
||||||
@@ -1220,10 +1198,10 @@ func tryNvidiaSMI() []GPUInfo {
|
|||||||
parts[i] = strings.Trim(parts[i], "[]")
|
parts[i] = strings.Trim(parts[i], "[]")
|
||||||
}
|
}
|
||||||
|
|
||||||
fan := parseFloatSafe(parts[10])
|
// 0:index 1:name 2:vram_total 3:vram_used 4:vram_free
|
||||||
power := parseFloatSafe(parts[9])
|
// 5:temp 6:load 7:core_clk 8:mem_clk 9:power 10:power_limit
|
||||||
powerLimit := parseFloatSafe(parts[10])
|
// 11:fan 12:pstate 13:persistence 14:compute_mode
|
||||||
|
// 15:driver 16:cuda
|
||||||
gpus = append(gpus, GPUInfo{
|
gpus = append(gpus, GPUInfo{
|
||||||
Name: parts[1],
|
Name: parts[1],
|
||||||
VRAMTotalMB: parseFloat(parts[2]),
|
VRAMTotalMB: parseFloat(parts[2]),
|
||||||
@@ -1232,9 +1210,9 @@ func tryNvidiaSMI() []GPUInfo {
|
|||||||
LoadPercent: parseFloat(parts[6]),
|
LoadPercent: parseFloat(parts[6]),
|
||||||
CoreClock: parseFloat(parts[7]),
|
CoreClock: parseFloat(parts[7]),
|
||||||
MemClock: parseFloat(parts[8]),
|
MemClock: parseFloat(parts[8]),
|
||||||
Power: power,
|
Power: parseFloatSafe(parts[9]),
|
||||||
PowerLimit: powerLimit,
|
PowerLimit: parseFloatSafe(parts[10]),
|
||||||
FanSpeed: fan,
|
FanSpeed: parseFloatSafe(parts[11]),
|
||||||
PState: cleanStr(parts[12]),
|
PState: cleanStr(parts[12]),
|
||||||
Persistence: cleanStr(parts[13]),
|
Persistence: cleanStr(parts[13]),
|
||||||
ComputeMode: cleanStr(parts[14]),
|
ComputeMode: cleanStr(parts[14]),
|
||||||
|
|||||||
Reference in New Issue
Block a user