"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MdDocumentHighlightProvider = void 0;
const lsp = require("vscode-languageserver-types");
const position_1 = require("../types/position");
const range_1 = require("../types/range");
const workspace_1 = require("../workspace");
const documentLinks_1 = require("./documentLinks");
const rename_1 = require("./rename");
class MdDocumentHighlightProvider {
    #configuration;
    #tocProvider;
    #linkProvider;
    constructor(configuration, tocProvider, linkProvider) {
        this.#configuration = configuration;
        this.#tocProvider = tocProvider;
        this.#linkProvider = linkProvider;
    }
    async getDocumentHighlights(document, position, token) {
        const toc = await this.#tocProvider.getForDocument(document);
        if (token.isCancellationRequested) {
            return [];
        }
        const { links } = await this.#linkProvider.getLinks(document);
        if (token.isCancellationRequested) {
            return [];
        }
        const header = toc.entries.find(entry => entry.line === position.line);
        if (header) {
            return [...this.#getHighlightsForHeader(document, header, links, toc)];
        }
        return [...this.#getHighlightsForLinkAtPosition(document, position, links, toc)];
    }
    *#getHighlightsForHeader(document, header, links, toc) {
        yield { range: header.headerLocation.range, kind: lsp.DocumentHighlightKind.Write };
        const docUri = document.uri.toString();
        for (const link of links) {
            if (link.href.kind === documentLinks_1.HrefKind.Internal
                && toc.lookup(link.href.fragment) === header
                && link.source.fragmentRange
                && link.href.path.toString() === docUri) {
                yield {
                    range: (0, range_1.modifyRange)(link.source.fragmentRange, (0, position_1.translatePosition)(link.source.fragmentRange.start, { characterDelta: -1 })),
                    kind: lsp.DocumentHighlightKind.Read,
                };
            }
        }
    }
    #getHighlightsForLinkAtPosition(document, position, links, toc) {
        const link = links.find(link => (0, range_1.rangeContains)(link.source.hrefRange, position) || (link.kind === documentLinks_1.MdLinkKind.Definition && (0, range_1.rangeContains)(link.ref.range, position)));
        if (!link) {
            return [];
        }
        if (link.kind === documentLinks_1.MdLinkKind.Definition && (0, range_1.rangeContains)(link.ref.range, position)) {
            // We are on the reference text inside the link definition
            return this.#getHighlightsForReference(link.ref.text, links);
        }
        switch (link.href.kind) {
            case documentLinks_1.HrefKind.Reference: {
                return this.#getHighlightsForReference(link.href.ref, links);
            }
            case documentLinks_1.HrefKind.Internal: {
                if (link.source.fragmentRange && (0, range_1.rangeContains)(link.source.fragmentRange, position)) {
                    return this.#getHighlightsForLinkFragment(document, link.href, links, toc);
                }
                return this.#getHighlightsForLinkPath(link.href.path, links);
            }
            case documentLinks_1.HrefKind.External: {
                return this.#getHighlightsForExternalLink(link.href.uri, links);
            }
        }
    }
    *#getHighlightsForLinkFragment(document, href, links, toc) {
        const targetDoc = (0, workspace_1.tryAppendMarkdownFileExtension)(this.#configuration, href.path);
        if (!targetDoc) {
            return;
        }
        const fragment = href.fragment.toLowerCase();
        if (targetDoc.toString() === document.uri) {
            const header = toc.lookup(fragment);
            if (header) {
                yield { range: header.headerLocation.range, kind: lsp.DocumentHighlightKind.Write };
            }
        }
        for (const link of links) {
            if (link.href.kind === documentLinks_1.HrefKind.Internal && (0, documentLinks_1.looksLikeLinkToResource)(this.#configuration, link.href, targetDoc)) {
                if (link.source.fragmentRange && link.href.fragment.toLowerCase() === fragment) {
                    yield {
                        range: (0, range_1.modifyRange)(link.source.fragmentRange, (0, position_1.translatePosition)(link.source.fragmentRange.start, { characterDelta: -1 })),
                        kind: lsp.DocumentHighlightKind.Read,
                    };
                }
            }
        }
    }
    *#getHighlightsForLinkPath(path, links) {
        const targetDoc = (0, workspace_1.tryAppendMarkdownFileExtension)(this.#configuration, path) ?? path;
        for (const link of links) {
            if (link.href.kind === documentLinks_1.HrefKind.Internal && (0, documentLinks_1.looksLikeLinkToResource)(this.#configuration, link.href, targetDoc)) {
                yield {
                    range: (0, rename_1.getFilePathRange)(link),
                    kind: lsp.DocumentHighlightKind.Read,
                };
            }
        }
    }
    *#getHighlightsForExternalLink(uri, links) {
        for (const link of links) {
            if (link.href.kind === documentLinks_1.HrefKind.External && link.href.uri.toString() === uri.toString()) {
                yield {
                    range: (0, rename_1.getFilePathRange)(link),
                    kind: lsp.DocumentHighlightKind.Read,
                };
            }
        }
    }
    *#getHighlightsForReference(ref, links) {
        for (const link of links) {
            if (link.kind === documentLinks_1.MdLinkKind.Definition && link.ref.text === ref) {
                yield {
                    range: link.ref.range,
                    kind: lsp.DocumentHighlightKind.Write,
                };
            }
            else if (link.href.kind === documentLinks_1.HrefKind.Reference && link.href.ref === ref) {
                yield {
                    range: link.source.hrefRange,
                    kind: lsp.DocumentHighlightKind.Read,
                };
            }
        }
    }
}
exports.MdDocumentHighlightProvider = MdDocumentHighlightProvider;
//# sourceMappingURL=documentHighlights.js.map