mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from master
This commit is contained in:
@@ -2,39 +2,42 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as network from 'vs/base/common/network';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IMarker, IMarkerService, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
|
||||
import { IMode, LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
|
||||
import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { ClassName } from 'vs/editor/common/model/intervalTree';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
import { overviewRulerWarning, overviewRulerError, overviewRulerInfo } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { ITextModel, IModelDeltaDecoration, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, DefaultEndOfLine, ITextModelCreationOptions, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextBufferFactory, ITextBuffer, EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as network from 'vs/base/common/network';
|
||||
import { basename } from 'vs/base/common/paths';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { DefaultEndOfLine, EndOfLinePreference, EndOfLineSequence, IIdentifiedSingleEditOperation, IModelDecorationOptions, IModelDeltaDecoration, ITextBuffer, ITextBufferFactory, ITextModel, ITextModelCreationOptions, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
|
||||
import { ClassName } from 'vs/editor/common/model/intervalTree';
|
||||
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
|
||||
import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { LanguageIdentifier } from 'vs/editor/common/modes';
|
||||
import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { ILanguageSelection } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { overviewRulerError, overviewRulerInfo, overviewRulerWarning } from 'vs/editor/common/view/editorColorRegistry';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IMarker, IMarkerService, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
|
||||
import { ThemeColor, themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
function MODEL_ID(resource: URI): string {
|
||||
return resource.toString();
|
||||
}
|
||||
|
||||
class ModelData implements IDisposable {
|
||||
model: ITextModel;
|
||||
public readonly model: ITextModel;
|
||||
|
||||
private _languageSelection: ILanguageSelection | null;
|
||||
private _languageSelectionListener: IDisposable | null;
|
||||
|
||||
private _markerDecorations: string[];
|
||||
private _modelEventListeners: IDisposable[];
|
||||
@@ -46,6 +49,9 @@ class ModelData implements IDisposable {
|
||||
) {
|
||||
this.model = model;
|
||||
|
||||
this._languageSelection = null;
|
||||
this._languageSelectionListener = null;
|
||||
|
||||
this._markerDecorations = [];
|
||||
|
||||
this._modelEventListeners = [];
|
||||
@@ -53,15 +59,33 @@ class ModelData implements IDisposable {
|
||||
this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
|
||||
}
|
||||
|
||||
private _disposeLanguageSelection(): void {
|
||||
if (this._languageSelectionListener) {
|
||||
this._languageSelectionListener.dispose();
|
||||
this._languageSelectionListener = null;
|
||||
}
|
||||
if (this._languageSelection) {
|
||||
this._languageSelection.dispose();
|
||||
this._languageSelection = null;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
|
||||
this._modelEventListeners = dispose(this._modelEventListeners);
|
||||
this.model = null;
|
||||
this._disposeLanguageSelection();
|
||||
}
|
||||
|
||||
public acceptMarkerDecorations(newDecorations: IModelDeltaDecoration[]): void {
|
||||
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations);
|
||||
}
|
||||
|
||||
public setLanguage(languageSelection: ILanguageSelection): void {
|
||||
this._disposeLanguageSelection();
|
||||
this._languageSelection = languageSelection;
|
||||
this._languageSelectionListener = this._languageSelection.onDidChange(() => this.model.setMode(languageSelection.languageIdentifier));
|
||||
this.model.setMode(languageSelection.languageIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
class ModelMarkerHandler {
|
||||
@@ -73,8 +97,8 @@ class ModelMarkerHandler {
|
||||
|
||||
let newModelDecorations: IModelDeltaDecoration[] = markers.map((marker) => {
|
||||
return {
|
||||
range: this._createDecorationRange(modelData.model, marker),
|
||||
options: this._createDecorationOption(marker)
|
||||
range: ModelMarkerHandler._createDecorationRange(modelData.model, marker),
|
||||
options: ModelMarkerHandler._createDecorationOption(marker)
|
||||
};
|
||||
});
|
||||
|
||||
@@ -85,9 +109,12 @@ class ModelMarkerHandler {
|
||||
|
||||
let ret = Range.lift(rawMarker);
|
||||
|
||||
if (rawMarker.severity === MarkerSeverity.Hint && Range.spansMultipleLines(ret)) {
|
||||
// never render hints on multiple lines
|
||||
ret = ret.setEndPosition(ret.startLineNumber, ret.startColumn);
|
||||
if (rawMarker.severity === MarkerSeverity.Hint) {
|
||||
if (!rawMarker.tags || rawMarker.tags.indexOf(MarkerTag.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);
|
||||
@@ -124,10 +151,9 @@ class ModelMarkerHandler {
|
||||
private static _createDecorationOption(marker: IMarker): IModelDecorationOptions {
|
||||
|
||||
let className: string;
|
||||
let color: ThemeColor;
|
||||
let darkColor: ThemeColor;
|
||||
let color: ThemeColor | undefined = undefined;
|
||||
let zIndex: number;
|
||||
let inlineClassName: string;
|
||||
let inlineClassName: string | undefined = undefined;
|
||||
|
||||
switch (marker.severity) {
|
||||
case MarkerSeverity.Hint:
|
||||
@@ -141,20 +167,17 @@ class ModelMarkerHandler {
|
||||
case MarkerSeverity.Warning:
|
||||
className = ClassName.EditorWarningDecoration;
|
||||
color = themeColorFromId(overviewRulerWarning);
|
||||
darkColor = themeColorFromId(overviewRulerWarning);
|
||||
zIndex = 20;
|
||||
break;
|
||||
case MarkerSeverity.Info:
|
||||
className = ClassName.EditorInfoDecoration;
|
||||
color = themeColorFromId(overviewRulerInfo);
|
||||
darkColor = themeColorFromId(overviewRulerInfo);
|
||||
zIndex = 10;
|
||||
break;
|
||||
case MarkerSeverity.Error:
|
||||
default:
|
||||
className = ClassName.EditorErrorDecoration;
|
||||
color = themeColorFromId(overviewRulerError);
|
||||
darkColor = themeColorFromId(overviewRulerError);
|
||||
zIndex = 30;
|
||||
break;
|
||||
}
|
||||
@@ -165,32 +188,37 @@ class ModelMarkerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
let hoverMessage: MarkdownString = null;
|
||||
let { message, source, relatedInformation } = marker;
|
||||
let hoverMessage: MarkdownString | null = null;
|
||||
let { message, source, relatedInformation, code } = marker;
|
||||
|
||||
if (typeof message === 'string') {
|
||||
message = message.trim();
|
||||
|
||||
hoverMessage = new MarkdownString();
|
||||
// Disable markdown renderer sanitize to allow html
|
||||
// Hence, escape all input strings
|
||||
hoverMessage.sanitize = false;
|
||||
|
||||
hoverMessage.appendMarkdown(`<div>`);
|
||||
hoverMessage.appendMarkdown(`<span style='font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback"; white-space: pre-wrap;'>${escape(message.trim())}</span>`);
|
||||
if (source) {
|
||||
if (/\n/g.test(message)) {
|
||||
message = nls.localize('diagAndSourceMultiline', "[{0}]\n{1}", source, message);
|
||||
} else {
|
||||
message = nls.localize('diagAndSource', "[{0}] {1}", source, message);
|
||||
hoverMessage.appendMarkdown(`<span style='opacity: 0.6; padding-left:6px;'>${escape(source)}</span>`);
|
||||
if (code) {
|
||||
hoverMessage.appendMarkdown(`<span style='opacity: 0.6; padding-left:2px;'>(${escape(code)})</span>`);
|
||||
}
|
||||
} else if (code) {
|
||||
hoverMessage.appendMarkdown(`<span style='opacity: 0.6; padding-left:6px;'>(${escape(code)})</span>`);
|
||||
}
|
||||
hoverMessage.appendMarkdown(`</div>`);
|
||||
|
||||
hoverMessage = new MarkdownString().appendCodeblock('_', message);
|
||||
|
||||
if (!isFalsyOrEmpty(relatedInformation)) {
|
||||
hoverMessage.appendMarkdown('\n');
|
||||
if (isNonEmptyArray(relatedInformation)) {
|
||||
hoverMessage.appendMarkdown(`<ul>`);
|
||||
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
|
||||
hoverMessage.appendMarkdown(
|
||||
`* [${basename(resource.path)}(${startLineNumber}, ${startColumn})](${resource.toString(false)}#${startLineNumber},${startColumn}): `
|
||||
);
|
||||
hoverMessage.appendText(`${message}`);
|
||||
hoverMessage.appendMarkdown('\n');
|
||||
hoverMessage.appendMarkdown(`<li>`);
|
||||
hoverMessage.appendMarkdown(`<a href='#' data-href='${resource.toString(false)}#${startLineNumber},${startColumn}'>${escape(basename(resource.path))}(${startLineNumber}, ${startColumn})</a>`);
|
||||
hoverMessage.appendMarkdown(`<span>: ${escape(message)}</span>`);
|
||||
hoverMessage.appendMarkdown(`</li>`);
|
||||
}
|
||||
hoverMessage.appendMarkdown('\n');
|
||||
hoverMessage.appendMarkdown(`</ul>`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +229,6 @@ class ModelMarkerHandler {
|
||||
showIfCollapsed: true,
|
||||
overviewRuler: {
|
||||
color,
|
||||
darkColor,
|
||||
position: OverviewRulerLane.Right
|
||||
},
|
||||
zIndex,
|
||||
@@ -210,33 +237,39 @@ class ModelMarkerHandler {
|
||||
}
|
||||
}
|
||||
|
||||
interface IRawEditorConfig {
|
||||
tabSize?: any;
|
||||
insertSpaces?: any;
|
||||
detectIndentation?: any;
|
||||
trimAutoWhitespace?: any;
|
||||
creationOptions?: any;
|
||||
largeFileOptimizations?: any;
|
||||
}
|
||||
|
||||
interface IRawConfig {
|
||||
files?: {
|
||||
eol?: any;
|
||||
};
|
||||
editor?: {
|
||||
tabSize?: any;
|
||||
insertSpaces?: any;
|
||||
detectIndentation?: any;
|
||||
trimAutoWhitespace?: any;
|
||||
creationOptions?: any;
|
||||
largeFileOptimizations?: any;
|
||||
};
|
||||
eol?: any;
|
||||
editor?: IRawEditorConfig;
|
||||
}
|
||||
|
||||
const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLine.LF : DefaultEndOfLine.CRLF;
|
||||
|
||||
export class ModelServiceImpl implements IModelService {
|
||||
export class ModelServiceImpl extends Disposable implements IModelService {
|
||||
public _serviceBrand: any;
|
||||
|
||||
private _markerService: IMarkerService;
|
||||
private _markerServiceSubscription: IDisposable;
|
||||
private _configurationService: IConfigurationService;
|
||||
private _configurationServiceSubscription: IDisposable;
|
||||
private _resourcePropertiesService: ITextResourcePropertiesService;
|
||||
|
||||
private readonly _onModelAdded: Emitter<ITextModel>;
|
||||
private readonly _onModelRemoved: Emitter<ITextModel>;
|
||||
private readonly _onModelModeChanged: Emitter<{ model: ITextModel; oldModeId: string; }>;
|
||||
private readonly _onModelAdded: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
|
||||
public readonly onModelAdded: Event<ITextModel> = this._onModelAdded.event;
|
||||
|
||||
private readonly _onModelRemoved: Emitter<ITextModel> = this._register(new Emitter<ITextModel>());
|
||||
public readonly onModelRemoved: Event<ITextModel> = this._onModelRemoved.event;
|
||||
|
||||
private readonly _onModelModeChanged: Emitter<{ model: ITextModel; oldModeId: string; }> = this._register(new Emitter<{ model: ITextModel; oldModeId: string; }>({ leakWarningThreshold: 500 }));
|
||||
public readonly onModelModeChanged: Event<{ model: ITextModel; oldModeId: string; }> = this._onModelModeChanged.event;
|
||||
|
||||
private _modelCreationOptionsByLanguageAndResource: {
|
||||
[languageAndResource: string]: ITextModelCreationOptions;
|
||||
@@ -250,14 +283,14 @@ export class ModelServiceImpl implements IModelService {
|
||||
constructor(
|
||||
@IMarkerService markerService: IMarkerService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService,
|
||||
) {
|
||||
super();
|
||||
this._markerService = markerService;
|
||||
this._configurationService = configurationService;
|
||||
this._resourcePropertiesService = resourcePropertiesService;
|
||||
this._models = {};
|
||||
this._modelCreationOptionsByLanguageAndResource = Object.create(null);
|
||||
this._onModelAdded = new Emitter<ITextModel>();
|
||||
this._onModelRemoved = new Emitter<ITextModel>();
|
||||
this._onModelModeChanged = new Emitter<{ model: ITextModel; oldModeId: string; }>();
|
||||
|
||||
if (this._markerService) {
|
||||
this._markerServiceSubscription = this._markerService.onMarkerChanged(this._handleMarkerChange, this);
|
||||
@@ -285,7 +318,7 @@ export class ModelServiceImpl implements IModelService {
|
||||
}
|
||||
|
||||
let newDefaultEOL = DEFAULT_EOL;
|
||||
const eol = config.files && config.files.eol;
|
||||
const eol = config.eol;
|
||||
if (eol === '\r\n') {
|
||||
newDefaultEOL = DefaultEndOfLine.CRLF;
|
||||
} else if (eol === '\n') {
|
||||
@@ -321,7 +354,9 @@ export class ModelServiceImpl implements IModelService {
|
||||
public getCreationOptions(language: string, resource: URI, isForSimpleWidget: boolean): ITextModelCreationOptions {
|
||||
let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
|
||||
if (!creationOptions) {
|
||||
creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getValue({ overrideIdentifier: language, resource }), isForSimpleWidget);
|
||||
const editor = this._configurationService.getValue<IRawEditorConfig>('editor', { overrideIdentifier: language, resource });
|
||||
const eol = this._resourcePropertiesService.getEOL(resource, language);
|
||||
creationOptions = ModelServiceImpl._readModelOptions({ editor, eol }, isForSimpleWidget);
|
||||
this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions;
|
||||
}
|
||||
return creationOptions;
|
||||
@@ -374,6 +409,7 @@ export class ModelServiceImpl implements IModelService {
|
||||
this._markerServiceSubscription.dispose();
|
||||
}
|
||||
this._configurationServiceSubscription.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private _handleMarkerChange(changedResources: URI[]): void {
|
||||
@@ -494,14 +530,14 @@ export class ModelServiceImpl implements IModelService {
|
||||
return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
|
||||
}
|
||||
|
||||
public createModel(value: string | ITextBufferFactory, modeOrPromise: TPromise<IMode> | IMode, resource: URI, isForSimpleWidget: boolean = false): ITextModel {
|
||||
public createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource: URI, isForSimpleWidget: boolean = false): ITextModel {
|
||||
let modelData: ModelData;
|
||||
|
||||
if (!modeOrPromise || TPromise.is(modeOrPromise)) {
|
||||
modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget);
|
||||
this.setMode(modelData.model, modeOrPromise);
|
||||
if (languageSelection) {
|
||||
modelData = this._createModelData(value, languageSelection.languageIdentifier, resource, isForSimpleWidget);
|
||||
this.setMode(modelData.model, languageSelection);
|
||||
} else {
|
||||
modelData = this._createModelData(value, modeOrPromise.getLanguageIdentifier(), resource, isForSimpleWidget);
|
||||
modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget);
|
||||
}
|
||||
|
||||
// handle markers (marker service => model)
|
||||
@@ -514,19 +550,15 @@ export class ModelServiceImpl implements IModelService {
|
||||
return modelData.model;
|
||||
}
|
||||
|
||||
public setMode(model: ITextModel, modeOrPromise: TPromise<IMode> | IMode): void {
|
||||
if (!modeOrPromise) {
|
||||
public setMode(model: ITextModel, languageSelection: ILanguageSelection): void {
|
||||
if (!languageSelection) {
|
||||
return;
|
||||
}
|
||||
if (TPromise.is(modeOrPromise)) {
|
||||
modeOrPromise.then((mode) => {
|
||||
if (!model.isDisposed()) {
|
||||
model.setMode(mode.getLanguageIdentifier());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
model.setMode(modeOrPromise.getLanguageIdentifier());
|
||||
let modelData = this._models[MODEL_ID(model.uri)];
|
||||
if (!modelData) {
|
||||
return;
|
||||
}
|
||||
modelData.setLanguage(languageSelection);
|
||||
}
|
||||
|
||||
public destroyModel(resource: URI): void {
|
||||
@@ -550,7 +582,7 @@ export class ModelServiceImpl implements IModelService {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public getModel(resource: URI): ITextModel {
|
||||
public getModel(resource: URI): ITextModel | null {
|
||||
let modelId = MODEL_ID(resource);
|
||||
let modelData = this._models[modelId];
|
||||
if (!modelData) {
|
||||
@@ -559,18 +591,6 @@ export class ModelServiceImpl implements IModelService {
|
||||
return modelData.model;
|
||||
}
|
||||
|
||||
public get onModelAdded(): Event<ITextModel> {
|
||||
return this._onModelAdded ? this._onModelAdded.event : null;
|
||||
}
|
||||
|
||||
public get onModelRemoved(): Event<ITextModel> {
|
||||
return this._onModelRemoved ? this._onModelRemoved.event : null;
|
||||
}
|
||||
|
||||
public get onModelModeChanged(): Event<{ model: ITextModel; oldModeId: string; }> {
|
||||
return this._onModelModeChanged ? this._onModelModeChanged.event : null;
|
||||
}
|
||||
|
||||
// --- end IModelService
|
||||
|
||||
private _onWillDispose(model: ITextModel): void {
|
||||
|
||||
Reference in New Issue
Block a user