// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.
// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).
/**
 * When a hashline payload is authored against `read`/`search` output, each
 * line is prefixed with either a hashline-mode line number (`123:`) or, for
 * diff-style echoes, a leading `+`. These helpers detect that and recover
 * the raw text. Two strip modes are exposed:
 *
 * - {@link stripNewLinePrefixes} — opportunistic: strips when the input
 *   clearly carries hashline or diff prefixes, leaves it alone otherwise.
 * - {@link stripHashlinePrefixes} — strict: only strips when every non-empty
 *   content line is hashline-prefixed.
 *
 * These run *before* the tokenizer; they exist because hashline mode is the
 * common case for echoed file content, and erroneously echoed prefixes will
 * otherwise turn every content line into a (malformed) op.
 */
import { HL_FILE_HASH_LENGTH } from "./format.js";
const HL_PREFIX_RE = /^\s*(?:>>>|>>)?\s*(?:[+*-]\s*)?\d+:/;
const HL_PREFIX_PLUS_RE = /^\s*(?:>>>|>>)?\s*\+\s*\d+:/;
const HL_HEADER_RE = new RegExp(`^\\s*\\[[^#\\r\\n]+#[0-9a-fA-F]{${HL_FILE_HASH_LENGTH}}\\]\\s*$`);
const DIFF_PLUS_RE = /^[+](?![+])/;
const READ_TRUNCATION_NOTICE_RE = /^\[(?:Showing lines \d+-\d+ of \d+|\d+ more lines? in (?:file|\S+))\b.*\bUse :L?\d+/;
function stripLeadingHashlinePrefixes(line) {
    let result = line;
    let previous;
    do {
        previous = result;
        result = result.replace(HL_PREFIX_RE, "");
    } while (result !== previous);
    return result;
}
/**
 * Single-pass variant of {@link stripLeadingHashlinePrefixes} that strips at
 * most one leading hashline prefix (`N:`, `>>>N:`, `+N:` etc.) and does NOT
 * loop. Use this when the input carries at most one snapshot prefix (e.g. a
 * bare body row paste from `read` output) — recursive stripping would corrupt
 * content whose own text starts with `digits:`.
 */
export function stripOneLeadingHashlinePrefix(line) {
    return line.replace(HL_PREFIX_RE, "");
}
function collectLinePrefixStats(lines) {
    const stats = {
        nonEmpty: 0,
        headerCount: 0,
        hashPrefixCount: 0,
        diffPlusHashPrefixCount: 0,
        diffPlusCount: 0,
        truncationNoticeCount: 0,
    };
    for (const line of lines) {
        if (line.length === 0)
            continue;
        if (READ_TRUNCATION_NOTICE_RE.test(line)) {
            stats.truncationNoticeCount++;
            continue;
        }
        if (HL_HEADER_RE.test(line)) {
            stats.nonEmpty++;
            stats.headerCount++;
            continue;
        }
        stats.nonEmpty++;
        if (HL_PREFIX_RE.test(line))
            stats.hashPrefixCount++;
        if (HL_PREFIX_PLUS_RE.test(line))
            stats.diffPlusHashPrefixCount++;
        if (DIFF_PLUS_RE.test(line))
            stats.diffPlusCount++;
    }
    return stats;
}
/**
 * Strip whichever prefix scheme the lines appear to be carrying:
 * - hashline line-number prefixes (`123:`) when every content line has one
 * - leading `+` (diff style) when at least half the lines have one
 * - mixed `+<n>:` form when present
 *
 * Returns the lines untouched if no scheme is recognized.
 */
export function stripNewLinePrefixes(lines) {
    const stats = collectLinePrefixStats(lines);
    if (stats.nonEmpty === 0)
        return lines;
    const contentLineCount = stats.nonEmpty - stats.headerCount;
    const stripHash = contentLineCount > 0 && stats.hashPrefixCount === contentLineCount;
    const stripPlus = !stripHash &&
        stats.diffPlusHashPrefixCount === 0 &&
        stats.diffPlusCount > 0 &&
        stats.diffPlusCount >= stats.nonEmpty * 0.5;
    if (!stripHash && !stripPlus && stats.diffPlusHashPrefixCount === 0)
        return lines;
    return lines
        .filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !(stripHash && HL_HEADER_RE.test(line)))
        .map(line => {
        if (stripHash)
            return stripLeadingHashlinePrefixes(line);
        if (stripPlus)
            return line.replace(DIFF_PLUS_RE, "");
        if (stats.diffPlusHashPrefixCount > 0 && HL_PREFIX_PLUS_RE.test(line)) {
            return line.replace(HL_PREFIX_RE, "");
        }
        return line;
    });
}
/**
 * Strict variant: strip hashline prefixes only when every content line is
 * hashline-prefixed. Returns the lines unchanged otherwise.
 */
export function stripHashlinePrefixes(lines) {
    const stats = collectLinePrefixStats(lines);
    if (stats.nonEmpty === 0)
        return lines;
    const contentLineCount = stats.nonEmpty - stats.headerCount;
    if (contentLineCount === 0 || stats.hashPrefixCount !== contentLineCount)
        return lines;
    return lines
        .filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !HL_HEADER_RE.test(line))
        .map(line => stripLeadingHashlinePrefixes(line));
}
/**
 * Normalize line payloads by stripping read/search line prefixes. `null` /
 * `undefined` yield `[]`; a single multiline string is split on `\n`.
 */
export function hashlineParseText(edit) {
    if (edit == null)
        return [];
    if (typeof edit === "string") {
        const trimmed = edit.endsWith("\n") ? edit.slice(0, -1) : edit;
        edit = trimmed.replaceAll("\r", "").split("\n");
    }
    return stripNewLinePrefixes(edit);
}
//# sourceMappingURL=prefixes.js.map