/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
import * as lsp from 'vscode-languageserver-protocol';
import { rangeContains } from '../types/range.js';
const inlineCodePattern = /(?<!`)(`+)((?:.+?|.*?(?:(?:\r?\n).+?)*?)(?:\r?\n)?\1)(?!`)/gm;
class InlineRanges {
    static create() {
        return new InlineRanges();
    }
    #map;
    constructor(data) {
        this.#map = new Map(data);
    }
    get(line) {
        return this.#map.get(line) || [];
    }
    add(range) {
        // Register the range for all lines that it covers
        for (let line = range.start.line; line <= range.end.line; line++) {
            let ranges = this.#map.get(line);
            if (!ranges) {
                ranges = [];
                this.#map.set(line, ranges);
            }
            ranges.push(range);
        }
    }
    concat(newRanges) {
        const result = new InlineRanges(this.#map);
        for (const range of newRanges) {
            result.add(range);
        }
        return result;
    }
}
export class NoLinkRanges {
    multiline;
    inline;
    static compute(tokens, document) {
        const multiline = tokens
            .filter(t => (t.type === 'code_block' || t.type === 'fence' || t.type === 'html_block') && !!t.map)
            .map(t => ({ type: t.type, range: t.map }));
        const inlineRanges = InlineRanges.create();
        const text = document.getText();
        for (const match of text.matchAll(inlineCodePattern)) {
            const startOffset = match.index ?? 0;
            const startPosition = document.positionAt(startOffset);
            inlineRanges.add(lsp.Range.create(startPosition, document.positionAt(startOffset + match[0].length)));
        }
        return new NoLinkRanges(multiline, inlineRanges);
    }
    constructor(
    /**
     * Block element ranges, such as code blocks. Represented by [line_start, line_end).
     */
    multiline, 
    /**
     * Inline code spans where links should not be detected
     */
    inline) {
        this.multiline = multiline;
        this.inline = inline;
    }
    contains(position, excludeType = '') {
        return this.multiline.some(({ type, range }) => type !== excludeType && position.line >= range[0] && position.line < range[1]) ||
            !!this.inline.get(position.line)?.some(inlineRange => rangeContains(inlineRange, position));
    }
    concatInline(inlineRanges) {
        return new NoLinkRanges(this.multiline, this.inline.concat(inlineRanges));
    }
}
//# sourceMappingURL=noLinkRanges.js.map