| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
- import { stringDiff } from '../../../base/common/diff/diff.js';
- import { globals } from '../../../base/common/platform.js';
- import { URI } from '../../../base/common/uri.js';
- import { Position } from '../core/position.js';
- import { Range } from '../core/range.js';
- import { DiffComputer } from '../diff/diffComputer.js';
- import { MirrorTextModel as BaseMirrorModel } from '../model/mirrorTextModel.js';
- import { ensureValidWordDefinition, getWordAtText } from '../core/wordHelper.js';
- import { computeLinks } from '../languages/linkComputer.js';
- import { BasicInplaceReplace } from '../languages/supports/inplaceReplaceSupport.js';
- import { createMonacoBaseAPI } from './editorBaseApi.js';
- import * as types from '../../../base/common/types.js';
- import { StopWatch } from '../../../base/common/stopwatch.js';
- import { UnicodeTextModelHighlighter } from './unicodeTextModelHighlighter.js';
- /**
- * @internal
- */
- export class MirrorModel extends BaseMirrorModel {
- get uri() {
- return this._uri;
- }
- get eol() {
- return this._eol;
- }
- getValue() {
- return this.getText();
- }
- getLinesContent() {
- return this._lines.slice(0);
- }
- getLineCount() {
- return this._lines.length;
- }
- getLineContent(lineNumber) {
- return this._lines[lineNumber - 1];
- }
- getWordAtPosition(position, wordDefinition) {
- const wordAtText = getWordAtText(position.column, ensureValidWordDefinition(wordDefinition), this._lines[position.lineNumber - 1], 0);
- if (wordAtText) {
- return new Range(position.lineNumber, wordAtText.startColumn, position.lineNumber, wordAtText.endColumn);
- }
- return null;
- }
- words(wordDefinition) {
- const lines = this._lines;
- const wordenize = this._wordenize.bind(this);
- let lineNumber = 0;
- let lineText = '';
- let wordRangesIdx = 0;
- let wordRanges = [];
- return {
- *[Symbol.iterator]() {
- while (true) {
- if (wordRangesIdx < wordRanges.length) {
- const value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end);
- wordRangesIdx += 1;
- yield value;
- }
- else {
- if (lineNumber < lines.length) {
- lineText = lines[lineNumber];
- wordRanges = wordenize(lineText, wordDefinition);
- wordRangesIdx = 0;
- lineNumber += 1;
- }
- else {
- break;
- }
- }
- }
- }
- };
- }
- getLineWords(lineNumber, wordDefinition) {
- const content = this._lines[lineNumber - 1];
- const ranges = this._wordenize(content, wordDefinition);
- const words = [];
- for (const range of ranges) {
- words.push({
- word: content.substring(range.start, range.end),
- startColumn: range.start + 1,
- endColumn: range.end + 1
- });
- }
- return words;
- }
- _wordenize(content, wordDefinition) {
- const result = [];
- let match;
- wordDefinition.lastIndex = 0; // reset lastIndex just to be sure
- while (match = wordDefinition.exec(content)) {
- if (match[0].length === 0) {
- // it did match the empty string
- break;
- }
- result.push({ start: match.index, end: match.index + match[0].length });
- }
- return result;
- }
- getValueInRange(range) {
- range = this._validateRange(range);
- if (range.startLineNumber === range.endLineNumber) {
- return this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1);
- }
- const lineEnding = this._eol;
- const startLineIndex = range.startLineNumber - 1;
- const endLineIndex = range.endLineNumber - 1;
- const resultLines = [];
- resultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));
- for (let i = startLineIndex + 1; i < endLineIndex; i++) {
- resultLines.push(this._lines[i]);
- }
- resultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1));
- return resultLines.join(lineEnding);
- }
- offsetAt(position) {
- position = this._validatePosition(position);
- this._ensureLineStarts();
- return this._lineStarts.getPrefixSum(position.lineNumber - 2) + (position.column - 1);
- }
- 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 {
- lineNumber: 1 + out.index,
- column: 1 + Math.min(out.remainder, lineLength)
- };
- }
- _validateRange(range) {
- const start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });
- const end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn });
- if (start.lineNumber !== range.startLineNumber
- || start.column !== range.startColumn
- || end.lineNumber !== range.endLineNumber
- || end.column !== range.endColumn) {
- return {
- startLineNumber: start.lineNumber,
- startColumn: start.column,
- endLineNumber: end.lineNumber,
- endColumn: end.column
- };
- }
- return range;
- }
- _validatePosition(position) {
- if (!Position.isIPosition(position)) {
- throw new Error('bad position');
- }
- let { lineNumber, column } = position;
- let hasChanged = false;
- if (lineNumber < 1) {
- lineNumber = 1;
- column = 1;
- hasChanged = true;
- }
- else if (lineNumber > this._lines.length) {
- lineNumber = this._lines.length;
- column = this._lines[lineNumber - 1].length + 1;
- hasChanged = true;
- }
- else {
- const maxCharacter = this._lines[lineNumber - 1].length + 1;
- if (column < 1) {
- column = 1;
- hasChanged = true;
- }
- else if (column > maxCharacter) {
- column = maxCharacter;
- hasChanged = true;
- }
- }
- if (!hasChanged) {
- return position;
- }
- else {
- return { lineNumber, column };
- }
- }
- }
- /**
- * @internal
- */
- export class EditorSimpleWorker {
- constructor(host, foreignModuleFactory) {
- this._host = host;
- this._models = Object.create(null);
- this._foreignModuleFactory = foreignModuleFactory;
- this._foreignModule = null;
- }
- dispose() {
- this._models = Object.create(null);
- }
- _getModel(uri) {
- return this._models[uri];
- }
- _getModels() {
- const all = [];
- Object.keys(this._models).forEach((key) => all.push(this._models[key]));
- return all;
- }
- acceptNewModel(data) {
- this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);
- }
- acceptModelChanged(strURL, e) {
- if (!this._models[strURL]) {
- return;
- }
- const model = this._models[strURL];
- model.onEvents(e);
- }
- acceptRemovedModel(strURL) {
- if (!this._models[strURL]) {
- return;
- }
- delete this._models[strURL];
- }
- computeUnicodeHighlights(url, options, range) {
- return __awaiter(this, void 0, void 0, function* () {
- const model = this._getModel(url);
- if (!model) {
- return { ranges: [], hasMore: false, ambiguousCharacterCount: 0, invisibleCharacterCount: 0, nonBasicAsciiCharacterCount: 0 };
- }
- return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);
- });
- }
- // ---- BEGIN diff --------------------------------------------------------------------------
- computeDiff(originalUrl, modifiedUrl, ignoreTrimWhitespace, maxComputationTime) {
- return __awaiter(this, void 0, void 0, function* () {
- const original = this._getModel(originalUrl);
- const modified = this._getModel(modifiedUrl);
- if (!original || !modified) {
- return null;
- }
- return EditorSimpleWorker.computeDiff(original, modified, ignoreTrimWhitespace, maxComputationTime);
- });
- }
- static computeDiff(originalTextModel, modifiedTextModel, ignoreTrimWhitespace, maxComputationTime) {
- const originalLines = originalTextModel.getLinesContent();
- const modifiedLines = modifiedTextModel.getLinesContent();
- const diffComputer = new DiffComputer(originalLines, modifiedLines, {
- shouldComputeCharChanges: true,
- shouldPostProcessCharChanges: true,
- shouldIgnoreTrimWhitespace: ignoreTrimWhitespace,
- shouldMakePrettyDiff: true,
- maxComputationTime: maxComputationTime
- });
- const diffResult = diffComputer.computeDiff();
- const identical = (diffResult.changes.length > 0 ? false : this._modelsAreIdentical(originalTextModel, modifiedTextModel));
- return {
- quitEarly: diffResult.quitEarly,
- identical: identical,
- changes: diffResult.changes
- };
- }
- static _modelsAreIdentical(original, modified) {
- const originalLineCount = original.getLineCount();
- const modifiedLineCount = modified.getLineCount();
- if (originalLineCount !== modifiedLineCount) {
- return false;
- }
- for (let line = 1; line <= originalLineCount; line++) {
- const originalLine = original.getLineContent(line);
- const modifiedLine = modified.getLineContent(line);
- if (originalLine !== modifiedLine) {
- return false;
- }
- }
- return true;
- }
- computeMoreMinimalEdits(modelUrl, edits) {
- return __awaiter(this, void 0, void 0, function* () {
- const model = this._getModel(modelUrl);
- if (!model) {
- return edits;
- }
- const result = [];
- let lastEol = undefined;
- edits = edits.slice(0).sort((a, b) => {
- if (a.range && b.range) {
- return Range.compareRangesUsingStarts(a.range, b.range);
- }
- // eol only changes should go to the end
- const aRng = a.range ? 0 : 1;
- const bRng = b.range ? 0 : 1;
- return aRng - bRng;
- });
- for (let { range, text, eol } of edits) {
- if (typeof eol === 'number') {
- lastEol = eol;
- }
- if (Range.isEmpty(range) && !text) {
- // empty change
- continue;
- }
- const original = model.getValueInRange(range);
- text = text.replace(/\r\n|\n|\r/g, model.eol);
- if (original === text) {
- // noop
- continue;
- }
- // make sure diff won't take too long
- if (Math.max(text.length, original.length) > EditorSimpleWorker._diffLimit) {
- result.push({ range, text });
- continue;
- }
- // compute diff between original and edit.text
- const changes = stringDiff(original, text, false);
- const editOffset = model.offsetAt(Range.lift(range).getStartPosition());
- for (const change of changes) {
- const start = model.positionAt(editOffset + change.originalStart);
- const end = model.positionAt(editOffset + change.originalStart + change.originalLength);
- const newEdit = {
- text: text.substr(change.modifiedStart, change.modifiedLength),
- range: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }
- };
- if (model.getValueInRange(newEdit.range) !== newEdit.text) {
- result.push(newEdit);
- }
- }
- }
- if (typeof lastEol === 'number') {
- result.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } });
- }
- return result;
- });
- }
- // ---- END minimal edits ---------------------------------------------------------------
- computeLinks(modelUrl) {
- return __awaiter(this, void 0, void 0, function* () {
- const model = this._getModel(modelUrl);
- if (!model) {
- return null;
- }
- return computeLinks(model);
- });
- }
- textualSuggest(modelUrls, leadingWord, wordDef, wordDefFlags) {
- return __awaiter(this, void 0, void 0, function* () {
- const sw = new StopWatch(true);
- const wordDefRegExp = new RegExp(wordDef, wordDefFlags);
- const seen = new Set();
- outer: for (const url of modelUrls) {
- const model = this._getModel(url);
- if (!model) {
- continue;
- }
- for (const word of model.words(wordDefRegExp)) {
- if (word === leadingWord || !isNaN(Number(word))) {
- continue;
- }
- seen.add(word);
- if (seen.size > EditorSimpleWorker._suggestionsLimit) {
- break outer;
- }
- }
- }
- return { words: Array.from(seen), duration: sw.elapsed() };
- });
- }
- // ---- END suggest --------------------------------------------------------------------------
- //#region -- word ranges --
- computeWordRanges(modelUrl, range, wordDef, wordDefFlags) {
- return __awaiter(this, void 0, void 0, function* () {
- const model = this._getModel(modelUrl);
- if (!model) {
- return Object.create(null);
- }
- const wordDefRegExp = new RegExp(wordDef, wordDefFlags);
- const result = Object.create(null);
- for (let line = range.startLineNumber; line < range.endLineNumber; line++) {
- const words = model.getLineWords(line, wordDefRegExp);
- for (const word of words) {
- if (!isNaN(Number(word.word))) {
- continue;
- }
- let array = result[word.word];
- if (!array) {
- array = [];
- result[word.word] = array;
- }
- array.push({
- startLineNumber: line,
- startColumn: word.startColumn,
- endLineNumber: line,
- endColumn: word.endColumn
- });
- }
- }
- return result;
- });
- }
- //#endregion
- navigateValueSet(modelUrl, range, up, wordDef, wordDefFlags) {
- return __awaiter(this, void 0, void 0, function* () {
- const model = this._getModel(modelUrl);
- if (!model) {
- return null;
- }
- const wordDefRegExp = new RegExp(wordDef, wordDefFlags);
- if (range.startColumn === range.endColumn) {
- range = {
- startLineNumber: range.startLineNumber,
- startColumn: range.startColumn,
- endLineNumber: range.endLineNumber,
- endColumn: range.endColumn + 1
- };
- }
- const selectionText = model.getValueInRange(range);
- const wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp);
- if (!wordRange) {
- return null;
- }
- const word = model.getValueInRange(wordRange);
- const result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up);
- return result;
- });
- }
- // ---- BEGIN foreign module support --------------------------------------------------------------------------
- loadForeignModule(moduleId, createData, foreignHostMethods) {
- const proxyMethodRequest = (method, args) => {
- return this._host.fhr(method, args);
- };
- const foreignHost = types.createProxyObject(foreignHostMethods, proxyMethodRequest);
- const ctx = {
- host: foreignHost,
- getMirrorModels: () => {
- return this._getModels();
- }
- };
- if (this._foreignModuleFactory) {
- this._foreignModule = this._foreignModuleFactory(ctx, createData);
- // static foreing module
- return Promise.resolve(types.getAllMethodNames(this._foreignModule));
- }
- // ESM-comment-begin
- // return new Promise<any>((resolve, reject) => {
- // require([moduleId], (foreignModule: { create: IForeignModuleFactory }) => {
- // this._foreignModule = foreignModule.create(ctx, createData);
- //
- // resolve(types.getAllMethodNames(this._foreignModule));
- //
- // }, reject);
- // });
- // ESM-comment-end
- // ESM-uncomment-begin
- return Promise.reject(new Error(`Unexpected usage`));
- // ESM-uncomment-end
- }
- // foreign method request
- fmr(method, args) {
- if (!this._foreignModule || typeof this._foreignModule[method] !== 'function') {
- return Promise.reject(new Error('Missing requestHandler or method: ' + method));
- }
- try {
- return Promise.resolve(this._foreignModule[method].apply(this._foreignModule, args));
- }
- catch (e) {
- return Promise.reject(e);
- }
- }
- }
- // ---- END diff --------------------------------------------------------------------------
- // ---- BEGIN minimal edits ---------------------------------------------------------------
- EditorSimpleWorker._diffLimit = 100000;
- // ---- BEGIN suggest --------------------------------------------------------------------------
- EditorSimpleWorker._suggestionsLimit = 10000;
- /**
- * Called on the worker side
- * @internal
- */
- export function create(host) {
- return new EditorSimpleWorker(host, null);
- }
- if (typeof importScripts === 'function') {
- // Running in a web worker
- globals.monaco = createMonacoBaseAPI();
- }
|