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:
Raven Scott
2026-04-21 19:01:42 -04:00
parent ef0301f435
commit 1d1e5c487e
13 changed files with 1341 additions and 51 deletions
+267 -9
View File
@@ -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
View File
@@ -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' +