UNPKG

monaco-editor

Version:
457 lines (456 loc) • 23.2 kB
/*--------------------------------------------------------------------------------------------- * 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 __()); }; })(); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import * as nls from '../../../nls.js'; import { isFalsyOrEmpty } from '../../../base/common/arrays.js'; import { Emitter } from '../../../base/common/event.js'; import { MarkdownString } from '../../../base/common/htmlContent.js'; import { Disposable, dispose } from '../../../base/common/lifecycle.js'; import * as network from '../../../base/common/network.js'; import { basename } from '../../../base/common/paths.js'; import * as platform from '../../../base/common/platform.js'; import { EDITOR_MODEL_DEFAULTS } from '../config/editorOptions.js'; import { Range } from '../core/range.js'; import { OverviewRulerLane } from '../model.js'; import { TextModel } from '../model/textModel.js'; import { PLAINTEXT_LANGUAGE_IDENTIFIER } from '../modes/modesRegistry.js'; import { ITextResourcePropertiesService } from './resourceConfiguration.js'; import { overviewRulerError, overviewRulerInfo, overviewRulerWarning } from '../view/editorColorRegistry.js'; import { IConfigurationService } from '../../../platform/configuration/common/configuration.js'; import { IMarkerService, MarkerSeverity } from '../../../platform/markers/common/markers.js'; import { themeColorFromId } from '../../../platform/theme/common/themeService.js'; function MODEL_ID(resource) { return resource.toString(); } var ModelData = /** @class */ (function () { function ModelData(model, onWillDispose, onDidChangeLanguage) { this.model = model; this._languageSelection = null; this._languageSelectionListener = null; this._markerDecorations = []; this._modelEventListeners = []; this._modelEventListeners.push(model.onWillDispose(function () { return onWillDispose(model); })); this._modelEventListeners.push(model.onDidChangeLanguage(function (e) { return onDidChangeLanguage(model, e); })); } ModelData.prototype._disposeLanguageSelection = function () { if (this._languageSelectionListener) { this._languageSelectionListener.dispose(); this._languageSelectionListener = null; } if (this._languageSelection) { this._languageSelection.dispose(); this._languageSelection = null; } }; ModelData.prototype.dispose = function () { this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []); this._modelEventListeners = dispose(this._modelEventListeners); this._disposeLanguageSelection(); }; ModelData.prototype.acceptMarkerDecorations = function (newDecorations) { this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations); }; ModelData.prototype.setLanguage = function (languageSelection) { var _this = this; this._disposeLanguageSelection(); this._languageSelection = languageSelection; this._languageSelectionListener = this._languageSelection.onDidChange(function () { return _this.model.setMode(languageSelection.languageIdentifier); }); this.model.setMode(languageSelection.languageIdentifier); }; return ModelData; }()); var ModelMarkerHandler = /** @class */ (function () { function ModelMarkerHandler() { } ModelMarkerHandler.setMarkers = function (modelData, markerService) { // Limit to the first 500 errors/warnings var markers = markerService.read({ resource: modelData.model.uri, take: 500 }); var newModelDecorations = markers.map(function (marker) { return { range: ModelMarkerHandler._createDecorationRange(modelData.model, marker), options: ModelMarkerHandler._createDecorationOption(marker) }; }); modelData.acceptMarkerDecorations(newModelDecorations); }; ModelMarkerHandler._createDecorationRange = function (model, rawMarker) { var ret = Range.lift(rawMarker); if (rawMarker.severity === MarkerSeverity.Hint) { if (!rawMarker.tags || rawMarker.tags.indexOf(1 /* Unnecessary */) === -1) { // * never render hints on multiple lines // * make enough space for three dots ret = ret.setEndPosition(ret.startLineNumber, ret.startColumn + 2); } } ret = model.validateRange(ret); if (ret.isEmpty()) { var word = model.getWordAtPosition(ret.getStartPosition()); if (word) { ret = new Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn); } else { var maxColumn = model.getLineLastNonWhitespaceColumn(ret.startLineNumber) || model.getLineMaxColumn(ret.startLineNumber); if (maxColumn === 1) { // empty line // console.warn('marker on empty line:', marker); } else if (ret.endColumn >= maxColumn) { // behind eol ret = new Range(ret.startLineNumber, maxColumn - 1, ret.endLineNumber, maxColumn); } else { // extend marker to width = 1 ret = new Range(ret.startLineNumber, ret.startColumn, ret.endLineNumber, ret.endColumn + 1); } } } else if (rawMarker.endColumn === Number.MAX_VALUE && rawMarker.startColumn === 1 && ret.startLineNumber === ret.endLineNumber) { var minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber); if (minColumn < ret.endColumn) { ret = new Range(ret.startLineNumber, minColumn, ret.endLineNumber, ret.endColumn); rawMarker.startColumn = minColumn; } } return ret; }; ModelMarkerHandler._createDecorationOption = function (marker) { var className; var color = undefined; var zIndex; var inlineClassName = undefined; switch (marker.severity) { case MarkerSeverity.Hint: if (marker.tags && marker.tags.indexOf(1 /* Unnecessary */) >= 0) { className = "squiggly-unnecessary" /* EditorUnnecessaryDecoration */; } else { className = "squiggly-hint" /* EditorHintDecoration */; } zIndex = 0; break; case MarkerSeverity.Warning: className = "squiggly-warning" /* EditorWarningDecoration */; color = themeColorFromId(overviewRulerWarning); zIndex = 20; break; case MarkerSeverity.Info: className = "squiggly-info" /* EditorInfoDecoration */; color = themeColorFromId(overviewRulerInfo); zIndex = 10; break; case MarkerSeverity.Error: default: className = "squiggly-error" /* EditorErrorDecoration */; color = themeColorFromId(overviewRulerError); zIndex = 30; break; } if (marker.tags) { if (marker.tags.indexOf(1 /* Unnecessary */) !== -1) { inlineClassName = "squiggly-inline-unnecessary" /* EditorUnnecessaryInlineDecoration */; } } var hoverMessage = null; var message = marker.message, source = marker.source, relatedInformation = marker.relatedInformation, code = marker.code; if (typeof message === 'string') { message = message.trim(); if (source) { if (/\n/g.test(message)) { if (code) { message = nls.localize('diagAndSourceAndCodeMultiline', "[{0}]\n{1} [{2}]", source, message, code); } else { message = nls.localize('diagAndSourceMultiline', "[{0}]\n{1}", source, message); } } else { if (code) { message = nls.localize('diagAndSourceAndCode', "[{0}] {1} [{2}]", source, message, code); } else { message = nls.localize('diagAndSource', "[{0}] {1}", source, message); } } } hoverMessage = new MarkdownString().appendCodeblock('_', message); if (!isFalsyOrEmpty(relatedInformation)) { hoverMessage.appendMarkdown('\n'); for (var _i = 0, _a = relatedInformation; _i < _a.length; _i++) { var _b = _a[_i], message_1 = _b.message, resource = _b.resource, startLineNumber = _b.startLineNumber, startColumn = _b.startColumn; hoverMessage.appendMarkdown("* [" + basename(resource.path) + "(" + startLineNumber + ", " + startColumn + ")](" + resource.toString(false) + "#" + startLineNumber + "," + startColumn + "): "); hoverMessage.appendText("" + message_1); hoverMessage.appendMarkdown('\n'); } hoverMessage.appendMarkdown('\n'); } } return { stickiness: 1 /* NeverGrowsWhenTypingAtEdges */, className: className, hoverMessage: hoverMessage, showIfCollapsed: true, overviewRuler: { color: color, position: OverviewRulerLane.Right }, zIndex: zIndex, inlineClassName: inlineClassName, }; }; return ModelMarkerHandler; }()); var DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? 1 /* LF */ : 2 /* CRLF */; var ModelServiceImpl = /** @class */ (function (_super) { __extends(ModelServiceImpl, _super); function ModelServiceImpl(markerService, configurationService, resourcePropertiesService) { var _this = _super.call(this) || this; _this._onModelAdded = _this._register(new Emitter()); _this.onModelAdded = _this._onModelAdded.event; _this._onModelRemoved = _this._register(new Emitter()); _this.onModelRemoved = _this._onModelRemoved.event; _this._onModelModeChanged = _this._register(new Emitter()); _this.onModelModeChanged = _this._onModelModeChanged.event; _this._markerService = markerService; _this._configurationService = configurationService; _this._resourcePropertiesService = resourcePropertiesService; _this._models = {}; _this._modelCreationOptionsByLanguageAndResource = Object.create(null); if (_this._markerService) { _this._markerServiceSubscription = _this._markerService.onMarkerChanged(_this._handleMarkerChange, _this); } _this._configurationServiceSubscription = _this._configurationService.onDidChangeConfiguration(function (e) { return _this._updateModelOptions(); }); _this._updateModelOptions(); return _this; } ModelServiceImpl._readModelOptions = function (config, isForSimpleWidget) { var tabSize = EDITOR_MODEL_DEFAULTS.tabSize; if (config.editor && typeof config.editor.tabSize !== 'undefined') { var parsedTabSize = parseInt(config.editor.tabSize, 10); if (!isNaN(parsedTabSize)) { tabSize = parsedTabSize; } if (tabSize < 1) { tabSize = 1; } } var insertSpaces = EDITOR_MODEL_DEFAULTS.insertSpaces; if (config.editor && typeof config.editor.insertSpaces !== 'undefined') { insertSpaces = (config.editor.insertSpaces === 'false' ? false : Boolean(config.editor.insertSpaces)); } var newDefaultEOL = DEFAULT_EOL; var eol = config.eol; if (eol === '\r\n') { newDefaultEOL = 2 /* CRLF */; } else if (eol === '\n') { newDefaultEOL = 1 /* LF */; } var trimAutoWhitespace = EDITOR_MODEL_DEFAULTS.trimAutoWhitespace; if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') { trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace)); } var detectIndentation = EDITOR_MODEL_DEFAULTS.detectIndentation; if (config.editor && typeof config.editor.detectIndentation !== 'undefined') { detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation)); } var largeFileOptimizations = EDITOR_MODEL_DEFAULTS.largeFileOptimizations; if (config.editor && typeof config.editor.largeFileOptimizations !== 'undefined') { largeFileOptimizations = (config.editor.largeFileOptimizations === 'false' ? false : Boolean(config.editor.largeFileOptimizations)); } return { isForSimpleWidget: isForSimpleWidget, tabSize: tabSize, insertSpaces: insertSpaces, detectIndentation: detectIndentation, defaultEOL: newDefaultEOL, trimAutoWhitespace: trimAutoWhitespace, largeFileOptimizations: largeFileOptimizations }; }; ModelServiceImpl.prototype.getCreationOptions = function (language, resource, isForSimpleWidget) { var creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource]; if (!creationOptions) { var editor = this._configurationService.getValue('editor', { overrideIdentifier: language, resource: resource }); var eol = this._resourcePropertiesService.getEOL(resource, language); creationOptions = ModelServiceImpl._readModelOptions({ editor: editor, eol: eol }, isForSimpleWidget); this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions; } return creationOptions; }; ModelServiceImpl.prototype._updateModelOptions = function () { var oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource; this._modelCreationOptionsByLanguageAndResource = Object.create(null); // Update options on all models var keys = Object.keys(this._models); for (var i = 0, len = keys.length; i < len; i++) { var modelId = keys[i]; var modelData = this._models[modelId]; var language = modelData.model.getLanguageIdentifier().language; var uri = modelData.model.uri; var oldOptions = oldOptionsByLanguageAndResource[language + uri]; var newOptions = this.getCreationOptions(language, uri, modelData.model.isForSimpleWidget); ModelServiceImpl._setModelOptionsForModel(modelData.model, newOptions, oldOptions); } }; ModelServiceImpl._setModelOptionsForModel = function (model, newOptions, currentOptions) { if (currentOptions && (currentOptions.detectIndentation === newOptions.detectIndentation) && (currentOptions.insertSpaces === newOptions.insertSpaces) && (currentOptions.tabSize === newOptions.tabSize) && (currentOptions.trimAutoWhitespace === newOptions.trimAutoWhitespace)) { // Same indent opts, no need to touch the model return; } if (newOptions.detectIndentation) { model.detectIndentation(newOptions.insertSpaces, newOptions.tabSize); model.updateOptions({ trimAutoWhitespace: newOptions.trimAutoWhitespace }); } else { model.updateOptions({ insertSpaces: newOptions.insertSpaces, tabSize: newOptions.tabSize, trimAutoWhitespace: newOptions.trimAutoWhitespace }); } }; ModelServiceImpl.prototype.dispose = function () { if (this._markerServiceSubscription) { this._markerServiceSubscription.dispose(); } this._configurationServiceSubscription.dispose(); _super.prototype.dispose.call(this); }; ModelServiceImpl.prototype._handleMarkerChange = function (changedResources) { var _this = this; changedResources.forEach(function (resource) { var modelId = MODEL_ID(resource); var modelData = _this._models[modelId]; if (!modelData) { return; } ModelMarkerHandler.setMarkers(modelData, _this._markerService); }); }; ModelServiceImpl.prototype._cleanUp = function (model) { var _this = this; // clean up markers for internal, transient models if (model.uri.scheme === network.Schemas.inMemory || model.uri.scheme === network.Schemas.internal || model.uri.scheme === network.Schemas.vscode) { if (this._markerService) { this._markerService.read({ resource: model.uri }).map(function (marker) { return marker.owner; }).forEach(function (owner) { return _this._markerService.remove(owner, [model.uri]); }); } } // clean up cache delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri]; }; // --- begin IModelService ModelServiceImpl.prototype._createModelData = function (value, languageIdentifier, resource, isForSimpleWidget) { var _this = this; // create & save the model var options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget); var model = new TextModel(value, options, languageIdentifier, resource); var modelId = MODEL_ID(model.uri); if (this._models[modelId]) { // There already exists a model with this id => this is a programmer error throw new Error('ModelService: Cannot add model because it already exists!'); } var modelData = new ModelData(model, function (model) { return _this._onWillDispose(model); }, function (model, e) { return _this._onDidChangeLanguage(model, e); }); this._models[modelId] = modelData; return modelData; }; ModelServiceImpl.prototype.createModel = function (value, languageSelection, resource, isForSimpleWidget) { if (isForSimpleWidget === void 0) { isForSimpleWidget = false; } var modelData; if (languageSelection) { modelData = this._createModelData(value, languageSelection.languageIdentifier, resource, isForSimpleWidget); this.setMode(modelData.model, languageSelection); } else { modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget); } // handle markers (marker service => model) if (this._markerService) { ModelMarkerHandler.setMarkers(modelData, this._markerService); } this._onModelAdded.fire(modelData.model); return modelData.model; }; ModelServiceImpl.prototype.setMode = function (model, languageSelection) { if (!languageSelection) { return; } var modelData = this._models[MODEL_ID(model.uri)]; if (!modelData) { return; } modelData.setLanguage(languageSelection); }; ModelServiceImpl.prototype.getModels = function () { var ret = []; var keys = Object.keys(this._models); for (var i = 0, len = keys.length; i < len; i++) { var modelId = keys[i]; ret.push(this._models[modelId].model); } return ret; }; ModelServiceImpl.prototype.getModel = function (resource) { var modelId = MODEL_ID(resource); var modelData = this._models[modelId]; if (!modelData) { return null; } return modelData.model; }; // --- end IModelService ModelServiceImpl.prototype._onWillDispose = function (model) { var modelId = MODEL_ID(model.uri); var modelData = this._models[modelId]; delete this._models[modelId]; modelData.dispose(); this._cleanUp(model); this._onModelRemoved.fire(model); }; ModelServiceImpl.prototype._onDidChangeLanguage = function (model, e) { var oldModeId = e.oldLanguage; var newModeId = model.getLanguageIdentifier().language; var oldOptions = this.getCreationOptions(oldModeId, model.uri, model.isForSimpleWidget); var newOptions = this.getCreationOptions(newModeId, model.uri, model.isForSimpleWidget); ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions); this._onModelModeChanged.fire({ model: model, oldModeId: oldModeId }); }; ModelServiceImpl = __decorate([ __param(0, IMarkerService), __param(1, IConfigurationService), __param(2, ITextResourcePropertiesService) ], ModelServiceImpl); return ModelServiceImpl; }(Disposable)); export { ModelServiceImpl };