Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/vs/workbench/contrib/snippets/browser/snippetsService.ts')
-rw-r--r--src/vs/workbench/contrib/snippets/browser/snippetsService.ts128
1 files changed, 111 insertions, 17 deletions
diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts
index abc007e863d..3c5ed85f665 100644
--- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts
+++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts
@@ -14,11 +14,10 @@ import { setSnippetSuggestSupport } from 'vs/editor/contrib/suggest/browser/sugg
import { localize } from 'vs/nls';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
-import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
-import { ISnippetGetOptions, ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets.contribution';
+import { ISnippetGetOptions, ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets';
import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippets/browser/snippetsFile';
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { languagesExtPoint } from 'vs/workbench/services/language/common/languageService';
@@ -31,6 +30,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
+import { insertInto } from 'vs/base/common/arrays';
namespace snippetExt {
@@ -167,7 +167,43 @@ class SnippetEnablement {
}
}
-class SnippetsService implements ISnippetsService {
+class SnippetUsageTimestamps {
+
+ private static _key = 'snippets.usageTimestamps';
+
+ private readonly _usages: Map<string, number>;
+
+ constructor(
+ @IStorageService private readonly _storageService: IStorageService,
+ ) {
+
+ const raw = _storageService.get(SnippetUsageTimestamps._key, StorageScope.PROFILE, '');
+ let data: [string, number][] | undefined;
+ try {
+ data = JSON.parse(raw);
+ } catch {
+ data = [];
+ }
+
+ this._usages = Array.isArray(data) ? new Map(data) : new Map();
+ }
+
+ getUsageTimestamp(id: string): number | undefined {
+ return this._usages.get(id);
+ }
+
+ updateUsageTimestamp(id: string): void {
+ // map uses insertion order, we want most recent at the end
+ this._usages.delete(id);
+ this._usages.set(id, Date.now());
+
+ // persist last 100 item
+ const all = [...this._usages].slice(-100);
+ this._storageService.store(SnippetUsageTimestamps._key, JSON.stringify(all), StorageScope.PROFILE, StorageTarget.USER);
+ }
+}
+
+export class SnippetsService implements ISnippetsService {
declare readonly _serviceBrand: undefined;
@@ -175,6 +211,7 @@ class SnippetsService implements ISnippetsService {
private readonly _pendingWork: Promise<any>[] = [];
private readonly _files = new ResourceMap<SnippetFile>();
private readonly _enablement: SnippetEnablement;
+ private readonly _usageTimestamps: SnippetUsageTimestamps;
constructor(
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@@ -198,6 +235,7 @@ class SnippetsService implements ISnippetsService {
setSnippetSuggestSupport(new SnippetCompletionProvider(this._languageService, this, languageConfigurationService));
this._enablement = instantiationService.createInstance(SnippetEnablement);
+ this._usageTimestamps = instantiationService.createInstance(SnippetUsageTimestamps);
}
dispose(): void {
@@ -205,13 +243,15 @@ class SnippetsService implements ISnippetsService {
}
isEnabled(snippet: Snippet): boolean {
- return !snippet.snippetIdentifier || !this._enablement.isIgnored(snippet.snippetIdentifier);
+ return !this._enablement.isIgnored(snippet.snippetIdentifier);
}
updateEnablement(snippet: Snippet, enabled: boolean): void {
- if (snippet.snippetIdentifier) {
- this._enablement.updateIgnored(snippet.snippetIdentifier, !enabled);
- }
+ this._enablement.updateIgnored(snippet.snippetIdentifier, !enabled);
+ }
+
+ updateUsageTimestamp(snippet: Snippet): void {
+ this._usageTimestamps.updateUsageTimestamp(snippet.snippetIdentifier);
}
private _joinSnippets(): Promise<any> {
@@ -225,22 +265,31 @@ class SnippetsService implements ISnippetsService {
return this._files.values();
}
- async getSnippets(languageId: string, opts?: ISnippetGetOptions): Promise<Snippet[]> {
+ async getSnippets(languageId: string | undefined, opts?: ISnippetGetOptions): Promise<Snippet[]> {
await this._joinSnippets();
const result: Snippet[] = [];
const promises: Promise<any>[] = [];
- if (this._languageService.isRegisteredLanguageId(languageId)) {
+ if (languageId) {
+ if (this._languageService.isRegisteredLanguageId(languageId)) {
+ for (const file of this._files.values()) {
+ promises.push(file.load()
+ .then(file => file.select(languageId, result))
+ .catch(err => this._logService.error(err, file.location.toString()))
+ );
+ }
+ }
+ } else {
for (const file of this._files.values()) {
promises.push(file.load()
- .then(file => file.select(languageId, result))
+ .then(file => insertInto(result, result.length, file.data))
.catch(err => this._logService.error(err, file.location.toString()))
);
}
}
await Promise.all(promises);
- return this._filterSnippets(result, opts);
+ return this._filterAndSortSnippets(result, opts);
}
getSnippetsSync(languageId: string, opts?: ISnippetGetOptions): Snippet[] {
@@ -253,16 +302,62 @@ class SnippetsService implements ISnippetsService {
file.select(languageId, result);
}
}
- return this._filterSnippets(result, opts);
+ return this._filterAndSortSnippets(result, opts);
}
- private _filterSnippets(snippets: Snippet[], opts?: ISnippetGetOptions): Snippet[] {
- return snippets.filter(snippet => {
- return (snippet.prefix || opts?.includeNoPrefixSnippets) // prefix or no-prefix wanted
- && (this.isEnabled(snippet) || opts?.includeDisabledSnippets); // enabled or disabled wanted
+ private _filterAndSortSnippets(snippets: Snippet[], opts?: ISnippetGetOptions): Snippet[] {
+
+ const result: Snippet[] = [];
+
+ for (const snippet of snippets) {
+ if (!snippet.prefix && !opts?.includeNoPrefixSnippets) {
+ // prefix or no-prefix wanted
+ continue;
+ }
+ if (!this.isEnabled(snippet) && !opts?.includeDisabledSnippets) {
+ // enabled or disabled wanted
+ continue;
+ }
+ if (typeof opts?.topLevelSnippets === 'boolean' && opts.topLevelSnippets !== snippet.isTopLevel) {
+ // isTopLevel requested but mismatching
+ continue;
+ }
+ result.push(snippet);
+ }
+
+
+ return result.sort((a, b) => {
+ let result = 0;
+ if (!opts?.noRecencySort) {
+ const val1 = this._usageTimestamps.getUsageTimestamp(a.snippetIdentifier) ?? -1;
+ const val2 = this._usageTimestamps.getUsageTimestamp(b.snippetIdentifier) ?? -1;
+ result = val2 - val1;
+ }
+ if (result === 0) {
+ result = this._compareSnippet(a, b);
+ }
+ return result;
});
}
+ private _compareSnippet(a: Snippet, b: Snippet): number {
+ if (a.snippetSource < b.snippetSource) {
+ return -1;
+ } else if (a.snippetSource > b.snippetSource) {
+ return 1;
+ } else if (a.source < b.source) {
+ return -1;
+ } else if (a.source > b.source) {
+ return 1;
+ } else if (a.name > b.name) {
+ return 1;
+ } else if (a.name < b.name) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
// --- loading, watching
private _initExtensionSnippets(): void {
@@ -408,7 +503,6 @@ class SnippetsService implements ISnippetsService {
}
}
-registerSingleton(ISnippetsService, SnippetsService, true);
export interface ISimpleModel {
getLineContent(lineNumber: number): string;