themes
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
/* BARE_OS_BIN_API 1.0.0 — bump when staged /bin script semantics change (see developer guide). */
|
||||
/** Shared helpers for drive-resident /bin scripts (prepended before each command). */
|
||||
function bareStdin(ctx) {
|
||||
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
|
||||
}
|
||||
|
||||
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
|
||||
function bareFormatModeString(mode, type) {
|
||||
const typeChar = type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
|
||||
const perm = mode & 0o777
|
||||
const r = (bit) => (perm & bit ? 'r' : '-')
|
||||
const w = (bit) => (perm & bit ? 'w' : '-')
|
||||
const x = (bit) => (perm & bit ? 'x' : '-')
|
||||
return (
|
||||
typeChar +
|
||||
r(0o400) +
|
||||
w(0o200) +
|
||||
x(0o100) +
|
||||
r(0o040) +
|
||||
w(0o020) +
|
||||
x(0o010) +
|
||||
r(0o004) +
|
||||
w(0o002) +
|
||||
x(0o001)
|
||||
)
|
||||
}
|
||||
|
||||
/** @param {number} mtimeMs @param {number} [nowMs] */
|
||||
function bareFormatLsMtime(mtimeMs, nowMs) {
|
||||
const now = nowMs != null ? nowMs : Date.now()
|
||||
const d = new Date(mtimeMs)
|
||||
const months = [
|
||||
'Jan',
|
||||
'Feb',
|
||||
'Mar',
|
||||
'Apr',
|
||||
'May',
|
||||
'Jun',
|
||||
'Jul',
|
||||
'Aug',
|
||||
'Sep',
|
||||
'Oct',
|
||||
'Nov',
|
||||
'Dec'
|
||||
]
|
||||
const mon = months[d.getMonth()]
|
||||
const day = String(d.getDate()).padStart(2, ' ')
|
||||
const sixMo = 180 * 24 * 3600 * 1000
|
||||
if (Math.abs(now - mtimeMs) > sixMo) {
|
||||
const yr = String(d.getFullYear()).padStart(4, ' ')
|
||||
return mon + ' ' + day + ' ' + yr
|
||||
}
|
||||
const hh = String(d.getHours()).padStart(2, '0')
|
||||
const mm = String(d.getMinutes()).padStart(2, '0')
|
||||
return mon + ' ' + day + ' ' + hh + ':' + mm
|
||||
}
|
||||
|
||||
/** @param {number} size */
|
||||
function barePosixBlocks(size) {
|
||||
return Math.ceil(Number(size) / 512) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* GNU-style LS_COLORS string + dircolors(5) database parsing and file classification.
|
||||
* Consumed by bare-os-booter (ESM import). Prepended into /bin/ls and /bin/dircolors by bare-os-coreutils build (no import there).
|
||||
*/
|
||||
|
||||
/** Default LS_COLORS (subset aligned with GNU dircolors -p essentials + common globs). */
|
||||
function bareDefaultLsColorsString() {
|
||||
return [
|
||||
'no=00',
|
||||
'fi=00',
|
||||
'di=01;34',
|
||||
'ln=01;36',
|
||||
'pi=40;33',
|
||||
'so=01;35',
|
||||
'do=01;35',
|
||||
'bd=40;33;01',
|
||||
'cd=40;33;01',
|
||||
'or=40;31;01',
|
||||
'mi=00',
|
||||
'su=37;41',
|
||||
'sg=30;43',
|
||||
'ca=30;41',
|
||||
'tw=30;42',
|
||||
'ow=34;43',
|
||||
'st=37;44',
|
||||
'ex=01;32',
|
||||
'mh=00',
|
||||
'*.tar=01;31',
|
||||
'*.tgz=01;31',
|
||||
'*.arc=01;31',
|
||||
'*.arj=01;31',
|
||||
'*.taz=01;31',
|
||||
'*.lha=01;31',
|
||||
'*.lz4=01;31',
|
||||
'*.lzh=01;31',
|
||||
'*.tlz=01;31',
|
||||
'*.txz=01;31',
|
||||
'*.tzo=01;31',
|
||||
'*.tzst=01;31',
|
||||
'*.bz2=01;31',
|
||||
'*.bz=01;31',
|
||||
'*.tbz=01;31',
|
||||
'*.tbz2=01;31',
|
||||
'*.tz=01;31',
|
||||
'*.deb=01;31',
|
||||
'*.rpm=01;31',
|
||||
'*.jar=01;31',
|
||||
'*.war=01;31',
|
||||
'*.ear=01;31',
|
||||
'*.sar=01;31',
|
||||
'*.rar=01;31',
|
||||
'*.alz=01;31',
|
||||
'*.ace=01;31',
|
||||
'*.zoo=01;31',
|
||||
'*.cpio=01;31',
|
||||
'*.7z=01;31',
|
||||
'*.rz=01;31',
|
||||
'*.cab=01;31',
|
||||
'*.wim=01;31',
|
||||
'*.swm=01;31',
|
||||
'*.dwm=01;31',
|
||||
'*.esd=01;31',
|
||||
'*.jpg=01;35',
|
||||
'*.jpeg=01;35',
|
||||
'*.mjpg=01;35',
|
||||
'*.mjpeg=01;35',
|
||||
'*.gif=01;35',
|
||||
'*.bmp=01;35',
|
||||
'*.pbm=01;35',
|
||||
'*.pgm=01;35',
|
||||
'*.ppm=01;35',
|
||||
'*.tga=01;35',
|
||||
'*.xbm=01;35',
|
||||
'*.xpm=01;35',
|
||||
'*.tif=01;35',
|
||||
'*.tiff=01;35',
|
||||
'*.png=01;35',
|
||||
'*.svg=01;35',
|
||||
'*.svgz=01;35',
|
||||
'*.mng=01;35',
|
||||
'*.pcx=01;35',
|
||||
'*.mov=01;35',
|
||||
'*.mpg=01;35',
|
||||
'*.mpeg=01;35',
|
||||
'*.m2v=01;35',
|
||||
'*.mkv=01;35',
|
||||
'*.webm=01;35',
|
||||
'*.ogm=01;35',
|
||||
'*.mp4=01;35',
|
||||
'*.m4v=01;35',
|
||||
'*.mp4v=01;35',
|
||||
'*.vob=01;35',
|
||||
'*.qt=01;35',
|
||||
'*.nuv=01;35',
|
||||
'*.wmv=01;35',
|
||||
'*.asf=01;35',
|
||||
'*.rm=01;35',
|
||||
'*.rmvb=01;35',
|
||||
'*.flc=01;35',
|
||||
'*.avi=01;35',
|
||||
'*.fli=01;35',
|
||||
'*.flv=01;35',
|
||||
'*.gl=01;35',
|
||||
'*.dl=01;35',
|
||||
'*.xcf=01;35',
|
||||
'*.xwd=01;35',
|
||||
'*.yuv=01;35',
|
||||
'*.cgm=01;35',
|
||||
'*.emf=01;35',
|
||||
'*.ogv=01;35',
|
||||
'*.ogx=01;35',
|
||||
'*.aac=00;36',
|
||||
'*.au=00;36',
|
||||
'*.flac=00;36',
|
||||
'*.m4a=00;36',
|
||||
'*.mid=00;36',
|
||||
'*.midi=00;36',
|
||||
'*.mka=00;36',
|
||||
'*.mp3=00;36',
|
||||
'*.mpc=00;36',
|
||||
'*.ogg=00;36',
|
||||
'*.ra=00;36',
|
||||
'*.wav=00;36',
|
||||
'*.oga=00;36',
|
||||
'*.opus=00;36',
|
||||
'*.spx=00;36',
|
||||
'*.xspf=00;36',
|
||||
'*.pdf=00;32',
|
||||
'*.ps=00;32',
|
||||
'*.txt=00;32',
|
||||
'*.patch=00;32',
|
||||
'*.diff=00;32',
|
||||
'*.log=00;32',
|
||||
'*.tex=00;32',
|
||||
'*.doc=00;32',
|
||||
'*.docx=00;32',
|
||||
'*.rtf=00;32',
|
||||
'*.odt=00;32',
|
||||
'*.md=00;32',
|
||||
'*.markdown=00;32',
|
||||
'*.css=00;32',
|
||||
'*.htm=00;32',
|
||||
'*.html=00;32',
|
||||
'*.xml=00;32',
|
||||
'*.json=00;32',
|
||||
'*.yaml=00;32',
|
||||
'*.yml=00;32',
|
||||
'*.c=00;32',
|
||||
'*.h=00;32',
|
||||
'*.js=00;32',
|
||||
'*.mjs=00;32',
|
||||
'*.java=00;32',
|
||||
'*.py=00;32',
|
||||
'*.go=00;32',
|
||||
'*.rs=00;32',
|
||||
'*.cpp=00;32',
|
||||
'*.cc=00;32',
|
||||
'*.cxx=00;32',
|
||||
'*.hpp=00;32',
|
||||
'*.shlib=01;32',
|
||||
'*.so=01;32',
|
||||
'*.dylib=01;32',
|
||||
'*.dll=01;32',
|
||||
'*.a=01;32',
|
||||
'*.lib=01;32',
|
||||
'*.ko=01;32',
|
||||
'*.sh=01;32',
|
||||
'*.bash=01;32',
|
||||
'*.zsh=01;32',
|
||||
'*.bat=01;32',
|
||||
'*.cmd=01;32',
|
||||
'*.exe=01;32',
|
||||
'*.com=01;32',
|
||||
'*.btm=01;32',
|
||||
'*.msi=01;32'
|
||||
].join(':')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {Record<string, string>}
|
||||
*/
|
||||
function bareParseLsColors(s) {
|
||||
const out = /** @type {Record<string, string>} */ ({})
|
||||
if (s == null || !String(s).trim()) return out
|
||||
for (const part of String(s).split(':')) {
|
||||
const p = part.trim()
|
||||
if (!p) continue
|
||||
const eq = p.indexOf('=')
|
||||
if (eq <= 0) continue
|
||||
const k = p.slice(0, eq)
|
||||
const v = p.slice(eq + 1)
|
||||
if (k) out[k] = v
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, string>} map
|
||||
*/
|
||||
function bareSerializeLsColors(map) {
|
||||
const keys = Object.keys(map).sort()
|
||||
return keys.map((k) => k + '=' + map[k]).join(':')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} code dircolors value (e.g. 01;34)
|
||||
* @returns {string} opening SGR including ESC
|
||||
*/
|
||||
function bareLscolorsToOpenSgr(code) {
|
||||
if (code == null || code === '' || code === '0' || code === '00') return ''
|
||||
return '\x1b[' + code + 'm'
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse dircolors database (GNU subset): # comments, blank lines, TERM blocks, KEY VALUE pairs.
|
||||
* @param {string} text
|
||||
* @param {string} termEnv value of TERM
|
||||
* @returns {Record<string, string>}
|
||||
*/
|
||||
function bareParseDircolorsDatabase(text, termEnv) {
|
||||
const term = termEnv != null ? String(termEnv) : ''
|
||||
/** @type {Record<string, string>} */
|
||||
const out = {}
|
||||
let blockActive = true
|
||||
const lines = String(text).split(/\r?\n/)
|
||||
for (let raw of lines) {
|
||||
const line = raw.replace(/#.*$/, '').trim()
|
||||
if (!line) continue
|
||||
const upper = line.toUpperCase()
|
||||
if (upper.startsWith('TERM ')) {
|
||||
const rest = line.slice(5).trim()
|
||||
if (rest === 'none') blockActive = false
|
||||
else
|
||||
blockActive =
|
||||
rest === '*' || rest === '' || rest === term || term.indexOf(rest) === 0
|
||||
continue
|
||||
}
|
||||
if (upper.startsWith('COLOR ') || upper.startsWith('OPTIONS ')) continue
|
||||
if (!blockActive) continue
|
||||
const ws = line.search(/\s/)
|
||||
if (ws <= 0) continue
|
||||
const key = line.slice(0, ws).trim()
|
||||
const val = line.slice(ws + 1).trim()
|
||||
if (!key || !val) continue
|
||||
if (key === 'TERM' || key === 'COLOR' || key === 'OPTIONS') continue
|
||||
out[key] = val
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filename basename only
|
||||
* @param {Record<string, string>} map
|
||||
*/
|
||||
function bareLsColorsGlobMatch(filename, map) {
|
||||
const keys = Object.keys(map).filter((k) => k.startsWith('*.'))
|
||||
keys.sort((a, b) => b.length - a.length)
|
||||
const lower = filename.toLowerCase()
|
||||
for (const k of keys) {
|
||||
const suf = k.slice(1).toLowerCase()
|
||||
if (lower.endsWith(suf)) return map[k]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ type?: string, mode?: number, linkname?: string, targetMissing?: boolean, nlink?: number, capabilities?: boolean } | null} st
|
||||
* @param {string} filename basename
|
||||
* @param {Record<string, string>} map from LS_COLORS
|
||||
* @returns {string} SGR open sequence or ''
|
||||
*/
|
||||
function bareLsColorOpenSgrFromMap(st, filename, map) {
|
||||
if (!st) {
|
||||
const no = map.no
|
||||
return no ? bareLscolorsToOpenSgr(no) : ''
|
||||
}
|
||||
const mode = Number(st.mode) || 0
|
||||
const perm = mode & 0o777
|
||||
const t = st.type
|
||||
let key = 'fi'
|
||||
|
||||
if (t === 'symlink') {
|
||||
key = st.targetMissing ? 'or' : 'ln'
|
||||
} else if (t === 'directory') {
|
||||
const ow = (perm & 0o002) !== 0
|
||||
const sticky = (mode & 0o1000) !== 0
|
||||
if (ow && sticky) key = 'tw'
|
||||
else if (ow) key = 'ow'
|
||||
else if (sticky) key = 'st'
|
||||
else key = 'di'
|
||||
} else if (t === 'file') {
|
||||
if (st.capabilities) key = 'ca'
|
||||
else if (mode & 0o4000) key = 'su'
|
||||
else if (mode & 0o2000) key = 'sg'
|
||||
else if (perm & 0o111) key = 'ex'
|
||||
else {
|
||||
const nlink = Number(st.nlink)
|
||||
if (nlink > 1 && map.mh != null && String(map.mh).trim() !== '') {
|
||||
const mhOpen = bareLscolorsToOpenSgr(map.mh)
|
||||
if (mhOpen) return mhOpen
|
||||
}
|
||||
const g = bareLsColorsGlobMatch(filename, map)
|
||||
if (g != null) return bareLscolorsToOpenSgr(g)
|
||||
key = 'fi'
|
||||
}
|
||||
}
|
||||
|
||||
const code = map[key] != null ? map[key] : map.fi
|
||||
return code ? bareLscolorsToOpenSgr(code) : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} multiline dircolors database (default colors)
|
||||
*/
|
||||
function bareDefaultDircolorsDatabase() {
|
||||
const pairs = bareParseLsColors(bareDefaultLsColorsString())
|
||||
const lines = ['# Bare OS default dircolors (GNU-like)', 'TERM *', '']
|
||||
for (const k of Object.keys(pairs).sort()) {
|
||||
lines.push(k + ' ' + pairs[k])
|
||||
}
|
||||
return lines.join('\n') + '\n'
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const env = ctx.env || {}
|
||||
let bourne = false
|
||||
let printDefault = false
|
||||
/** @type {string | null} */
|
||||
let file = null
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '--') continue
|
||||
if (a === '-b' || a === '--sh' || a === '--bourne-shell') bourne = true
|
||||
else if (a === '-p' || a === '--print-database') printDefault = true
|
||||
else if (a.startsWith('-')) {
|
||||
ctx.console.error('dircolors: unrecognized option: ' + a)
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
} else file = a
|
||||
}
|
||||
if (printDefault) {
|
||||
ctx.console.log(bareDefaultDircolorsDatabase())
|
||||
return
|
||||
}
|
||||
let text = bareDefaultDircolorsDatabase()
|
||||
if (file) {
|
||||
const buf = await ctx.vfs.readFile(file)
|
||||
if (!buf) {
|
||||
ctx.console.error('dircolors: cannot read ' + file)
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
}
|
||||
text = ctx.b4a.toString(buf)
|
||||
}
|
||||
const term = env.TERM || ''
|
||||
const db = bareParseDircolorsDatabase(text, term)
|
||||
const ls = bareSerializeLsColors(db)
|
||||
if (bourne) {
|
||||
const q = "'" + ls.replace(/'/g, "'\\''") + "'"
|
||||
ctx.console.log('LS_COLORS=' + q)
|
||||
ctx.console.log('export LS_COLORS')
|
||||
} else {
|
||||
ctx.console.log(ls)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user