languageFeatureRegistry.ts 3.7 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

J
Johannes Rieken 已提交
8 9 10 11
import Event, { Emitter } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IReadOnlyModel } from 'vs/editor/common/editorCommon';
import { LanguageSelector, score } from 'vs/editor/common/modes/languageSelector';
E
Erich Gamma 已提交
12 13 14 15 16 17 18 19 20 21

interface Entry<T> {
	selector: LanguageSelector;
	provider: T;
	_score: number;
	_time: number;
}

export default class LanguageFeatureRegistry<T> {

22
	private _clock: number = 0;
E
Erich Gamma 已提交
23
	private _entries: Entry<T>[] = [];
J
Johannes Rieken 已提交
24
	private _onDidChange: Emitter<number> = new Emitter<number>();
E
Erich Gamma 已提交
25

26
	constructor() {
E
Erich Gamma 已提交
27 28
	}

J
Johannes Rieken 已提交
29
	get onDidChange(): Event<number> {
E
Erich Gamma 已提交
30 31 32
		return this._onDidChange.event;
	}

33
	register(selector: LanguageSelector, provider: T): IDisposable {
E
Erich Gamma 已提交
34 35 36 37 38

		let entry: Entry<T> = {
			selector,
			provider,
			_score: -1,
39
			_time: this._clock++
E
Erich Gamma 已提交
40 41 42
		};

		this._entries.push(entry);
43
		this._lastCandidate = undefined;
E
Erich Gamma 已提交
44 45 46 47 48 49 50 51
		this._onDidChange.fire(this._entries.length);

		return {
			dispose: () => {
				if (entry) {
					let idx = this._entries.indexOf(entry);
					if (idx >= 0) {
						this._entries.splice(idx, 1);
52
						this._lastCandidate = undefined;
E
Erich Gamma 已提交
53 54 55 56 57
						this._onDidChange.fire(this._entries.length);
						entry = undefined;
					}
				}
			}
A
Alex Dima 已提交
58
		};
E
Erich Gamma 已提交
59 60
	}

61
	has(model: IReadOnlyModel): boolean {
E
Erich Gamma 已提交
62 63 64
		return this.all(model).length > 0;
	}

65
	all(model: IReadOnlyModel): T[] {
66
		if (!model || model.isTooLargeForHavingARichMode()) {
67 68 69 70 71 72
			return [];
		}

		this._updateScores(model);
		const result: T[] = [];

73
		// from registry
74 75 76
		for (let entry of this._entries) {
			if (entry._score > 0) {
				result.push(entry.provider);
E
Erich Gamma 已提交
77 78
			}
		}
79

E
Erich Gamma 已提交
80 81 82
		return result;
	}

83
	ordered(model: IReadOnlyModel): T[] {
84 85 86
		const result: T[] = [];
		this._orderedForEach(model, entry => result.push(entry.provider));
		return result;
E
Erich Gamma 已提交
87 88
	}

89
	orderedGroups(model: IReadOnlyModel): T[][] {
90
		const result: T[][] = [];
E
Erich Gamma 已提交
91 92 93
		let lastBucket: T[];
		let lastBucketScore: number;

94
		this._orderedForEach(model, entry => {
E
Erich Gamma 已提交
95 96 97 98 99 100 101
			if (lastBucket && lastBucketScore === entry._score) {
				lastBucket.push(entry.provider);
			} else {
				lastBucketScore = entry._score;
				lastBucket = [entry.provider];
				result.push(lastBucket);
			}
102
		});
E
Erich Gamma 已提交
103 104 105 106

		return result;
	}

107
	private _orderedForEach(model: IReadOnlyModel, callback: (provider: Entry<T>) => any): void {
108

109
		if (!model || model.isTooLargeForHavingARichMode()) {
110
			return;
111
		}
E
Erich Gamma 已提交
112

113
		this._updateScores(model);
114

115 116 117 118
		for (let from = 0; from < this._entries.length; from++) {
			let entry = this._entries[from];
			if (entry._score > 0) {
				callback(entry);
119
			}
E
Erich Gamma 已提交
120 121 122
		}
	}

123
	private _lastCandidate: { uri: string; language: string; };
E
Erich Gamma 已提交
124

125
	private _updateScores(model: IReadOnlyModel): boolean {
E
Erich Gamma 已提交
126

127
		let candidate = {
128
			uri: model.uri.toString(),
129 130
			language: model.getModeId()
		};
E
Erich Gamma 已提交
131

132 133 134
		if (this._lastCandidate
			&& this._lastCandidate.language === candidate.language
			&& this._lastCandidate.uri === candidate.uri) {
E
Erich Gamma 已提交
135 136 137 138 139

			// nothing has changed
			return;
		}

140
		this._lastCandidate = candidate;
E
Erich Gamma 已提交
141 142

		for (let entry of this._entries) {
143
			entry._score = score(entry.selector, model.uri, model.getModeId());
E
Erich Gamma 已提交
144 145
		}

146
		// needs sorting
E
Erich Gamma 已提交
147 148 149 150 151 152 153 154
		this._entries.sort(LanguageFeatureRegistry._compareByScoreAndTime);
	}

	private static _compareByScoreAndTime(a: Entry<any>, b: Entry<any>): number {
		if (a._score < b._score) {
			return 1;
		} else if (a._score > b._score) {
			return -1;
J
Johannes Rieken 已提交
155
		} else if (a._time < b._time) {
E
Erich Gamma 已提交
156 157 158 159 160 161 162 163
			return 1;
		} else if (a._time > b._time) {
			return -1;
		} else {
			return 0;
		}
	}
}