提交 21ad2c89 编写于 作者: D Daniel Imms

Merge remote-tracking branch 'origin/master' into pr/usernamehw/66179

......@@ -26,7 +26,7 @@ export class PackageJSONContribution implements IJSONContribution {
'shelljs', 'gulp', 'yargs', 'browserify', 'minimatch', 'react', 'less', 'prompt', 'inquirer', 'ws', 'event-stream', 'inherits', 'mysql', 'esprima',
'jsdom', 'stylus', 'when', 'readable-stream', 'aws-sdk', 'concat-stream', 'chai', 'Thenable', 'wrench'];
private knownScopes = ['@types', '@angular'];
private knownScopes = ['@types', '@angular', '@babel', '@nuxtjs', '@vue', '@bazel'];
private xhr: XHRRequest;
public getDocumentSelector(): DocumentSelector {
......@@ -163,7 +163,11 @@ export class PackageJSONContribution implements IJSONContribution {
}
} else if (segments.length === 2 && segments[0].length > 1) {
let scope = segments[0].substr(1);
let queryUrl = `https://registry.npmjs.org/-/v1/search?text=scope:${scope}%20${segments[1]}&size=${SCOPED_LIMIT}&popularity=1.0`;
let name = segments[1];
if (name.length < 4) {
name = '';
}
let queryUrl = `https://api.npms.io/v2/search?q=scope:${scope}%20${name}&size=250`;
return this.xhr({
url: queryUrl,
agent: USER_AGENT
......@@ -171,8 +175,8 @@ export class PackageJSONContribution implements IJSONContribution {
if (success.status === 200) {
try {
const obj = JSON.parse(success.responseText);
if (obj && Array.isArray(obj.objects)) {
const objects = <{ package: { name: string; version: string, description: string; } }[]>obj.objects;
if (obj && Array.isArray(obj.results)) {
const objects = <{ package: { name: string; version: string, description: string; } }[]>obj.results;
for (let object of objects) {
if (object.package && object.package.name) {
const name = object.package.name;
......
......@@ -6,7 +6,7 @@
import * as DOM from 'vs/base/browser/dom';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { escape } from 'vs/base/common/strings';
import { removeMarkdownEscapes, IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
import { removeMarkdownEscapes, IMarkdownString } from 'vs/base/common/htmlContent';
import * as marked from 'vs/base/common/marked/marked';
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { IDisposable } from 'vs/base/common/lifecycle';
......@@ -211,7 +211,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions
}
const markedOptions: marked.MarkedOptions = {
sanitize: markdown instanceof MarkdownString ? markdown.sanitize : true,
sanitize: true,
renderer
};
......
......@@ -16,7 +16,6 @@ export class MarkdownString implements IMarkdownString {
value: string;
isTrusted?: boolean;
sanitize: boolean = true;
constructor(value: string = '') {
this.value = value;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IMarkerService, IMarker, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IModelDeltaDecoration, ITextModel, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, IModelDecoration } from 'vs/editor/common/model';
import { ClassName } from 'vs/editor/common/model/intervalTree';
import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService';
import { overviewRulerWarning, overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry';
import { IModelService } from 'vs/editor/common/services/modelService';
import { Range } from 'vs/editor/common/core/range';
import { keys } from 'vs/base/common/map';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { Schemas } from 'vs/base/common/network';
function MODEL_ID(resource: URI): string {
return resource.toString();
}
class MarkerDecorations extends Disposable {
private readonly _markersData: Map<string, IMarker> = new Map<string, IMarker>();
constructor(
readonly model: ITextModel
) {
super();
this._register(toDisposable(() => {
this.model.deltaDecorations(keys(this._markersData), []);
this._markersData.clear();
}));
}
public update(markers: IMarker[], newDecorations: IModelDeltaDecoration[]): void {
const ids = this.model.deltaDecorations(keys(this._markersData), newDecorations);
for (let index = 0; index < ids.length; index++) {
this._markersData.set(ids[index], markers[index]);
}
}
getMarker(decoration: IModelDecoration): IMarker | null {
return this._markersData.get(decoration.id);
}
}
export class MarkerDecorationsService extends Disposable implements IMarkerDecorationsService {
_serviceBrand: any;
private readonly _markerDecorations: Map<string, MarkerDecorations> = new Map<string, MarkerDecorations>();
constructor(
@IModelService modelService: IModelService,
@IMarkerService private readonly _markerService: IMarkerService
) {
super();
modelService.getModels().forEach(model => this._onModelAdded(model));
this._register(modelService.onModelAdded(this._onModelAdded, this));
this._register(modelService.onModelRemoved(this._onModelRemoved, this));
this._register(this._markerService.onMarkerChanged(this._handleMarkerChange, this));
}
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null {
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
return markerDecorations ? markerDecorations.getMarker(decoration) : null;
}
private _handleMarkerChange(changedResources: URI[]): void {
changedResources.forEach((resource) => {
const markerDecorations = this._markerDecorations.get(MODEL_ID(resource));
if (markerDecorations) {
this.updateDecorations(markerDecorations);
}
});
}
private _onModelAdded(model: ITextModel): void {
const markerDecorations = new MarkerDecorations(model);
this._markerDecorations.set(MODEL_ID(model.uri), markerDecorations);
this.updateDecorations(markerDecorations);
}
private _onModelRemoved(model: ITextModel): void {
const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri));
if (markerDecorations) {
markerDecorations.dispose();
this._markerDecorations.delete(MODEL_ID(model.uri));
}
// clean up markers for internal, transient models
if (model.uri.scheme === Schemas.inMemory
|| model.uri.scheme === Schemas.internal
|| model.uri.scheme === Schemas.vscode) {
if (this._markerService) {
this._markerService.read({ resource: model.uri }).map(marker => marker.owner).forEach(owner => this._markerService.remove(owner, [model.uri]));
}
}
}
private updateDecorations(markerDecorations: MarkerDecorations): void {
// Limit to the first 500 errors/warnings
const markers = this._markerService.read({ resource: markerDecorations.model.uri, take: 500 });
let newModelDecorations: IModelDeltaDecoration[] = markers.map((marker) => {
return {
range: this._createDecorationRange(markerDecorations.model, marker),
options: this._createDecorationOption(marker)
};
});
markerDecorations.update(markers, newModelDecorations);
}
private _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range {
let ret = Range.lift(rawMarker);
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);
if (ret.isEmpty()) {
let word = model.getWordAtPosition(ret.getStartPosition());
if (word) {
ret = new Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn);
} else {
let 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) {
let minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
if (minColumn < ret.endColumn) {
ret = new Range(ret.startLineNumber, minColumn, ret.endLineNumber, ret.endColumn);
rawMarker.startColumn = minColumn;
}
}
return ret;
}
private _createDecorationOption(marker: IMarker): IModelDecorationOptions {
let className: string;
let color: ThemeColor | undefined = undefined;
let zIndex: number;
let inlineClassName: string | undefined = undefined;
switch (marker.severity) {
case MarkerSeverity.Hint:
if (marker.tags && marker.tags.indexOf(MarkerTag.Unnecessary) >= 0) {
className = ClassName.EditorUnnecessaryDecoration;
} else {
className = ClassName.EditorHintDecoration;
}
zIndex = 0;
break;
case MarkerSeverity.Warning:
className = ClassName.EditorWarningDecoration;
color = themeColorFromId(overviewRulerWarning);
zIndex = 20;
break;
case MarkerSeverity.Info:
className = ClassName.EditorInfoDecoration;
color = themeColorFromId(overviewRulerInfo);
zIndex = 10;
break;
case MarkerSeverity.Error:
default:
className = ClassName.EditorErrorDecoration;
color = themeColorFromId(overviewRulerError);
zIndex = 30;
break;
}
if (marker.tags) {
if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) {
inlineClassName = ClassName.EditorUnnecessaryInlineDecoration;
}
}
return {
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
className,
showIfCollapsed: true,
overviewRuler: {
color,
position: OverviewRulerLane.Right
},
zIndex,
inlineClassName,
};
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITextModel, IModelDecoration } from 'vs/editor/common/model';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IMarker } from 'vs/platform/markers/common/markers';
export const IMarkerDecorationsService = createDecorator<IMarkerDecorationsService>('markerDecorationsService');
export interface IMarkerDecorationsService {
_serviceBrand: any;
getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null;
}
\ No newline at end of file
......@@ -3,20 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { Emitter, Event } from 'vs/base/common/event';
import { MarkdownString } from 'vs/base/common/htmlContent';
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 { DefaultEndOfLine, EndOfLinePreference, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextBuffer, ITextBufferFactory, ITextModel, ITextModelCreationOptions } from 'vs/editor/common/model';
import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel';
import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { LanguageIdentifier } from 'vs/editor/common/modes';
......@@ -24,10 +18,7 @@ import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegis
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();
......@@ -39,7 +30,6 @@ class ModelData implements IDisposable {
private _languageSelection: ILanguageSelection | null;
private _languageSelectionListener: IDisposable | null;
private _markerDecorations: string[];
private _modelEventListeners: IDisposable[];
constructor(
......@@ -52,8 +42,6 @@ class ModelData implements IDisposable {
this._languageSelection = null;
this._languageSelectionListener = null;
this._markerDecorations = [];
this._modelEventListeners = [];
this._modelEventListeners.push(model.onWillDispose(() => onWillDispose(model)));
this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
......@@ -71,15 +59,10 @@ class ModelData implements IDisposable {
}
public dispose(): void {
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
this._modelEventListeners = dispose(this._modelEventListeners);
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;
......@@ -88,155 +71,6 @@ class ModelData implements IDisposable {
}
}
class ModelMarkerHandler {
public static setMarkers(modelData: ModelData, markerService: IMarkerService): void {
// Limit to the first 500 errors/warnings
const markers = markerService.read({ resource: modelData.model.uri, take: 500 });
let newModelDecorations: IModelDeltaDecoration[] = markers.map((marker) => {
return {
range: ModelMarkerHandler._createDecorationRange(modelData.model, marker),
options: ModelMarkerHandler._createDecorationOption(marker)
};
});
modelData.acceptMarkerDecorations(newModelDecorations);
}
private static _createDecorationRange(model: ITextModel, rawMarker: IMarker): Range {
let ret = Range.lift(rawMarker);
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);
if (ret.isEmpty()) {
let word = model.getWordAtPosition(ret.getStartPosition());
if (word) {
ret = new Range(ret.startLineNumber, word.startColumn, ret.endLineNumber, word.endColumn);
} else {
let 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) {
let minColumn = model.getLineFirstNonWhitespaceColumn(rawMarker.startLineNumber);
if (minColumn < ret.endColumn) {
ret = new Range(ret.startLineNumber, minColumn, ret.endLineNumber, ret.endColumn);
rawMarker.startColumn = minColumn;
}
}
return ret;
}
private static _createDecorationOption(marker: IMarker): IModelDecorationOptions {
let className: string;
let color: ThemeColor | undefined = undefined;
let zIndex: number;
let inlineClassName: string | undefined = undefined;
switch (marker.severity) {
case MarkerSeverity.Hint:
if (marker.tags && marker.tags.indexOf(MarkerTag.Unnecessary) >= 0) {
className = ClassName.EditorUnnecessaryDecoration;
} else {
className = ClassName.EditorHintDecoration;
}
zIndex = 0;
break;
case MarkerSeverity.Warning:
className = ClassName.EditorWarningDecoration;
color = themeColorFromId(overviewRulerWarning);
zIndex = 20;
break;
case MarkerSeverity.Info:
className = ClassName.EditorInfoDecoration;
color = themeColorFromId(overviewRulerInfo);
zIndex = 10;
break;
case MarkerSeverity.Error:
default:
className = ClassName.EditorErrorDecoration;
color = themeColorFromId(overviewRulerError);
zIndex = 30;
break;
}
if (marker.tags) {
if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) {
inlineClassName = ClassName.EditorUnnecessaryInlineDecoration;
}
}
let hoverMessage: MarkdownString | null = null;
let { message, source, relatedInformation, code } = marker;
if (typeof message === 'string') {
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) {
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>`);
if (isNonEmptyArray(relatedInformation)) {
hoverMessage.appendMarkdown(`<ul>`);
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
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(`</ul>`);
}
}
return {
stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,
className,
hoverMessage,
showIfCollapsed: true,
overviewRuler: {
color,
position: OverviewRulerLane.Right
},
zIndex,
inlineClassName,
};
}
}
interface IRawEditorConfig {
tabSize?: any;
insertSpaces?: any;
......@@ -256,8 +90,6 @@ const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? DefaultEndOfLin
export class ModelServiceImpl extends Disposable implements IModelService {
public _serviceBrand: any;
private _markerService: IMarkerService | null;
private _markerServiceSubscription: IDisposable;
private _configurationService: IConfigurationService;
private _configurationServiceSubscription: IDisposable;
private _resourcePropertiesService: ITextResourcePropertiesService;
......@@ -281,22 +113,15 @@ export class ModelServiceImpl extends Disposable implements IModelService {
private _models: { [modelId: string]: ModelData; };
constructor(
@IMarkerService markerService: IMarkerService | null,
@IConfigurationService configurationService: IConfigurationService,
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService,
@ITextResourcePropertiesService resourcePropertiesService: ITextResourcePropertiesService
) {
super();
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._handleMarkerChange(this._markerService.read().map(m => m.resource));
}
this._configurationServiceSubscription = this._configurationService.onDidChangeConfiguration(e => this._updateModelOptions());
this._updateModelOptions();
}
......@@ -406,38 +231,10 @@ export class ModelServiceImpl extends Disposable implements IModelService {
}
public dispose(): void {
if (this._markerServiceSubscription) {
this._markerServiceSubscription.dispose();
}
this._configurationServiceSubscription.dispose();
super.dispose();
}
private _handleMarkerChange(changedResources: URI[]): void {
changedResources.forEach((resource) => {
let modelId = MODEL_ID(resource);
let modelData = this._models[modelId];
if (!modelData) {
return;
}
ModelMarkerHandler.setMarkers(modelData, this._markerService!);
});
}
private _cleanUp(model: ITextModel): void {
// 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(marker => marker.owner).forEach(owner => this._markerService!.remove(owner, [model.uri]));
}
}
// clean up cache
delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri];
}
// --- begin IModelService
private _createModelData(value: string | ITextBufferFactory, languageIdentifier: LanguageIdentifier, resource: URI | null | undefined, isForSimpleWidget: boolean): ModelData {
......@@ -541,11 +338,6 @@ export class ModelServiceImpl extends Disposable implements IModelService {
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;
......@@ -601,7 +393,9 @@ export class ModelServiceImpl extends Disposable implements IModelService {
delete this._models[modelId];
modelData.dispose();
this._cleanUp(model);
// clean up cache
delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri];
this._onModelRemoved.fire(model);
}
......
......@@ -24,6 +24,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCodeBlockBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
export class ModesHoverController implements IEditorContribution {
......@@ -61,6 +62,7 @@ export class ModesHoverController implements IEditorContribution {
constructor(private readonly _editor: ICodeEditor,
@IOpenerService private readonly _openerService: IOpenerService,
@IModeService private readonly _modeService: IModeService,
@IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService,
@IThemeService private readonly _themeService: IThemeService
) {
this._toUnhook = [];
......@@ -204,7 +206,7 @@ export class ModesHoverController implements IEditorContribution {
private _createHoverWidget() {
const renderer = new MarkdownRenderer(this._editor, this._modeService, this._openerService);
this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._themeService);
this._contentWidget = new ModesContentHoverWidget(this._editor, renderer, this._markerDecorationsService, this._themeService);
this._glyphWidget = new ModesGlyphHoverWidget(this._editor, renderer);
}
......
......@@ -13,7 +13,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { DocumentColorProvider, Hover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes';
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes';
import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';
import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';
......@@ -23,7 +23,10 @@ import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contri
import { ContentHoverWidget } from 'vs/editor/contrib/hover/hoverWidgets';
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { coalesce } from 'vs/base/common/arrays';
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { IMarker, IMarkerData } from 'vs/platform/markers/common/markers';
import { basename } from 'vs/base/common/paths';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
const $ = dom.$;
......@@ -36,7 +39,15 @@ class ColorHover {
) { }
}
type HoverPart = Hover | ColorHover;
class MarkerHover {
constructor(
public readonly range: IRange,
public readonly marker: IMarker,
) { }
}
type HoverPart = MarkdownHover | ColorHover | MarkerHover;
class ModesContentComputer implements IHoverComputer<HoverPart[]> {
......@@ -44,7 +55,10 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
private _result: HoverPart[];
private _range: Range | null;
constructor(editor: ICodeEditor) {
constructor(
editor: ICodeEditor,
private _markerDecorationsService: IMarkerDecorationsService
) {
this._editor = editor;
this._range = null;
}
......@@ -80,6 +94,7 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
return [];
}
const model = this._editor.getModel();
const lineNumber = this._range.startLineNumber;
if (lineNumber > this._editor.getModel().getLineCount()) {
......@@ -88,7 +103,7 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
}
const colorDetector = ColorDetector.get(this._editor);
const maxColumn = this._editor.getModel().getLineMaxColumn(lineNumber);
const maxColumn = model.getLineMaxColumn(lineNumber);
const lineDecorations = this._editor.getLineDecorations(lineNumber);
let didFindColor = false;
......@@ -102,6 +117,11 @@ class ModesContentComputer implements IHoverComputer<HoverPart[]> {
}
const range = new Range(hoverRange.startLineNumber, startColumn, hoverRange.startLineNumber, endColumn);
const marker = this._markerDecorationsService.getMarker(model, d);
if (marker) {
return new MarkerHover(range, marker);
}
const colorData = colorDetector.getColorData(d.range.getStartPosition());
if (!didFindColor && colorData) {
......@@ -182,13 +202,14 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
constructor(
editor: ICodeEditor,
markdownRenderer: MarkdownRenderer,
markerDecorationsService: IMarkerDecorationsService,
private readonly _themeService: IThemeService
) {
super(ModesContentHoverWidget.ID, editor);
this._messages = [];
this._lastRange = null;
this._computer = new ModesContentComputer(this._editor);
this._computer = new ModesContentComputer(this._editor, markerDecorationsService);
this._highlightDecorations = [];
this._isChangingDecorations = false;
......@@ -328,16 +349,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
renderColumn = Math.min(renderColumn, msg.range.startColumn);
highlightRange = highlightRange ? Range.plusRange(highlightRange, msg.range) : Range.lift(msg.range);
if (!(msg instanceof ColorHover)) {
msg.contents
.filter(contents => !isEmptyMarkdownString(contents))
.forEach(contents => {
const renderedContents = this._markdownRenderer.render(contents);
markdownDisposeable = renderedContents;
fragment.appendChild($('div.hover-row', undefined, renderedContents.element));
isEmptyHoverContent = false;
});
} else {
if (msg instanceof ColorHover) {
containColorPicker = true;
const { red, green, blue, alpha } = msg.color;
......@@ -420,6 +432,20 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
this.renderDisposable = combinedDisposable([colorListener, colorChangeListener, widget, markdownDisposeable]);
});
} else {
if (msg instanceof MarkerHover) {
isEmptyHoverContent = false;
fragment.appendChild($('div.hover-row', undefined, this.renderMarkerHover(msg)));
} else {
msg.contents
.filter(contents => !isEmptyMarkdownString(contents))
.forEach(contents => {
const renderedContents = this._markdownRenderer.render(contents);
markdownDisposeable = renderedContents;
fragment.appendChild($('div.hover-row', undefined, renderedContents.element));
isEmptyHoverContent = false;
});
}
}
});
......@@ -438,6 +464,36 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
this._isChangingDecorations = false;
}
private renderMarkerHover(markerHover: MarkerHover): HTMLElement {
const hoverElement = $('div');
const { source, message, code, relatedInformation } = markerHover.marker;
const messageElement = dom.append(hoverElement, $('span'));
messageElement.style.whiteSpace = 'pre-wrap';
messageElement.innerText = message.trim();
this._editor.applyFontInfo(messageElement);
if (source || code) {
const detailsElement = dom.append(hoverElement, $('span'));
detailsElement.style.opacity = '0.6';
detailsElement.style.paddingLeft = '6px';
detailsElement.innerText = source && code ? `${source}(${code})` : `(${code})`;
}
if (isNonEmptyArray(relatedInformation)) {
const listElement = dom.append(hoverElement, $('ul'));
for (const { message, resource, startLineNumber, startColumn } of relatedInformation) {
const item = dom.append(listElement, $('li'));
const a = dom.append(item, $('a'));
a.setAttribute('data-href', `${resource.toString(false)}#${startLineNumber},${startColumn}`);
a.innerText = `${basename(resource.path)}(${startLineNumber}, ${startColumn})`;
const messageElement = dom.append<HTMLAnchorElement>(item, $('span'));
messageElement.innerText = `: ${message}`;
}
}
return hoverElement;
}
private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({
className: 'hoverHighlight'
});
......@@ -450,10 +506,13 @@ function hoverContentsEquals(first: HoverPart[], second: HoverPart[]): boolean {
for (let i = 0; i < first.length; i++) {
const firstElement = first[i];
const secondElement = second[i];
if (firstElement instanceof ColorHover) {
if (firstElement instanceof MarkerHover && secondElement instanceof MarkerHover) {
return IMarkerData.makeKey(firstElement.marker) === IMarkerData.makeKey(secondElement.marker);
}
if (firstElement instanceof ColorHover || secondElement instanceof ColorHover) {
return false;
}
if (secondElement instanceof ColorHover) {
if (firstElement instanceof MarkerHover || secondElement instanceof MarkerHover) {
return false;
}
if (!markedStringsEquals(firstElement.contents, secondElement.contents)) {
......
......@@ -15,7 +15,6 @@ import { javascriptOnEnterRules } from 'vs/editor/test/common/modes/supports/jav
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { isLinux, isMacintosh } from 'vs/base/common/platform';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections';
import { provideSelectionRanges } from 'vs/editor/contrib/smartSelect/smartSelect';
import { CancellationToken } from 'vs/base/common/cancellation';
......@@ -66,7 +65,7 @@ suite('SmartSelect', () => {
setup(() => {
const configurationService = new TestConfigurationService();
modelService = new ModelServiceImpl(new MarkerService(), configurationService, new TestTextResourcePropertiesService(configurationService));
modelService = new ModelServiceImpl(configurationService, new TestTextResourcePropertiesService(configurationService));
mode = new MockJSMode();
});
......
......@@ -42,6 +42,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { MenuService } from 'vs/platform/actions/common/menuService';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl';
export interface IEditorOverrideServices {
[index: string]: any;
......@@ -133,7 +135,9 @@ export module StaticServices {
export const modeService = define(IModeService, (o) => new ModeServiceImpl());
export const modelService = define(IModelService, (o) => new ModelServiceImpl(markerService.get(o), configurationService.get(o), resourcePropertiesService.get(o)));
export const modelService = define(IModelService, (o) => new ModelServiceImpl(configurationService.get(o), resourcePropertiesService.get(o)));
export const markerDecorationsService = define(IMarkerDecorationsService, (o) => new MarkerDecorationsService(modelService.get(o), markerService.get(o)));
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o)));
......
......@@ -27,7 +27,7 @@ suite('ModelService', () => {
configService.setUserConfiguration('files', { 'eol': '\n' });
configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot'));
modelService = new ModelServiceImpl(null, configService, new TestTextResourcePropertiesService(configService));
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService));
});
teardown(() => {
......
......@@ -596,7 +596,7 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
}
// after tests have run, we shutdown the host
this._gracefulExit(failures && failures > 0 ? 1 /* ERROR */ : 0 /* OK */);
this._gracefulExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
});
});
}
......
......@@ -104,6 +104,8 @@ import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/el
import { MultiExtensionManagementService } from 'vs/platform/extensionManagement/node/multiExtensionManagement';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService';
import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService';
import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl';
/**
* Services that we require for the Shell
......@@ -488,6 +490,7 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService, undefined, true));
serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl));
serviceCollection.set(ITextResourceConfigurationService, new SyncDescriptor(TextResourceConfigurationService));
......@@ -496,6 +499,8 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IModelService, new SyncDescriptor(ModelServiceImpl, undefined, true));
serviceCollection.set(IMarkerDecorationsService, new SyncDescriptor(MarkerDecorationsService));
serviceCollection.set(IEditorWorkerService, new SyncDescriptor(EditorWorkerServiceImpl));
serviceCollection.set(IUntitledEditorService, new SyncDescriptor(UntitledEditorService, undefined, true));
......
......@@ -42,7 +42,7 @@ suite('MainThreadDocumentsAndEditors', () => {
deltas.length = 0;
const configService = new TestConfigurationService();
configService.setUserConfiguration('editor', { 'detectIndentation': false });
modelService = new ModelServiceImpl(null, configService, new TestTextResourcePropertiesService(configService));
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService));
codeEditorService = new TestCodeEditorService();
textFileService = new class extends mock<ITextFileService>() {
isDirty() { return false; }
......
......@@ -41,7 +41,7 @@ suite('MainThreadEditors', () => {
setup(() => {
const configService = new TestConfigurationService();
modelService = new ModelServiceImpl(null, configService, new TestTextResourcePropertiesService(configService));
modelService = new ModelServiceImpl(configService, new TestTextResourcePropertiesService(configService));
const codeEditorService = new TestCodeEditorService();
movedResources.clear();
......
......@@ -72,7 +72,7 @@ suite.skip('QuickOpen performance (integration)', () => {
[ITelemetryService, telemetryService],
[IConfigurationService, configurationService],
[ITextResourcePropertiesService, textResourcePropertiesService],
[IModelService, new ModelServiceImpl(null, configurationService, textResourcePropertiesService)],
[IModelService, new ModelServiceImpl(configurationService, textResourcePropertiesService)],
[IWorkspaceContextService, new TestContextService(testWorkspace(URI.file(testWorkspacePath)))],
[IEditorService, new TestEditorService()],
[IEditorGroupsService, new TestEditorGroupsService()],
......
......@@ -62,7 +62,7 @@ suite.skip('TextSearch performance (integration)', () => {
[ITelemetryService, telemetryService],
[IConfigurationService, configurationService],
[ITextResourcePropertiesService, textResourcePropertiesService],
[IModelService, new ModelServiceImpl(null, configurationService, textResourcePropertiesService)],
[IModelService, new ModelServiceImpl(configurationService, textResourcePropertiesService)],
[IWorkspaceContextService, new TestContextService(testWorkspace(URI.file(testWorkspacePath)))],
[IEditorService, new TestEditorService()],
[IEditorGroupsService, new TestEditorGroupsService()],
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册