{
const ext = extname(path).slice(1)
const file = Bun.file(path)
switch (ext) {
case "jpeg": case "jpg": case "png": case "gif": case "webp":
const img = await file.arrayBuffer()
return { html: `
` }
case "mp3": case "wav":
case "mp4": case "mov": case "avi": case "mkv": case "webm":
return "Not implemented"
case "js": case "ts": case "tsx": case "json":
return {
html: `${highlight(convertIndent(await file.text()))}
`
}
default:
if (await isBinaryContent(file))
throw "Cannot display binary file"
return {
html: `${escapeHTML(await file.text())}
`
}
}
}
// cut down 4space and 2space indents into 1space, for readability on a small screen
function convertIndent(str: string) {
const lines = str.split("\n")
// find the smallest non-zero indent
const minIndent = Math.min(
...lines
.map(l => (l.match(/^ +/) || [""])[0].length)
.filter(len => len > 0)
)
return lines
.map(line =>
line.replace(/^( +)/, (_, spaces) => " ".repeat(spaces.length / minIndent))
)
.join("\n")
}
async function isBinaryContent(file: Bun.FileBlob): Promise {
// Create a stream to read just the beginning
const stream = file.stream()
const reader = stream.getReader()
try {
// Read first chunk (typically 16KB, which is more than enough to detect binary)
const { value } = await reader.read()
if (!value) return false
// Check first 512 bytes or less
const bytes = new Uint8Array(value)
const checkLength = Math.min(bytes.length, 512)
for (let i = 0; i < checkLength; i++) {
const byte = bytes[i]!
if (byte === 0) return true // null byte
if (byte < 32 && ![9, 10, 13].includes(byte)) return true // control char
}
return false
} finally {
reader.releaseLock()
stream.cancel()
}
}