monaco-editor
Version:
A browser based code editor
543 lines (542 loc) • 22.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import { mergeSort } from '../../../base/common/arrays.js';
import { stringDiff } from '../../../base/common/diff/diff.js';
import { FIN } from '../../../base/common/iterator.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 '../model/wordHelper.js';
import { computeLinks } from '../modes/linkComputer.js';
import { BasicInplaceReplace } from '../modes/supports/inplaceReplaceSupport.js';
import { createMonacoBaseAPI } from '../standalone/standaloneBase.js';
/**
* @internal
*/
var MirrorModel = /** @class */ (function (_super) {
__extends(MirrorModel, _super);
function MirrorModel() {
return _super !== null && _super.apply(this, arguments) || this;
}
Object.defineProperty(MirrorModel.prototype, "uri", {
get: function () {
return this._uri;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MirrorModel.prototype, "version", {
get: function () {
return this._versionId;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MirrorModel.prototype, "eol", {
get: function () {
return this._eol;
},
enumerable: true,
configurable: true
});
MirrorModel.prototype.getValue = function () {
return this.getText();
};
MirrorModel.prototype.getLinesContent = function () {
return this._lines.slice(0);
};
MirrorModel.prototype.getLineCount = function () {
return this._lines.length;
};
MirrorModel.prototype.getLineContent = function (lineNumber) {
return this._lines[lineNumber - 1];
};
MirrorModel.prototype.getWordAtPosition = function (position, wordDefinition) {
var 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;
};
MirrorModel.prototype.getWordUntilPosition = function (position, wordDefinition) {
var wordAtPosition = this.getWordAtPosition(position, wordDefinition);
if (!wordAtPosition) {
return {
word: '',
startColumn: position.column,
endColumn: position.column
};
}
return {
word: this._lines[position.lineNumber - 1].substring(wordAtPosition.startColumn - 1, position.column - 1),
startColumn: wordAtPosition.startColumn,
endColumn: position.column
};
};
MirrorModel.prototype.createWordIterator = function (wordDefinition) {
var _this = this;
var obj;
var lineNumber = 0;
var lineText;
var wordRangesIdx = 0;
var wordRanges = [];
var next = function () {
if (wordRangesIdx < wordRanges.length) {
var value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end);
wordRangesIdx += 1;
if (!obj) {
obj = { done: false, value: value };
}
else {
obj.value = value;
}
return obj;
}
else if (lineNumber >= _this._lines.length) {
return FIN;
}
else {
lineText = _this._lines[lineNumber];
wordRanges = _this._wordenize(lineText, wordDefinition);
wordRangesIdx = 0;
lineNumber += 1;
return next();
}
};
return { next: next };
};
MirrorModel.prototype.getLineWords = function (lineNumber, wordDefinition) {
var content = this._lines[lineNumber - 1];
var ranges = this._wordenize(content, wordDefinition);
var words = [];
for (var _i = 0, ranges_1 = ranges; _i < ranges_1.length; _i++) {
var range = ranges_1[_i];
words.push({
word: content.substring(range.start, range.end),
startColumn: range.start + 1,
endColumn: range.end + 1
});
}
return words;
};
MirrorModel.prototype._wordenize = function (content, wordDefinition) {
var result = [];
var 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;
};
MirrorModel.prototype.getValueInRange = function (range) {
range = this._validateRange(range);
if (range.startLineNumber === range.endLineNumber) {
return this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1);
}
var lineEnding = this._eol;
var startLineIndex = range.startLineNumber - 1;
var endLineIndex = range.endLineNumber - 1;
var resultLines = [];
resultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));
for (var 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);
};
MirrorModel.prototype.offsetAt = function (position) {
position = this._validatePosition(position);
this._ensureLineStarts();
return this._lineStarts.getAccumulatedValue(position.lineNumber - 2) + (position.column - 1);
};
MirrorModel.prototype.positionAt = function (offset) {
offset = Math.floor(offset);
offset = Math.max(0, offset);
this._ensureLineStarts();
var out = this._lineStarts.getIndexOf(offset);
var lineLength = this._lines[out.index].length;
// Ensure we return a valid position
return {
lineNumber: 1 + out.index,
column: 1 + Math.min(out.remainder, lineLength)
};
};
MirrorModel.prototype._validateRange = function (range) {
var start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });
var 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;
};
MirrorModel.prototype._validatePosition = function (position) {
if (!Position.isIPosition(position)) {
throw new Error('bad position');
}
var lineNumber = position.lineNumber, column = position.column;
var 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 {
var 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: lineNumber, column: column };
}
};
return MirrorModel;
}(BaseMirrorModel));
/**
* @internal
*/
var BaseEditorSimpleWorker = /** @class */ (function () {
function BaseEditorSimpleWorker(foreignModuleFactory) {
this._foreignModuleFactory = foreignModuleFactory;
this._foreignModule = null;
}
// ---- BEGIN diff --------------------------------------------------------------------------
BaseEditorSimpleWorker.prototype.computeDiff = function (originalUrl, modifiedUrl, ignoreTrimWhitespace) {
var original = this._getModel(originalUrl);
var modified = this._getModel(modifiedUrl);
if (!original || !modified) {
return Promise.resolve(null);
}
var originalLines = original.getLinesContent();
var modifiedLines = modified.getLinesContent();
var diffComputer = new DiffComputer(originalLines, modifiedLines, {
shouldComputeCharChanges: true,
shouldPostProcessCharChanges: true,
shouldIgnoreTrimWhitespace: ignoreTrimWhitespace,
shouldMakePrettyDiff: true
});
var changes = diffComputer.computeDiff();
var identical = (changes.length > 0 ? false : this._modelsAreIdentical(original, modified));
return Promise.resolve({
identical: identical,
changes: changes
});
};
BaseEditorSimpleWorker.prototype._modelsAreIdentical = function (original, modified) {
var originalLineCount = original.getLineCount();
var modifiedLineCount = modified.getLineCount();
if (originalLineCount !== modifiedLineCount) {
return false;
}
for (var line = 1; line <= originalLineCount; line++) {
var originalLine = original.getLineContent(line);
var modifiedLine = modified.getLineContent(line);
if (originalLine !== modifiedLine) {
return false;
}
}
return true;
};
BaseEditorSimpleWorker.prototype.computeMoreMinimalEdits = function (modelUrl, edits) {
var model = this._getModel(modelUrl);
if (!model) {
return Promise.resolve(edits);
}
var result = [];
var lastEol = undefined;
edits = mergeSort(edits, function (a, b) {
if (a.range && b.range) {
return Range.compareRangesUsingStarts(a.range, b.range);
}
// eol only changes should go to the end
var aRng = a.range ? 0 : 1;
var bRng = b.range ? 0 : 1;
return aRng - bRng;
});
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var _a = edits_1[_i], range = _a.range, text = _a.text, eol = _a.eol;
if (typeof eol === 'number') {
lastEol = eol;
}
if (!range) {
// eol-change only
continue;
}
var 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) > BaseEditorSimpleWorker._diffLimit) {
result.push({ range: range, text: text });
continue;
}
// compute diff between original and edit.text
var changes = stringDiff(original, text, false);
var editOffset = model.offsetAt(Range.lift(range).getStartPosition());
for (var _b = 0, changes_1 = changes; _b < changes_1.length; _b++) {
var change = changes_1[_b];
var start = model.positionAt(editOffset + change.originalStart);
var end = model.positionAt(editOffset + change.originalStart + change.originalLength);
var 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: undefined, range: undefined });
}
return Promise.resolve(result);
};
// ---- END minimal edits ---------------------------------------------------------------
BaseEditorSimpleWorker.prototype.computeLinks = function (modelUrl) {
var model = this._getModel(modelUrl);
if (!model) {
return Promise.resolve(null);
}
return Promise.resolve(computeLinks(model));
};
BaseEditorSimpleWorker.prototype.textualSuggest = function (modelUrl, position, wordDef, wordDefFlags) {
var model = this._getModel(modelUrl);
if (!model) {
return Promise.resolve(null);
}
var suggestions = [];
var wordDefRegExp = new RegExp(wordDef, wordDefFlags);
var currentWord = model.getWordUntilPosition(position, wordDefRegExp);
var seen = Object.create(null);
seen[currentWord.word] = true;
for (var iter = model.createWordIterator(wordDefRegExp), e = iter.next(); !e.done && suggestions.length <= BaseEditorSimpleWorker._suggestionsLimit; e = iter.next()) {
var word = e.value;
if (seen[word]) {
continue;
}
seen[word] = true;
if (!isNaN(Number(word))) {
continue;
}
suggestions.push({
kind: 18 /* Text */,
label: word,
insertText: word,
range: { startLineNumber: position.lineNumber, startColumn: currentWord.startColumn, endLineNumber: position.lineNumber, endColumn: currentWord.endColumn }
});
}
return Promise.resolve({ suggestions: suggestions });
};
// ---- END suggest --------------------------------------------------------------------------
//#region -- word ranges --
BaseEditorSimpleWorker.prototype.computeWordRanges = function (modelUrl, range, wordDef, wordDefFlags) {
var model = this._getModel(modelUrl);
if (!model) {
return Promise.resolve(Object.create(null));
}
var wordDefRegExp = new RegExp(wordDef, wordDefFlags);
var result = Object.create(null);
for (var line = range.startLineNumber; line < range.endLineNumber; line++) {
var words = model.getLineWords(line, wordDefRegExp);
for (var _i = 0, words_1 = words; _i < words_1.length; _i++) {
var word = words_1[_i];
if (!isNaN(Number(word.word))) {
continue;
}
var array = result[word.word];
if (!array) {
array = [];
result[word.word] = array;
}
array.push({
startLineNumber: line,
startColumn: word.startColumn,
endLineNumber: line,
endColumn: word.endColumn
});
}
}
return Promise.resolve(result);
};
//#endregion
BaseEditorSimpleWorker.prototype.navigateValueSet = function (modelUrl, range, up, wordDef, wordDefFlags) {
var model = this._getModel(modelUrl);
if (!model) {
return Promise.resolve(null);
}
var wordDefRegExp = new RegExp(wordDef, wordDefFlags);
if (range.startColumn === range.endColumn) {
range = {
startLineNumber: range.startLineNumber,
startColumn: range.startColumn,
endLineNumber: range.endLineNumber,
endColumn: range.endColumn + 1
};
}
var selectionText = model.getValueInRange(range);
var wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp);
if (!wordRange) {
return Promise.resolve(null);
}
var word = model.getValueInRange(wordRange);
var result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up);
return Promise.resolve(result);
};
// ---- BEGIN foreign module support --------------------------------------------------------------------------
BaseEditorSimpleWorker.prototype.loadForeignModule = function (moduleId, createData) {
var _this = this;
var ctx = {
getMirrorModels: function () {
return _this._getModels();
}
};
if (this._foreignModuleFactory) {
this._foreignModule = this._foreignModuleFactory(ctx, createData);
// static foreing module
var methods = [];
for (var prop in this._foreignModule) {
if (typeof this._foreignModule[prop] === 'function') {
methods.push(prop);
}
}
return Promise.resolve(methods);
}
// ESM-comment-begin
// return new Promise<any>((resolve, reject) => {
// require([moduleId], (foreignModule: { create: IForeignModuleFactory }) => {
// this._foreignModule = foreignModule.create(ctx, createData);
//
// let methods: string[] = [];
// for (let prop in this._foreignModule) {
// if (typeof this._foreignModule[prop] === 'function') {
// methods.push(prop);
// }
// }
//
// resolve(methods);
//
// }, reject);
// });
// ESM-comment-end
// ESM-uncomment-begin
return Promise.reject(new Error("Unexpected usage"));
// ESM-uncomment-end
};
// foreign method request
BaseEditorSimpleWorker.prototype.fmr = function (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 ---------------------------------------------------------------
BaseEditorSimpleWorker._diffLimit = 10000;
// ---- BEGIN suggest --------------------------------------------------------------------------
BaseEditorSimpleWorker._suggestionsLimit = 10000;
return BaseEditorSimpleWorker;
}());
export { BaseEditorSimpleWorker };
/**
* @internal
*/
var EditorSimpleWorkerImpl = /** @class */ (function (_super) {
__extends(EditorSimpleWorkerImpl, _super);
function EditorSimpleWorkerImpl(foreignModuleFactory) {
var _this = _super.call(this, foreignModuleFactory) || this;
_this._models = Object.create(null);
return _this;
}
EditorSimpleWorkerImpl.prototype.dispose = function () {
this._models = Object.create(null);
};
EditorSimpleWorkerImpl.prototype._getModel = function (uri) {
return this._models[uri];
};
EditorSimpleWorkerImpl.prototype._getModels = function () {
var _this = this;
var all = [];
Object.keys(this._models).forEach(function (key) { return all.push(_this._models[key]); });
return all;
};
EditorSimpleWorkerImpl.prototype.acceptNewModel = function (data) {
this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);
};
EditorSimpleWorkerImpl.prototype.acceptModelChanged = function (strURL, e) {
if (!this._models[strURL]) {
return;
}
var model = this._models[strURL];
model.onEvents(e);
};
EditorSimpleWorkerImpl.prototype.acceptRemovedModel = function (strURL) {
if (!this._models[strURL]) {
return;
}
delete this._models[strURL];
};
return EditorSimpleWorkerImpl;
}(BaseEditorSimpleWorker));
export { EditorSimpleWorkerImpl };
/**
* Called on the worker side
* @internal
*/
export function create() {
return new EditorSimpleWorkerImpl(null);
}
if (typeof importScripts === 'function') {
// Running in a web worker
globals.monaco = createMonacoBaseAPI();
}