Replace Enter-key process detail pretty-print with flattened/summary/fd/env
views; gate legacy JSON with BARE_TOP_PROC_DETAIL_JSON. Render nested snapshot fields via bareTopFormatNestedBrief instead of compact JSON snippets (features, net helpers, overview). Retitle help/initd copy and soften catalog quotas hint; document new env in -h and F2 setup. Regenerate kernel baretop/btop bundles. Shallow object lines format *Bytes and *Ms with existing formatters.
This commit is contained in:
+267
-9
@@ -1582,7 +1582,7 @@ function bareTopLimitsMergedLines(snap) {
|
||||
}
|
||||
}
|
||||
if (q) {
|
||||
lines.push(' quotas (operator caps — full JSON on catalog tab)')
|
||||
lines.push(' quotas (operator caps — full detail on catalog tab)')
|
||||
row(' ', q, 8)
|
||||
}
|
||||
if (r) {
|
||||
@@ -1592,6 +1592,128 @@ function bareTopLimitsMergedLines(snap) {
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable key labels (matches baretop-tui bareTopHumanKey).
|
||||
* @param {string} k
|
||||
*/
|
||||
function bareTopUiHumanKey(k) {
|
||||
return String(k || '')
|
||||
.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/^\w/, (c) => c.toUpperCase())
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten nested values to lines (no JSON); uses N/A for nulls.
|
||||
* @param {string} prefix
|
||||
* @param {unknown} v
|
||||
* @param {number} depth
|
||||
* @param {number} maxD
|
||||
* @param {string[]} lines
|
||||
* @param {number} maxKeys
|
||||
*/
|
||||
function bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys) {
|
||||
const na = 'N/A'
|
||||
const pad = ' '.repeat(depth)
|
||||
if (depth > maxD) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '\u2026')
|
||||
return
|
||||
}
|
||||
if (v == null) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + na)
|
||||
return
|
||||
}
|
||||
const t = typeof v
|
||||
if (t === 'string' || t === 'number' || t === 'boolean') {
|
||||
let s = String(v)
|
||||
if (t === 'string' && s.length > 800) s = s.slice(0, 797) + '\u2026'
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + s)
|
||||
return
|
||||
}
|
||||
if (Array.isArray(v)) {
|
||||
const label = prefix ? bareTopUiHumanKey(prefix) + ': ' : ''
|
||||
if (v.length === 0) {
|
||||
lines.push(pad + label + '(empty)')
|
||||
return
|
||||
}
|
||||
lines.push(pad + label + '(' + v.length + ' items)')
|
||||
const lim = Math.min(v.length, 120)
|
||||
for (let i = 0; i < lim; i++) {
|
||||
const it = v[i]
|
||||
if (it != null && typeof it === 'object' && !Array.isArray(it)) {
|
||||
lines.push(pad + ' #' + i)
|
||||
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
|
||||
} else if (Array.isArray(it)) {
|
||||
lines.push(pad + ' #' + i)
|
||||
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
|
||||
} else {
|
||||
lines.push(
|
||||
pad + ' #' + i + ': ' + (it == null ? na : String(it))
|
||||
)
|
||||
}
|
||||
}
|
||||
if (v.length > lim) lines.push(pad + ' \u2026 +' + (v.length - lim) + ' more')
|
||||
return
|
||||
}
|
||||
if (t === 'object') {
|
||||
const o = /** @type {Record<string, unknown>} */ (v)
|
||||
const keys = Object.keys(o)
|
||||
if (keys.length === 0) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '(empty)')
|
||||
return
|
||||
}
|
||||
const slice = keys.slice(0, maxKeys)
|
||||
if (prefix) {
|
||||
lines.push(pad + bareTopUiHumanKey(prefix) + ':')
|
||||
for (const k of slice) bareTopUiFlatten(k, o[k], depth + 1, maxD, lines, maxKeys)
|
||||
} else {
|
||||
for (const k of slice) bareTopUiFlatten(k, o[k], depth, maxD, lines, maxKeys)
|
||||
}
|
||||
if (keys.length > maxKeys)
|
||||
lines.push(pad + '\u2026 +' + (keys.length - maxKeys) + ' keys')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} prefix
|
||||
* @param {unknown} v
|
||||
* @param {number} depth
|
||||
* @param {number} maxD
|
||||
* @param {number} maxKeys
|
||||
* @param {number} maxLines
|
||||
*/
|
||||
function bareTopUiFlattenLimited(prefix, v, depth, maxD, maxKeys, maxLines) {
|
||||
const lines = []
|
||||
bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys)
|
||||
const cap = Math.max(4, maxLines | 0)
|
||||
if (lines.length > cap) {
|
||||
return lines.slice(0, cap - 1).concat([' … (truncated)'])
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* One-line-ish summary for nested objects (no JSON braces in the TUI).
|
||||
* @param {unknown} v
|
||||
* @param {number} maxChars
|
||||
*/
|
||||
function bareTopFormatNestedBrief(v, maxChars) {
|
||||
const m = Math.max(8, maxChars | 0)
|
||||
if (v == null) return ''
|
||||
const t = typeof v
|
||||
if (t === 'string' || t === 'number' || t === 'boolean')
|
||||
return bareTopTruncateCell(String(v), m, false)
|
||||
if (t === 'bigint') return String(v)
|
||||
if (t !== 'object') return bareTopTruncateCell(String(v), m, false)
|
||||
const lines = bareTopUiFlattenLimited('', v, 0, 6, 80, 24)
|
||||
const s = lines.join(' · ')
|
||||
if (s.length <= m) return s
|
||||
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} v
|
||||
* @param {number} maxChars
|
||||
@@ -1599,6 +1721,9 @@ function bareTopLimitsMergedLines(snap) {
|
||||
function bareTopJsonSnippet(v, maxChars) {
|
||||
const m = Math.max(8, maxChars | 0)
|
||||
try {
|
||||
if (v != null && typeof v === 'object')
|
||||
return bareTopFormatNestedBrief(v, m)
|
||||
if (typeof v === 'bigint') return String(v)
|
||||
const s = JSON.stringify(v)
|
||||
if (s.length <= m) return s
|
||||
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
|
||||
@@ -4216,7 +4341,24 @@ function bareTopShallowObjectLines(val, cols) {
|
||||
for (const k of keys.slice(0, 80)) {
|
||||
const label = bareTopHumanKey(k).slice(0, keyW)
|
||||
const pad = ' '.repeat(Math.max(0, keyW - label.length))
|
||||
let sv = o[k] == null ? bareTopStrings.na : String(o[k])
|
||||
const rawV = o[k]
|
||||
let sv = ''
|
||||
if (rawV == null) sv = bareTopStrings.na
|
||||
else if (
|
||||
typeof rawV === 'number' &&
|
||||
Number.isFinite(rawV) &&
|
||||
/Bytes$/i.test(k) &&
|
||||
typeof bareTopFormatBytes === 'function'
|
||||
)
|
||||
sv = bareTopFormatBytes(rawV)
|
||||
else if (
|
||||
typeof rawV === 'number' &&
|
||||
Number.isFinite(rawV) &&
|
||||
/Ms$/i.test(k) &&
|
||||
typeof bareTopFormatDurationMs === 'function'
|
||||
)
|
||||
sv = bareTopFormatDurationMs(rawV)
|
||||
else sv = String(rawV)
|
||||
sv = bareTopTruncateCell(sv, Math.max(8, cols - keyW - 4), true)
|
||||
out.push(' ' + label + pad + ' ' + sv)
|
||||
}
|
||||
@@ -4271,6 +4413,118 @@ function bareTopLinesFromSingle(title, o, maxDepth, wrapCols) {
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll line budget for process detail panel.
|
||||
* @param {number} rows
|
||||
* @param {number} hdrRow
|
||||
*/
|
||||
function bareTopProcDetailMaxLines(rows, hdrRow) {
|
||||
return Math.max(12, Math.min(200, Math.max(1, rows - hdrRow - 2)))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} o
|
||||
* @param {number} cols
|
||||
*/
|
||||
function bareTopProcDetailEnvLines(o, cols) {
|
||||
const c = Math.max(24, cols | 0)
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
const keys = Object.keys(o).sort((a, b) => a.localeCompare(b))
|
||||
for (const k of keys) {
|
||||
const v = o[k]
|
||||
let val = ''
|
||||
if (v == null) val = ''
|
||||
else if (typeof v === 'object')
|
||||
val = bareTopFlattenLimited('', v, 0, 4, 48, 8).join(' ')
|
||||
else val = String(v)
|
||||
const piece = k + '=' + val
|
||||
lines.push(' ' + bareTopTruncateCell(piece, Math.max(12, c - 2), false))
|
||||
}
|
||||
return lines.length ? lines : [' (empty env)']
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} o
|
||||
* @param {number} cols
|
||||
*/
|
||||
function bareTopProcDetailFdLines(o, cols) {
|
||||
const c = Math.max(24, cols | 0)
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
const keys = Object.keys(o)
|
||||
keys.sort((a, b) => {
|
||||
const na = Number(a)
|
||||
const nb = Number(b)
|
||||
if (Number.isFinite(na) && Number.isFinite(nb)) return na - nb
|
||||
return String(a).localeCompare(String(b))
|
||||
})
|
||||
for (const k of keys) {
|
||||
const v = o[k]
|
||||
let cell = ''
|
||||
if (v == null) cell = ''
|
||||
else if (typeof v === 'object' && !Array.isArray(v)) {
|
||||
cell = bareTopFlattenLimited('', v, 0, 5, 48, 12).join(' · ')
|
||||
} else if (Array.isArray(v)) {
|
||||
cell = v.map((x) => String(x)).join(', ')
|
||||
} else {
|
||||
cell = String(v)
|
||||
}
|
||||
const ks = String(k)
|
||||
const fdLab =
|
||||
ks.length <= 8 ? ks.padStart(4) : bareTopTruncateCell(ks, 8, false)
|
||||
lines.push(
|
||||
' ' +
|
||||
fdLab +
|
||||
' ' +
|
||||
bareTopTruncateCell(cell, Math.max(12, c - 12), false)
|
||||
)
|
||||
}
|
||||
return lines.length ? lines : [' (empty fd table)']
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'all' | 'summary' | 'fds' | 'env'} sub
|
||||
* @param {Record<string, unknown>} detailObj
|
||||
* @param {number} cols
|
||||
* @param {number} maxLines
|
||||
* @param {Record<string, string>} envTop
|
||||
*/
|
||||
function bareTopProcDetailBodyLines(sub, detailObj, cols, maxLines, envTop) {
|
||||
const wantJson =
|
||||
envTop.BARE_TOP_PROC_DETAIL_JSON === '1' ||
|
||||
envTop.BARE_TOP_PROC_DETAIL_JSON === 'true'
|
||||
const maxChars = Math.min(
|
||||
16000,
|
||||
Math.max(400, cols * Math.max(8, maxLines) * 2)
|
||||
)
|
||||
if (wantJson)
|
||||
return bareTopTruncateJsonPretty(detailObj, maxChars).split('\n')
|
||||
const onlyNote =
|
||||
detailObj &&
|
||||
typeof detailObj === 'object' &&
|
||||
!Array.isArray(detailObj) &&
|
||||
Object.keys(detailObj).length === 1 &&
|
||||
typeof detailObj.note === 'string'
|
||||
if (onlyNote) return [' ' + String(detailObj.note)]
|
||||
if (sub === 'env')
|
||||
return bareTopProcDetailEnvLines(
|
||||
/** @type {Record<string, unknown>} */ (detailObj),
|
||||
cols
|
||||
)
|
||||
if (sub === 'fds')
|
||||
return bareTopProcDetailFdLines(
|
||||
/** @type {Record<string, unknown>} */ (detailObj),
|
||||
cols
|
||||
)
|
||||
if (sub === 'summary') {
|
||||
const shallow = bareTopShallowObjectLines(detailObj, cols)
|
||||
if (shallow) return shallow
|
||||
return bareTopFlattenLimited('', detailObj, 1, 6, 120, maxLines)
|
||||
}
|
||||
return bareTopFlattenLimited('', detailObj, 1, 10, 120, maxLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} maxLen
|
||||
@@ -5163,8 +5417,8 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
'Actions (2/2)' +
|
||||
rst +
|
||||
'\r\n' +
|
||||
' < > Sort processes F6 S sort menu V tree x initd raw JSON\r\n' +
|
||||
' Enter Process JSON detail k F9 signal (HUP USR1 USR2 TERM INT KILL)\r\n' +
|
||||
' < > Sort processes F6 S sort menu V tree x initd alternate view\r\n' +
|
||||
' Enter Process detail panel k F9 signal (HUP USR1 USR2 TERM INT KILL)\r\n' +
|
||||
' F2 Setup F3 F4 row jump (matches / filter substring when set)\r\n' +
|
||||
' F10 Quit h ? help\r\n' +
|
||||
'\r\n' +
|
||||
@@ -5237,6 +5491,7 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
' BARE_TOP_SNAPSHOT_LITE 1 = smaller /proc batch (see baretop -h)\r\n' +
|
||||
' BARE_TOP_NET_FILTER 1 = / filter applies on network tab\r\n' +
|
||||
' BARE_TOP_CMD_ELLIPSIS_MIDDLE 1 = middle-ellipsis long process names\r\n' +
|
||||
' BARE_TOP_PROC_DETAIL_JSON 1 = pretty-print JSON in process detail (Enter)\r\n' +
|
||||
' BARE_TOP_DEBUG_TIMINGS 1 = throttled fetch/draw ms on stderr\r\n' +
|
||||
' BARE_TOP_FETCH_EWMA 1 = lower /proc batch concurrency when fetches are slow\r\n' +
|
||||
' BARE_TOP_SNAPSHOT_LITE_AUTO 1 = auto lite batch after sustained slow fetches\r\n' +
|
||||
@@ -5927,11 +6182,13 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
? /** @type {Record<string, unknown>} */ (raw.env)
|
||||
: { note: 'no env slice on row' }
|
||||
}
|
||||
const js = bareTopTruncateJsonPretty(
|
||||
const jl = bareTopProcDetailBodyLines(
|
||||
/** @type {'all' | 'summary' | 'fds' | 'env'} */ (procDetailSub),
|
||||
detailObj,
|
||||
Math.min(16000, Math.max(400, cols * Math.max(8, rows - hdrRow - 2) * 2))
|
||||
cols,
|
||||
bareTopProcDetailMaxLines(rows, hdrRow),
|
||||
envTop
|
||||
)
|
||||
const jl = js.split('\n')
|
||||
emitHdrLn(
|
||||
(useColor ? pal.dim : '') +
|
||||
' (Enter closes) i summary o fds e env sub:' +
|
||||
@@ -6180,11 +6437,11 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
'Initd graph' +
|
||||
(useColor ? pal.reset : '') +
|
||||
(filterInitd ? ' filter:' + filterInitd : '') +
|
||||
(initdRawFallback ? ' [raw JSON]' : '')
|
||||
(initdRawFallback ? ' [alternate layout]' : '')
|
||||
)
|
||||
emitHdrLn(
|
||||
(useColor ? pal.dim : '') +
|
||||
'x toggles raw JSON view when nodes list exists' +
|
||||
'x toggles alternate layout when a nodes list exists (edges / graph path)' +
|
||||
(useColor ? pal.reset : '')
|
||||
)
|
||||
const g = snap.initdGraph
|
||||
@@ -7733,6 +7990,7 @@ async function run(ctx, argv) {
|
||||
' BARE_TOP_PROC_COL_SEP=1 Unicode column separators in process table\n' +
|
||||
' BARE_TOP_MINIMAP=1 Scroll minimap on long lists\n' +
|
||||
' BARE_TOP_CMD_ELLIPSIS_MIDDLE Middle-ellipsis long process names\n' +
|
||||
' BARE_TOP_PROC_DETAIL_JSON 1 = pretty-print JSON in process detail (Enter)\n' +
|
||||
' BARE_TOP_NO_ALTSCREEN Non-empty skips alternate-screen mode\n' +
|
||||
' BARE_TOP_NO_2J_AFTER_FIRST Soft clear after first full paint\n' +
|
||||
' BARE_TOP_ASCII_GRAPH / BARE_TOP_ASCII_UI / BARE_TOP_MONO / BARE_TOP_BRAILLE_SPARK\n' +
|
||||
|
||||
+267
-9
@@ -1582,7 +1582,7 @@ function bareTopLimitsMergedLines(snap) {
|
||||
}
|
||||
}
|
||||
if (q) {
|
||||
lines.push(' quotas (operator caps — full JSON on catalog tab)')
|
||||
lines.push(' quotas (operator caps — full detail on catalog tab)')
|
||||
row(' ', q, 8)
|
||||
}
|
||||
if (r) {
|
||||
@@ -1592,6 +1592,128 @@ function bareTopLimitsMergedLines(snap) {
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable key labels (matches baretop-tui bareTopHumanKey).
|
||||
* @param {string} k
|
||||
*/
|
||||
function bareTopUiHumanKey(k) {
|
||||
return String(k || '')
|
||||
.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/^\w/, (c) => c.toUpperCase())
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten nested values to lines (no JSON); uses N/A for nulls.
|
||||
* @param {string} prefix
|
||||
* @param {unknown} v
|
||||
* @param {number} depth
|
||||
* @param {number} maxD
|
||||
* @param {string[]} lines
|
||||
* @param {number} maxKeys
|
||||
*/
|
||||
function bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys) {
|
||||
const na = 'N/A'
|
||||
const pad = ' '.repeat(depth)
|
||||
if (depth > maxD) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '\u2026')
|
||||
return
|
||||
}
|
||||
if (v == null) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + na)
|
||||
return
|
||||
}
|
||||
const t = typeof v
|
||||
if (t === 'string' || t === 'number' || t === 'boolean') {
|
||||
let s = String(v)
|
||||
if (t === 'string' && s.length > 800) s = s.slice(0, 797) + '\u2026'
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + s)
|
||||
return
|
||||
}
|
||||
if (Array.isArray(v)) {
|
||||
const label = prefix ? bareTopUiHumanKey(prefix) + ': ' : ''
|
||||
if (v.length === 0) {
|
||||
lines.push(pad + label + '(empty)')
|
||||
return
|
||||
}
|
||||
lines.push(pad + label + '(' + v.length + ' items)')
|
||||
const lim = Math.min(v.length, 120)
|
||||
for (let i = 0; i < lim; i++) {
|
||||
const it = v[i]
|
||||
if (it != null && typeof it === 'object' && !Array.isArray(it)) {
|
||||
lines.push(pad + ' #' + i)
|
||||
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
|
||||
} else if (Array.isArray(it)) {
|
||||
lines.push(pad + ' #' + i)
|
||||
bareTopUiFlatten('', it, depth + 2, maxD, lines, maxKeys)
|
||||
} else {
|
||||
lines.push(
|
||||
pad + ' #' + i + ': ' + (it == null ? na : String(it))
|
||||
)
|
||||
}
|
||||
}
|
||||
if (v.length > lim) lines.push(pad + ' \u2026 +' + (v.length - lim) + ' more')
|
||||
return
|
||||
}
|
||||
if (t === 'object') {
|
||||
const o = /** @type {Record<string, unknown>} */ (v)
|
||||
const keys = Object.keys(o)
|
||||
if (keys.length === 0) {
|
||||
lines.push(pad + (prefix ? bareTopUiHumanKey(prefix) + ': ' : '') + '(empty)')
|
||||
return
|
||||
}
|
||||
const slice = keys.slice(0, maxKeys)
|
||||
if (prefix) {
|
||||
lines.push(pad + bareTopUiHumanKey(prefix) + ':')
|
||||
for (const k of slice) bareTopUiFlatten(k, o[k], depth + 1, maxD, lines, maxKeys)
|
||||
} else {
|
||||
for (const k of slice) bareTopUiFlatten(k, o[k], depth, maxD, lines, maxKeys)
|
||||
}
|
||||
if (keys.length > maxKeys)
|
||||
lines.push(pad + '\u2026 +' + (keys.length - maxKeys) + ' keys')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} prefix
|
||||
* @param {unknown} v
|
||||
* @param {number} depth
|
||||
* @param {number} maxD
|
||||
* @param {number} maxKeys
|
||||
* @param {number} maxLines
|
||||
*/
|
||||
function bareTopUiFlattenLimited(prefix, v, depth, maxD, maxKeys, maxLines) {
|
||||
const lines = []
|
||||
bareTopUiFlatten(prefix, v, depth, maxD, lines, maxKeys)
|
||||
const cap = Math.max(4, maxLines | 0)
|
||||
if (lines.length > cap) {
|
||||
return lines.slice(0, cap - 1).concat([' … (truncated)'])
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* One-line-ish summary for nested objects (no JSON braces in the TUI).
|
||||
* @param {unknown} v
|
||||
* @param {number} maxChars
|
||||
*/
|
||||
function bareTopFormatNestedBrief(v, maxChars) {
|
||||
const m = Math.max(8, maxChars | 0)
|
||||
if (v == null) return ''
|
||||
const t = typeof v
|
||||
if (t === 'string' || t === 'number' || t === 'boolean')
|
||||
return bareTopTruncateCell(String(v), m, false)
|
||||
if (t === 'bigint') return String(v)
|
||||
if (t !== 'object') return bareTopTruncateCell(String(v), m, false)
|
||||
const lines = bareTopUiFlattenLimited('', v, 0, 6, 80, 24)
|
||||
const s = lines.join(' · ')
|
||||
if (s.length <= m) return s
|
||||
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} v
|
||||
* @param {number} maxChars
|
||||
@@ -1599,6 +1721,9 @@ function bareTopLimitsMergedLines(snap) {
|
||||
function bareTopJsonSnippet(v, maxChars) {
|
||||
const m = Math.max(8, maxChars | 0)
|
||||
try {
|
||||
if (v != null && typeof v === 'object')
|
||||
return bareTopFormatNestedBrief(v, m)
|
||||
if (typeof v === 'bigint') return String(v)
|
||||
const s = JSON.stringify(v)
|
||||
if (s.length <= m) return s
|
||||
return s.slice(0, Math.max(4, m - 18)) + '\u2026(truncated)'
|
||||
@@ -4216,7 +4341,24 @@ function bareTopShallowObjectLines(val, cols) {
|
||||
for (const k of keys.slice(0, 80)) {
|
||||
const label = bareTopHumanKey(k).slice(0, keyW)
|
||||
const pad = ' '.repeat(Math.max(0, keyW - label.length))
|
||||
let sv = o[k] == null ? bareTopStrings.na : String(o[k])
|
||||
const rawV = o[k]
|
||||
let sv = ''
|
||||
if (rawV == null) sv = bareTopStrings.na
|
||||
else if (
|
||||
typeof rawV === 'number' &&
|
||||
Number.isFinite(rawV) &&
|
||||
/Bytes$/i.test(k) &&
|
||||
typeof bareTopFormatBytes === 'function'
|
||||
)
|
||||
sv = bareTopFormatBytes(rawV)
|
||||
else if (
|
||||
typeof rawV === 'number' &&
|
||||
Number.isFinite(rawV) &&
|
||||
/Ms$/i.test(k) &&
|
||||
typeof bareTopFormatDurationMs === 'function'
|
||||
)
|
||||
sv = bareTopFormatDurationMs(rawV)
|
||||
else sv = String(rawV)
|
||||
sv = bareTopTruncateCell(sv, Math.max(8, cols - keyW - 4), true)
|
||||
out.push(' ' + label + pad + ' ' + sv)
|
||||
}
|
||||
@@ -4271,6 +4413,118 @@ function bareTopLinesFromSingle(title, o, maxDepth, wrapCols) {
|
||||
return lines
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll line budget for process detail panel.
|
||||
* @param {number} rows
|
||||
* @param {number} hdrRow
|
||||
*/
|
||||
function bareTopProcDetailMaxLines(rows, hdrRow) {
|
||||
return Math.max(12, Math.min(200, Math.max(1, rows - hdrRow - 2)))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} o
|
||||
* @param {number} cols
|
||||
*/
|
||||
function bareTopProcDetailEnvLines(o, cols) {
|
||||
const c = Math.max(24, cols | 0)
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
const keys = Object.keys(o).sort((a, b) => a.localeCompare(b))
|
||||
for (const k of keys) {
|
||||
const v = o[k]
|
||||
let val = ''
|
||||
if (v == null) val = ''
|
||||
else if (typeof v === 'object')
|
||||
val = bareTopFlattenLimited('', v, 0, 4, 48, 8).join(' ')
|
||||
else val = String(v)
|
||||
const piece = k + '=' + val
|
||||
lines.push(' ' + bareTopTruncateCell(piece, Math.max(12, c - 2), false))
|
||||
}
|
||||
return lines.length ? lines : [' (empty env)']
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} o
|
||||
* @param {number} cols
|
||||
*/
|
||||
function bareTopProcDetailFdLines(o, cols) {
|
||||
const c = Math.max(24, cols | 0)
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
const keys = Object.keys(o)
|
||||
keys.sort((a, b) => {
|
||||
const na = Number(a)
|
||||
const nb = Number(b)
|
||||
if (Number.isFinite(na) && Number.isFinite(nb)) return na - nb
|
||||
return String(a).localeCompare(String(b))
|
||||
})
|
||||
for (const k of keys) {
|
||||
const v = o[k]
|
||||
let cell = ''
|
||||
if (v == null) cell = ''
|
||||
else if (typeof v === 'object' && !Array.isArray(v)) {
|
||||
cell = bareTopFlattenLimited('', v, 0, 5, 48, 12).join(' · ')
|
||||
} else if (Array.isArray(v)) {
|
||||
cell = v.map((x) => String(x)).join(', ')
|
||||
} else {
|
||||
cell = String(v)
|
||||
}
|
||||
const ks = String(k)
|
||||
const fdLab =
|
||||
ks.length <= 8 ? ks.padStart(4) : bareTopTruncateCell(ks, 8, false)
|
||||
lines.push(
|
||||
' ' +
|
||||
fdLab +
|
||||
' ' +
|
||||
bareTopTruncateCell(cell, Math.max(12, c - 12), false)
|
||||
)
|
||||
}
|
||||
return lines.length ? lines : [' (empty fd table)']
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'all' | 'summary' | 'fds' | 'env'} sub
|
||||
* @param {Record<string, unknown>} detailObj
|
||||
* @param {number} cols
|
||||
* @param {number} maxLines
|
||||
* @param {Record<string, string>} envTop
|
||||
*/
|
||||
function bareTopProcDetailBodyLines(sub, detailObj, cols, maxLines, envTop) {
|
||||
const wantJson =
|
||||
envTop.BARE_TOP_PROC_DETAIL_JSON === '1' ||
|
||||
envTop.BARE_TOP_PROC_DETAIL_JSON === 'true'
|
||||
const maxChars = Math.min(
|
||||
16000,
|
||||
Math.max(400, cols * Math.max(8, maxLines) * 2)
|
||||
)
|
||||
if (wantJson)
|
||||
return bareTopTruncateJsonPretty(detailObj, maxChars).split('\n')
|
||||
const onlyNote =
|
||||
detailObj &&
|
||||
typeof detailObj === 'object' &&
|
||||
!Array.isArray(detailObj) &&
|
||||
Object.keys(detailObj).length === 1 &&
|
||||
typeof detailObj.note === 'string'
|
||||
if (onlyNote) return [' ' + String(detailObj.note)]
|
||||
if (sub === 'env')
|
||||
return bareTopProcDetailEnvLines(
|
||||
/** @type {Record<string, unknown>} */ (detailObj),
|
||||
cols
|
||||
)
|
||||
if (sub === 'fds')
|
||||
return bareTopProcDetailFdLines(
|
||||
/** @type {Record<string, unknown>} */ (detailObj),
|
||||
cols
|
||||
)
|
||||
if (sub === 'summary') {
|
||||
const shallow = bareTopShallowObjectLines(detailObj, cols)
|
||||
if (shallow) return shallow
|
||||
return bareTopFlattenLimited('', detailObj, 1, 6, 120, maxLines)
|
||||
}
|
||||
return bareTopFlattenLimited('', detailObj, 1, 10, 120, maxLines)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {number} maxLen
|
||||
@@ -5163,8 +5417,8 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
'Actions (2/2)' +
|
||||
rst +
|
||||
'\r\n' +
|
||||
' < > Sort processes F6 S sort menu V tree x initd raw JSON\r\n' +
|
||||
' Enter Process JSON detail k F9 signal (HUP USR1 USR2 TERM INT KILL)\r\n' +
|
||||
' < > Sort processes F6 S sort menu V tree x initd alternate view\r\n' +
|
||||
' Enter Process detail panel k F9 signal (HUP USR1 USR2 TERM INT KILL)\r\n' +
|
||||
' F2 Setup F3 F4 row jump (matches / filter substring when set)\r\n' +
|
||||
' F10 Quit h ? help\r\n' +
|
||||
'\r\n' +
|
||||
@@ -5237,6 +5491,7 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
' BARE_TOP_SNAPSHOT_LITE 1 = smaller /proc batch (see baretop -h)\r\n' +
|
||||
' BARE_TOP_NET_FILTER 1 = / filter applies on network tab\r\n' +
|
||||
' BARE_TOP_CMD_ELLIPSIS_MIDDLE 1 = middle-ellipsis long process names\r\n' +
|
||||
' BARE_TOP_PROC_DETAIL_JSON 1 = pretty-print JSON in process detail (Enter)\r\n' +
|
||||
' BARE_TOP_DEBUG_TIMINGS 1 = throttled fetch/draw ms on stderr\r\n' +
|
||||
' BARE_TOP_FETCH_EWMA 1 = lower /proc batch concurrency when fetches are slow\r\n' +
|
||||
' BARE_TOP_SNAPSHOT_LITE_AUTO 1 = auto lite batch after sustained slow fetches\r\n' +
|
||||
@@ -5927,11 +6182,13 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
? /** @type {Record<string, unknown>} */ (raw.env)
|
||||
: { note: 'no env slice on row' }
|
||||
}
|
||||
const js = bareTopTruncateJsonPretty(
|
||||
const jl = bareTopProcDetailBodyLines(
|
||||
/** @type {'all' | 'summary' | 'fds' | 'env'} */ (procDetailSub),
|
||||
detailObj,
|
||||
Math.min(16000, Math.max(400, cols * Math.max(8, rows - hdrRow - 2) * 2))
|
||||
cols,
|
||||
bareTopProcDetailMaxLines(rows, hdrRow),
|
||||
envTop
|
||||
)
|
||||
const jl = js.split('\n')
|
||||
emitHdrLn(
|
||||
(useColor ? pal.dim : '') +
|
||||
' (Enter closes) i summary o fds e env sub:' +
|
||||
@@ -6180,11 +6437,11 @@ async function bareOsRunBareTopTui(ctx) {
|
||||
'Initd graph' +
|
||||
(useColor ? pal.reset : '') +
|
||||
(filterInitd ? ' filter:' + filterInitd : '') +
|
||||
(initdRawFallback ? ' [raw JSON]' : '')
|
||||
(initdRawFallback ? ' [alternate layout]' : '')
|
||||
)
|
||||
emitHdrLn(
|
||||
(useColor ? pal.dim : '') +
|
||||
'x toggles raw JSON view when nodes list exists' +
|
||||
'x toggles alternate layout when a nodes list exists (edges / graph path)' +
|
||||
(useColor ? pal.reset : '')
|
||||
)
|
||||
const g = snap.initdGraph
|
||||
@@ -7733,6 +7990,7 @@ async function run(ctx, argv) {
|
||||
' BARE_TOP_PROC_COL_SEP=1 Unicode column separators in process table\n' +
|
||||
' BARE_TOP_MINIMAP=1 Scroll minimap on long lists\n' +
|
||||
' BARE_TOP_CMD_ELLIPSIS_MIDDLE Middle-ellipsis long process names\n' +
|
||||
' BARE_TOP_PROC_DETAIL_JSON 1 = pretty-print JSON in process detail (Enter)\n' +
|
||||
' BARE_TOP_NO_ALTSCREEN Non-empty skips alternate-screen mode\n' +
|
||||
' BARE_TOP_NO_2J_AFTER_FIRST Soft clear after first full paint\n' +
|
||||
' BARE_TOP_ASCII_GRAPH / BARE_TOP_ASCII_UI / BARE_TOP_MONO / BARE_TOP_BRAILLE_SPARK\n' +
|
||||
|
||||
Reference in New Issue
Block a user