"use strict";
var _ExtHostDocumentData_proxy;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtHostDocumentData = void 0;
exports.setWordDefinitionFor = setWordDefinitionFor;
exports.getWordDefinitionFor = getWordDefinitionFor;
exports.regExpLeadsToEndlessLoop = regExpLeadsToEndlessLoop;
const tslib_1 = require("tslib");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const ext_types_1 = require("../../../../common/vscode/ext-types");
const mirror_1 = require("./mirror");
const wordHelper_1 = require("./wordHelper");
const _modeId2WordDefinition = new Map();
function setWordDefinitionFor(modeId, wordDefinition) {
    _modeId2WordDefinition.set(modeId, wordDefinition);
}
function getWordDefinitionFor(modeId) {
    return _modeId2WordDefinition.get(modeId);
}
function regExpLeadsToEndlessLoop(regexp) {
    // Exit early if it's one of these special cases which are meant to match
    // against an empty string
    if (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\s*$') {
        return false;
    }
    // We check against an empty string. If the regular expression doesn't advance
    // (e.g. ends in an endless loop) it will match an empty string.
    const match = regexp.exec('');
    return !!(match && regexp.lastIndex === 0);
}
class ExtHostDocumentData extends mirror_1.MirrorTextModel {
    constructor(proxy, uri, lines, eol, languageId, versionId, isDirty) {
        super(uri, lines, eol, versionId);
        _ExtHostDocumentData_proxy.set(this, void 0);
        this._textLines = [];
        this._isDisposed = false;
        tslib_1.__classPrivateFieldSet(this, _ExtHostDocumentData_proxy, proxy, "f");
        this._languageId = languageId;
        this._isDirty = isDirty;
    }
    dispose() {
        this._isDisposed = true;
        this._isDirty = false;
    }
    equalLines(lines) {
        const len = lines.length;
        if (len !== this._lines.length) {
            return false;
        }
        for (let i = 0; i < len; i++) {
            if (lines[i] !== this._lines[i]) {
                return false;
            }
        }
        return true;
    }
    get document() {
        if (!this._document) {
            const data = this;
            this._document = {
                get uri() {
                    return data._uri;
                },
                get fileName() {
                    return data._uri.fsPath;
                },
                get isUntitled() {
                    return data._uri.scheme === ide_core_common_1.Schemes.untitled;
                },
                get languageId() {
                    return data._languageId;
                },
                get version() {
                    return data._versionId;
                },
                get isClosed() {
                    return data._isDisposed;
                },
                get isDirty() {
                    return data._isDirty;
                },
                save() {
                    return data._save();
                },
                getText(range) {
                    return range ? data._getTextInRange(range) : data.getText();
                },
                get eol() {
                    return data._eol === '\n' ? ext_types_1.EndOfLine.LF : ext_types_1.EndOfLine.CRLF;
                },
                get lineCount() {
                    return data._lines.length;
                },
                lineAt(lineOrPos) {
                    return data._lineAt(lineOrPos);
                },
                offsetAt(pos) {
                    return data._offsetAt(pos);
                },
                positionAt(offset) {
                    return data._positionAt(offset);
                },
                validateRange(ran) {
                    return data._validateRange(ran);
                },
                validatePosition(pos) {
                    return data._validatePosition(pos);
                },
                getWordRangeAtPosition(pos, regexp) {
                    return data._getWordRangeAtPosition(pos, regexp);
                },
            };
        }
        return Object.freeze(this._document);
    }
    _acceptLanguageId(newLanguageId) {
        this._languageId = newLanguageId;
    }
    _getLanguageId() {
        return this._languageId;
    }
    _acceptIsDirty(isDirty) {
        this._isDirty = isDirty;
    }
    _save() {
        if (this._isDisposed) {
            return Promise.reject(new Error('Document has been closed'));
        }
        return tslib_1.__classPrivateFieldGet(this, _ExtHostDocumentData_proxy, "f").$trySaveDocument(this._uri.toString());
    }
    _getTextInRange(_range) {
        const range = this._validateRange(_range);
        if (range.isEmpty) {
            return '';
        }
        if (range.isSingleLine) {
            return this._lines[range.start.line].substring(range.start.character, range.end.character);
        }
        const lineEnding = this._eol;
        const startLineIndex = range.start.line;
        const endLineIndex = range.end.line;
        const resultLines = [];
        resultLines.push(this._lines[startLineIndex].substring(range.start.character));
        for (let i = startLineIndex + 1; i < endLineIndex; i++) {
            resultLines.push(this._lines[i]);
        }
        resultLines.push(this._lines[endLineIndex].substring(0, range.end.character));
        return resultLines.join(lineEnding);
    }
    _lineAt(lineOrPosition) {
        let line;
        if (lineOrPosition instanceof ext_types_1.Position) {
            line = lineOrPosition.line;
        }
        else if (typeof lineOrPosition === 'number') {
            line = lineOrPosition;
        }
        if (typeof line !== 'number' || line < 0 || line >= this._lines.length) {
            throw new Error('Illegal value for `line`');
        }
        let result = this._textLines[line];
        if (!result || result.lineNumber !== line || result.text !== this._lines[line]) {
            const text = this._lines[line];
            const firstNonWhitespaceCharacterIndex = /^(\s*)/.exec(text)[1].length;
            const range = new ext_types_1.Range(line, 0, line, text.length);
            const rangeIncludingLineBreak = line < this._lines.length - 1 ? new ext_types_1.Range(line, 0, line + 1, 0) : range;
            result = Object.freeze({
                lineNumber: line,
                range,
                rangeIncludingLineBreak,
                text,
                firstNonWhitespaceCharacterIndex,
                isEmptyOrWhitespace: firstNonWhitespaceCharacterIndex === text.length,
            });
            this._textLines[line] = result;
        }
        return result;
    }
    _offsetAt(position) {
        position = this._validatePosition(position);
        this._ensureLineStarts();
        return this._lineStarts.getAccumulatedValue(position.line - 1) + position.character;
    }
    _positionAt(offset) {
        offset = Math.floor(offset);
        offset = Math.max(0, offset);
        this._ensureLineStarts();
        const out = this._lineStarts.getIndexOf(offset);
        const lineLength = this._lines[out.index].length;
        // Ensure we return a valid position
        return new ext_types_1.Position(out.index, Math.min(out.remainder, lineLength));
    }
    // ---- range math
    _validateRange(range) {
        if (!(range instanceof ext_types_1.Range)) {
            throw new Error('Invalid argument');
        }
        const start = this._validatePosition(range.start);
        const end = this._validatePosition(range.end);
        if (start === range.start && end === range.end) {
            return range;
        }
        return new ext_types_1.Range(start.line, start.character, end.line, end.character);
    }
    _validatePosition(position) {
        if (!(position instanceof ext_types_1.Position)) {
            throw new Error('Invalid argument');
        }
        let { line, character } = position;
        let hasChanged = false;
        if (line < 0) {
            line = 0;
            character = 0;
            hasChanged = true;
        }
        else if (line >= this._lines.length) {
            line = this._lines.length - 1;
            character = this._lines[line].length;
            hasChanged = true;
        }
        else {
            const maxCharacter = this._lines[line].length;
            if (character < 0) {
                character = 0;
                hasChanged = true;
            }
            else if (character > maxCharacter) {
                character = maxCharacter;
                hasChanged = true;
            }
        }
        if (!hasChanged) {
            return position;
        }
        return new ext_types_1.Position(line, character);
    }
    _getWordRangeAtPosition(_position, regexp) {
        const position = this._validatePosition(_position);
        if (!regexp) {
            // use default when custom-regexp isn't provided
            regexp = getWordDefinitionFor(this._languageId);
        }
        else if (regExpLeadsToEndlessLoop(regexp)) {
            // use default when custom-regexp is bad
            // eslint-disable-next-line no-console
            console.warn(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`);
            regexp = getWordDefinitionFor(this._languageId);
        }
        const wordAtText = (0, wordHelper_1.getWordAtText)(position.character + 1, (0, wordHelper_1.ensureValidWordDefinition)(regexp), this._lines[position.line], 0);
        if (wordAtText) {
            return new ext_types_1.Range(position.line, wordAtText.startColumn - 1, position.line, wordAtText.endColumn - 1);
        }
        return undefined;
    }
}
exports.ExtHostDocumentData = ExtHostDocumentData;
_ExtHostDocumentData_proxy = new WeakMap();
//# sourceMappingURL=ext-data.host.js.map