/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { PASTED_TEXT_PLACEHOLDER_REGEX, } from '../components/shared/text-buffer.js';
import { LRUCache } from 'mnemonist';
import { cpLen, cpSlice } from './textUtils.js';
import { LRU_BUFFER_PERF_CACHE_LIMIT } from '../constants.js';
import { AT_COMMAND_PATH_REGEX_SOURCE } from '../hooks/atCommandProcessor.js';
// Matches slash commands (e.g., /help), @ references (files or MCP resource URIs),
// and large paste placeholders (e.g., [Pasted Text: 6 lines]).
//
// The @ pattern uses the same source as the command processor to ensure consistency.
// It matches any character except strict delimiters (ASCII whitespace, comma, etc.).
// This supports URIs like `@file:///example.txt` and filenames with Unicode spaces (like NNBSP).
const HIGHLIGHT_REGEX = new RegExp(`(^/[a-zA-Z0-9_-]+|@${AT_COMMAND_PATH_REGEX_SOURCE}|${PASTED_TEXT_PLACEHOLDER_REGEX.source})`, 'g');
const highlightCache = new LRUCache(LRU_BUFFER_PERF_CACHE_LIMIT);
export function parseInputForHighlighting(text, index, transformations = [], cursorCol) {
    let isCursorInsideTransform = false;
    if (cursorCol !== undefined) {
        for (const transform of transformations) {
            if (cursorCol >= transform.logStart && cursorCol <= transform.logEnd) {
                isCursorInsideTransform = true;
                break;
            }
        }
    }
    const cacheKey = `${index === 0 ? 'F' : 'N'}:${isCursorInsideTransform ? cursorCol : 'NC'}:${text}`;
    const cached = highlightCache.get(cacheKey);
    if (cached !== undefined)
        return cached;
    HIGHLIGHT_REGEX.lastIndex = 0;
    if (!text) {
        return [{ text: '', type: 'default' }];
    }
    const parseUntransformedInput = (text) => {
        const tokens = [];
        if (!text)
            return tokens;
        HIGHLIGHT_REGEX.lastIndex = 0;
        let last = 0;
        let match;
        while ((match = HIGHLIGHT_REGEX.exec(text)) !== null) {
            const [fullMatch] = match;
            const matchIndex = match.index;
            if (matchIndex > last) {
                tokens.push({ text: text.slice(last, matchIndex), type: 'default' });
            }
            const type = fullMatch.startsWith('/')
                ? 'command'
                : fullMatch.startsWith('@')
                    ? 'file'
                    : 'paste';
            if (type === 'command' && index !== 0) {
                tokens.push({ text: fullMatch, type: 'default' });
            }
            else {
                tokens.push({ text: fullMatch, type });
            }
            last = matchIndex + fullMatch.length;
        }
        if (last < text.length) {
            tokens.push({ text: text.slice(last), type: 'default' });
        }
        return tokens;
    };
    const tokens = [];
    let column = 0;
    const sortedTransformations = (transformations ?? [])
        .slice()
        .sort((a, b) => a.logStart - b.logStart);
    for (const transformation of sortedTransformations) {
        const textBeforeTransformation = cpSlice(text, column, transformation.logStart);
        tokens.push(...parseUntransformedInput(textBeforeTransformation));
        const isCursorInside = cursorCol !== undefined &&
            cursorCol >= transformation.logStart &&
            cursorCol <= transformation.logEnd;
        const transformationText = isCursorInside
            ? transformation.logicalText
            : transformation.collapsedText;
        tokens.push({ text: transformationText, type: 'file' });
        column = transformation.logEnd;
    }
    const textAfterFinalTransformation = cpSlice(text, column);
    tokens.push(...parseUntransformedInput(textAfterFinalTransformation));
    highlightCache.set(cacheKey, tokens);
    return tokens;
}
export function parseSegmentsFromTokens(tokens, sliceStart, sliceEnd) {
    if (sliceStart >= sliceEnd)
        return [];
    const segments = [];
    let tokenCpStart = 0;
    for (const token of tokens) {
        const tokenLen = cpLen(token.text);
        const tokenStart = tokenCpStart;
        const tokenEnd = tokenStart + tokenLen;
        const overlapStart = Math.max(tokenStart, sliceStart);
        const overlapEnd = Math.min(tokenEnd, sliceEnd);
        if (overlapStart < overlapEnd) {
            const sliceStartInToken = overlapStart - tokenStart;
            const sliceEndInToken = overlapEnd - tokenStart;
            const rawSlice = cpSlice(token.text, sliceStartInToken, sliceEndInToken);
            const last = segments[segments.length - 1];
            if (last && last.type === token.type) {
                last.text += rawSlice;
            }
            else {
                segments.push({ type: token.type, text: rawSlice });
            }
        }
        tokenCpStart += tokenLen;
    }
    return segments;
}
//# sourceMappingURL=highlight.js.map