Updates
This commit is contained in:
@@ -514,12 +514,13 @@ function bareSedMatchAddr(
|
||||
/**
|
||||
* @param {string[]} lines
|
||||
* @param {string[]} scripts
|
||||
* @param {{ silent?: boolean, extended?: boolean, readFile?: (p: string) => string | null, writeFile?: (p: string, chunk: string) => void, lastLineHint?: number }} opts
|
||||
* @param {{ silent?: boolean, extended?: boolean, nullData?: boolean, readFile?: (p: string) => string | null, writeFile?: (p: string, chunk: string) => void, lastLineHint?: number }} opts
|
||||
* @returns {string}
|
||||
*/
|
||||
function bareSedRun(lines, scripts, opts) {
|
||||
const silent = !!opts.silent
|
||||
const extended = !!opts.extended
|
||||
const eol = opts.nullData ? '\0' : '\n'
|
||||
const readF = opts.readFile || (() => null)
|
||||
const writeF = opts.writeFile || (() => {})
|
||||
const fullScript = scripts.join('\n')
|
||||
@@ -608,7 +609,7 @@ function bareSedRun(lines, scripts, opts) {
|
||||
}
|
||||
if (count) {
|
||||
ps = res + str.slice(pos)
|
||||
if (fl.p) emit(ps + '\n')
|
||||
if (fl.p) emit(ps + eol)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -637,15 +638,15 @@ function bareSedRun(lines, scripts, opts) {
|
||||
break
|
||||
}
|
||||
case 'print':
|
||||
emit(ps + '\n')
|
||||
emit(ps + eol)
|
||||
break
|
||||
case 'printFirst': {
|
||||
const nl = ps.indexOf('\n')
|
||||
emit((nl === -1 ? ps : ps.slice(0, nl)) + '\n')
|
||||
emit((nl === -1 ? ps : ps.slice(0, nl)) + eol)
|
||||
break
|
||||
}
|
||||
case 'nextLine':
|
||||
if (autoPrint && !silent) emit(ps + '\n')
|
||||
if (autoPrint && !silent) emit(ps + eol)
|
||||
lineIdx++
|
||||
nextRead = true
|
||||
ci = cmds.length
|
||||
@@ -674,25 +675,25 @@ function bareSedRun(lines, scripts, opts) {
|
||||
break
|
||||
}
|
||||
case 'quit':
|
||||
if (autoPrint && !silent) emit(ps + '\n')
|
||||
if (autoPrint && !silent) emit(ps + eol)
|
||||
quit = /** @type {number} */ (cmd.quitCode) || 0
|
||||
break
|
||||
case 'list':
|
||||
emit(bareSedListLine(ps) + '\n')
|
||||
emit(bareSedListLine(ps) + eol)
|
||||
break
|
||||
case 'lineNum':
|
||||
emit(String(lineNo) + '\n')
|
||||
emit(String(lineNo) + eol)
|
||||
break
|
||||
case 'readFile': {
|
||||
const text = readF(/** @type {string} */ (cmd.path))
|
||||
if (text) emit(text.endsWith('\n') ? text : text + '\n')
|
||||
if (text) emit(text.endsWith(eol) ? text : text + eol)
|
||||
break
|
||||
}
|
||||
case 'writeFile':
|
||||
writeF(/** @type {string} */ (cmd.path), ps + '\n')
|
||||
break
|
||||
case 'append':
|
||||
emit(/** @type {string} */ (cmd.text) + '\n')
|
||||
emit(/** @type {string} */ (cmd.text) + eol)
|
||||
break
|
||||
case 'insert':
|
||||
/* handled as emit before line — approximated by prepending to output before autoPrint */
|
||||
@@ -700,7 +701,7 @@ function bareSedRun(lines, scripts, opts) {
|
||||
break
|
||||
case 'change':
|
||||
autoPrint = false
|
||||
emit(/** @type {string} */ (cmd.text) + '\n')
|
||||
emit(/** @type {string} */ (cmd.text) + eol)
|
||||
delLine = true
|
||||
break
|
||||
case 'b': {
|
||||
@@ -726,7 +727,7 @@ function bareSedRun(lines, scripts, opts) {
|
||||
|
||||
if (quit) break
|
||||
if (nextRead) continue
|
||||
if (!delLine && autoPrint) emit(ps + '\n')
|
||||
if (!delLine && autoPrint) emit(ps + eol)
|
||||
lineIdx++
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,12 @@ async function run(ctx, argv) {
|
||||
/** @type {'never' | 'always' | 'auto'} */
|
||||
let colorMode = 'never'
|
||||
let recursive = false
|
||||
/** @type {string[]} */
|
||||
const includeGlobs = []
|
||||
/** @type {string[]} */
|
||||
const excludeGlobs = []
|
||||
/** @type {string[]} */
|
||||
const excludeDirGlobs = []
|
||||
|
||||
const args = argv.slice(1)
|
||||
let i = 0
|
||||
@@ -93,6 +99,36 @@ async function run(ctx, argv) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a === '--include' && args[i + 1]) {
|
||||
includeGlobs.push(args[++i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('--include=')) {
|
||||
includeGlobs.push(a.slice('--include='.length))
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a === '--exclude' && args[i + 1]) {
|
||||
excludeGlobs.push(args[++i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('--exclude=')) {
|
||||
excludeGlobs.push(a.slice('--exclude='.length))
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a === '--exclude-dir' && args[i + 1]) {
|
||||
excludeDirGlobs.push(args[++i])
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('--exclude-dir=')) {
|
||||
excludeDirGlobs.push(a.slice('--exclude-dir='.length))
|
||||
i++
|
||||
continue
|
||||
}
|
||||
ctx.console.error('grep: unknown option ' + a)
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
@@ -304,7 +340,15 @@ async function run(ctx, argv) {
|
||||
continue
|
||||
}
|
||||
if (st.type === 'directory') {
|
||||
await grepWalkFiles(ctx, p, acc, suppressErrors)
|
||||
await grepWalkFiles(ctx, p, acc, suppressErrors, {
|
||||
includeGlobs,
|
||||
excludeGlobs,
|
||||
excludeDirGlobs,
|
||||
filterCap: Number.parseInt(
|
||||
String(ctx.vfs?.env?.BARE_OS_GREP_FILTER_MAX || '32'),
|
||||
10
|
||||
) || 32
|
||||
})
|
||||
} else {
|
||||
acc.push(p)
|
||||
}
|
||||
@@ -500,8 +544,31 @@ const GREP_RECURSE_MAX_DEPTH = 64
|
||||
* @param {string[]} acc
|
||||
* @param {boolean} suppressErrors
|
||||
*/
|
||||
async function grepWalkFiles(ctx, dir, acc, suppressErrors) {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} pat
|
||||
*/
|
||||
function grepSimpleGlobMatch(name, pat) {
|
||||
if (!pat || pat === '*') return true
|
||||
if (pat.includes('/')) return name === pat
|
||||
if (pat.startsWith('*') && pat.length > 1 && pat.endsWith('*')) {
|
||||
const mid = pat.slice(1, -1)
|
||||
return mid !== '' && name.includes(mid)
|
||||
}
|
||||
if (pat.startsWith('*')) return name.endsWith(pat.slice(1))
|
||||
if (pat.endsWith('*')) return name.startsWith(pat.slice(0, -1))
|
||||
return name === pat
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ includeGlobs?: string[], excludeGlobs?: string[], excludeDirGlobs?: string[], filterCap?: number }} [opts]
|
||||
*/
|
||||
async function grepWalkFiles(ctx, dir, acc, suppressErrors, opts = {}) {
|
||||
const vfs = ctx.vfs
|
||||
const cap = opts.filterCap && opts.filterCap > 0 ? opts.filterCap : 32
|
||||
const inc = (opts.includeGlobs || []).slice(0, cap)
|
||||
const exc = (opts.excludeGlobs || []).slice(0, cap)
|
||||
const excd = (opts.excludeDirGlobs || []).slice(0, cap)
|
||||
/** @param {string} d @param {number} depth */
|
||||
const walk = async (d, depth) => {
|
||||
if (depth > GREP_RECURSE_MAX_DEPTH) return
|
||||
@@ -523,12 +590,21 @@ async function grepWalkFiles(ctx, dir, acc, suppressErrors) {
|
||||
continue
|
||||
}
|
||||
if (!st) continue
|
||||
if (st.type === 'directory') await walk(sub, depth + 1)
|
||||
else if (st.type === 'file') acc.push(sub)
|
||||
else if (st.type === 'symlink') {
|
||||
if (st.type === 'directory') {
|
||||
if (excd.some((p) => grepSimpleGlobMatch(n, p))) continue
|
||||
await walk(sub, depth + 1)
|
||||
} else if (st.type === 'file') {
|
||||
if (inc.length && !inc.some((p) => grepSimpleGlobMatch(n, p))) continue
|
||||
if (exc.some((p) => grepSimpleGlobMatch(n, p))) continue
|
||||
acc.push(sub)
|
||||
} else if (st.type === 'symlink') {
|
||||
try {
|
||||
const ft = await vfs.stat(sub)
|
||||
if (ft && ft.type === 'file') acc.push(sub)
|
||||
if (ft && ft.type === 'file') {
|
||||
if (inc.length && !inc.some((p) => grepSimpleGlobMatch(n, p))) continue
|
||||
if (exc.some((p) => grepSimpleGlobMatch(n, p))) continue
|
||||
acc.push(sub)
|
||||
}
|
||||
} catch {
|
||||
/* skip */
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
async function run(ctx, argv) {
|
||||
let silent = false
|
||||
let extended = false
|
||||
let nullData = false
|
||||
/** @type {string[]} */
|
||||
const scripts = []
|
||||
/** @type {string[]} */
|
||||
@@ -11,6 +12,10 @@ async function run(ctx, argv) {
|
||||
silent = true
|
||||
continue
|
||||
}
|
||||
if (a === '-z' || a === '--null-data') {
|
||||
nullData = true
|
||||
continue
|
||||
}
|
||||
if (a === '-E' || a === '-r') {
|
||||
extended = true
|
||||
continue
|
||||
@@ -89,6 +94,12 @@ async function run(ctx, argv) {
|
||||
readCache[rp] = buf ? ctx.b4a.toString(buf) : ''
|
||||
}
|
||||
|
||||
const maxNull =
|
||||
Number.parseInt(
|
||||
String(ctx.vfs?.env?.BARE_OS_SED_NULL_MAX_RECORDS || '100000'),
|
||||
10
|
||||
) || 100000
|
||||
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
async function pushFile(path) {
|
||||
@@ -99,16 +110,22 @@ async function run(ctx, argv) {
|
||||
return false
|
||||
}
|
||||
const t = ctx.b4a.toString(buf)
|
||||
const ls = t.split(/\r?\n/)
|
||||
if (ls.length && ls[ls.length - 1] === '') ls.pop()
|
||||
lines.push(...ls)
|
||||
if (nullData) {
|
||||
const rec = t.split('\0')
|
||||
const room = maxNull - lines.length
|
||||
lines.push(...rec.slice(0, Math.max(0, room)))
|
||||
} else {
|
||||
const ls = t.split(/\r?\n/)
|
||||
if (ls.length && ls[ls.length - 1] === '') ls.pop()
|
||||
lines.push(...ls)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (!files.length) {
|
||||
const s = bareStdin(ctx)
|
||||
const ls = s.split(/\r?\n/)
|
||||
if (ls.length && ls[ls.length - 1] === '') ls.pop()
|
||||
const ls = nullData ? s.split('\0').slice(0, maxNull) : s.split(/\r?\n/)
|
||||
if (!nullData && ls.length && ls[ls.length - 1] === '') ls.pop()
|
||||
lines.push(...ls)
|
||||
} else {
|
||||
for (const f of files) {
|
||||
@@ -121,6 +138,7 @@ async function run(ctx, argv) {
|
||||
const out = bareSedRun(lines, scripts, {
|
||||
silent,
|
||||
extended,
|
||||
nullData,
|
||||
readFile: (p) => readCache[p] ?? null,
|
||||
writeFile: (p, chunk) => {
|
||||
wAccum[p] = (wAccum[p] || '') + chunk
|
||||
@@ -141,6 +159,7 @@ async function run(ctx, argv) {
|
||||
}
|
||||
}
|
||||
|
||||
const t = out.replace(/\n$/, '')
|
||||
const trail = nullData ? /\0$/ : /\n$/
|
||||
const t = out.replace(trail, '')
|
||||
ctx.console.log(t)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user