| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { isFalsyOrEmpty, isNonEmptyArray } from '../../../base/common/arrays.js';
- import { DebounceEmitter } from '../../../base/common/event.js';
- import { Iterable } from '../../../base/common/iterator.js';
- import { ResourceMap } from '../../../base/common/map.js';
- import { Schemas } from '../../../base/common/network.js';
- import { URI } from '../../../base/common/uri.js';
- import { MarkerSeverity } from './markers.js';
- class DoubleResourceMap {
- constructor() {
- this._byResource = new ResourceMap();
- this._byOwner = new Map();
- }
- set(resource, owner, value) {
- let ownerMap = this._byResource.get(resource);
- if (!ownerMap) {
- ownerMap = new Map();
- this._byResource.set(resource, ownerMap);
- }
- ownerMap.set(owner, value);
- let resourceMap = this._byOwner.get(owner);
- if (!resourceMap) {
- resourceMap = new ResourceMap();
- this._byOwner.set(owner, resourceMap);
- }
- resourceMap.set(resource, value);
- }
- get(resource, owner) {
- const ownerMap = this._byResource.get(resource);
- return ownerMap === null || ownerMap === void 0 ? void 0 : ownerMap.get(owner);
- }
- delete(resource, owner) {
- let removedA = false;
- let removedB = false;
- const ownerMap = this._byResource.get(resource);
- if (ownerMap) {
- removedA = ownerMap.delete(owner);
- }
- const resourceMap = this._byOwner.get(owner);
- if (resourceMap) {
- removedB = resourceMap.delete(resource);
- }
- if (removedA !== removedB) {
- throw new Error('illegal state');
- }
- return removedA && removedB;
- }
- values(key) {
- var _a, _b, _c, _d;
- if (typeof key === 'string') {
- return (_b = (_a = this._byOwner.get(key)) === null || _a === void 0 ? void 0 : _a.values()) !== null && _b !== void 0 ? _b : Iterable.empty();
- }
- if (URI.isUri(key)) {
- return (_d = (_c = this._byResource.get(key)) === null || _c === void 0 ? void 0 : _c.values()) !== null && _d !== void 0 ? _d : Iterable.empty();
- }
- return Iterable.map(Iterable.concat(...this._byOwner.values()), map => map[1]);
- }
- }
- class MarkerStats {
- constructor(service) {
- this.errors = 0;
- this.infos = 0;
- this.warnings = 0;
- this.unknowns = 0;
- this._data = new ResourceMap();
- this._service = service;
- this._subscription = service.onMarkerChanged(this._update, this);
- }
- dispose() {
- this._subscription.dispose();
- }
- _update(resources) {
- for (const resource of resources) {
- const oldStats = this._data.get(resource);
- if (oldStats) {
- this._substract(oldStats);
- }
- const newStats = this._resourceStats(resource);
- this._add(newStats);
- this._data.set(resource, newStats);
- }
- }
- _resourceStats(resource) {
- const result = { errors: 0, warnings: 0, infos: 0, unknowns: 0 };
- // TODO this is a hack
- if (resource.scheme === Schemas.inMemory || resource.scheme === Schemas.walkThrough || resource.scheme === Schemas.walkThroughSnippet || resource.scheme === Schemas.vscodeSourceControl) {
- return result;
- }
- for (const { severity } of this._service.read({ resource })) {
- if (severity === MarkerSeverity.Error) {
- result.errors += 1;
- }
- else if (severity === MarkerSeverity.Warning) {
- result.warnings += 1;
- }
- else if (severity === MarkerSeverity.Info) {
- result.infos += 1;
- }
- else {
- result.unknowns += 1;
- }
- }
- return result;
- }
- _substract(op) {
- this.errors -= op.errors;
- this.warnings -= op.warnings;
- this.infos -= op.infos;
- this.unknowns -= op.unknowns;
- }
- _add(op) {
- this.errors += op.errors;
- this.warnings += op.warnings;
- this.infos += op.infos;
- this.unknowns += op.unknowns;
- }
- }
- export class MarkerService {
- constructor() {
- this._onMarkerChanged = new DebounceEmitter({
- delay: 0,
- merge: MarkerService._merge
- });
- this.onMarkerChanged = this._onMarkerChanged.event;
- this._data = new DoubleResourceMap();
- this._stats = new MarkerStats(this);
- }
- dispose() {
- this._stats.dispose();
- this._onMarkerChanged.dispose();
- }
- remove(owner, resources) {
- for (const resource of resources || []) {
- this.changeOne(owner, resource, []);
- }
- }
- changeOne(owner, resource, markerData) {
- if (isFalsyOrEmpty(markerData)) {
- // remove marker for this (owner,resource)-tuple
- const removed = this._data.delete(resource, owner);
- if (removed) {
- this._onMarkerChanged.fire([resource]);
- }
- }
- else {
- // insert marker for this (owner,resource)-tuple
- const markers = [];
- for (const data of markerData) {
- const marker = MarkerService._toMarker(owner, resource, data);
- if (marker) {
- markers.push(marker);
- }
- }
- this._data.set(resource, owner, markers);
- this._onMarkerChanged.fire([resource]);
- }
- }
- static _toMarker(owner, resource, data) {
- let { code, severity, message, source, startLineNumber, startColumn, endLineNumber, endColumn, relatedInformation, tags, } = data;
- if (!message) {
- return undefined;
- }
- // santize data
- startLineNumber = startLineNumber > 0 ? startLineNumber : 1;
- startColumn = startColumn > 0 ? startColumn : 1;
- endLineNumber = endLineNumber >= startLineNumber ? endLineNumber : startLineNumber;
- endColumn = endColumn > 0 ? endColumn : startColumn;
- return {
- resource,
- owner,
- code,
- severity,
- message,
- source,
- startLineNumber,
- startColumn,
- endLineNumber,
- endColumn,
- relatedInformation,
- tags,
- };
- }
- changeAll(owner, data) {
- const changes = [];
- // remove old marker
- const existing = this._data.values(owner);
- if (existing) {
- for (const data of existing) {
- const first = Iterable.first(data);
- if (first) {
- changes.push(first.resource);
- this._data.delete(first.resource, owner);
- }
- }
- }
- // add new markers
- if (isNonEmptyArray(data)) {
- // group by resource
- const groups = new ResourceMap();
- for (const { resource, marker: markerData } of data) {
- const marker = MarkerService._toMarker(owner, resource, markerData);
- if (!marker) {
- // filter bad markers
- continue;
- }
- const array = groups.get(resource);
- if (!array) {
- groups.set(resource, [marker]);
- changes.push(resource);
- }
- else {
- array.push(marker);
- }
- }
- // insert all
- for (const [resource, value] of groups) {
- this._data.set(resource, owner, value);
- }
- }
- if (changes.length > 0) {
- this._onMarkerChanged.fire(changes);
- }
- }
- read(filter = Object.create(null)) {
- let { owner, resource, severities, take } = filter;
- if (!take || take < 0) {
- take = -1;
- }
- if (owner && resource) {
- // exactly one owner AND resource
- const data = this._data.get(resource, owner);
- if (!data) {
- return [];
- }
- else {
- const result = [];
- for (const marker of data) {
- if (MarkerService._accept(marker, severities)) {
- const newLen = result.push(marker);
- if (take > 0 && newLen === take) {
- break;
- }
- }
- }
- return result;
- }
- }
- else if (!owner && !resource) {
- // all
- const result = [];
- for (const markers of this._data.values()) {
- for (const data of markers) {
- if (MarkerService._accept(data, severities)) {
- const newLen = result.push(data);
- if (take > 0 && newLen === take) {
- return result;
- }
- }
- }
- }
- return result;
- }
- else {
- // of one resource OR owner
- const iterable = this._data.values(resource !== null && resource !== void 0 ? resource : owner);
- const result = [];
- for (const markers of iterable) {
- for (const data of markers) {
- if (MarkerService._accept(data, severities)) {
- const newLen = result.push(data);
- if (take > 0 && newLen === take) {
- return result;
- }
- }
- }
- }
- return result;
- }
- }
- static _accept(marker, severities) {
- return severities === undefined || (severities & marker.severity) === marker.severity;
- }
- // --- event debounce logic
- static _merge(all) {
- const set = new ResourceMap();
- for (const array of all) {
- for (const item of array) {
- set.set(item, true);
- }
- }
- return Array.from(set.keys());
- }
- }
|