add persisted snippet enablement

This commit is contained in:
Johannes Rieken
2020-11-03 15:45:02 +01:00
parent 70227b45b5
commit 20b534d41e
4 changed files with 80 additions and 9 deletions
@@ -19,9 +19,13 @@ export interface ISnippetsService {
getSnippetFiles(): Promise<Iterable<SnippetFile>>;
getSnippets(languageId: LanguageId): Promise<Snippet[]>;
isEnabled(snippet: Snippet): boolean;
getSnippetsSync(languageId: LanguageId): Snippet[];
updateEnablement(snippet: Snippet, enabled: string): void;
getSnippets(languageId: LanguageId, includeDisabledSnippets?: boolean): Promise<Snippet[]>;
getSnippetsSync(languageId: LanguageId, includeDisabledSnippets?: boolean): Snippet[];
}
const languageScopeSchemaId = 'vscode://schemas/snippets';
@@ -15,6 +15,7 @@ import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IdleValue } from 'vs/base/common/async';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { relativePath } from 'vs/base/common/resources';
class SnippetBodyInsights {
@@ -86,6 +87,7 @@ export class Snippet {
readonly body: string,
readonly source: string,
readonly snippetSource: SnippetSource,
readonly snippetIdentifier?: string
) {
//
this.prefixLow = prefix ? prefix.toLowerCase() : prefix;
@@ -289,7 +291,8 @@ export class SnippetFile {
description,
body,
source,
this.source
this.source,
this._extension && `${relativePath(this._extension.extensionLocation, this.location)}/${name}`
));
});
}
@@ -26,6 +26,10 @@ import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchMo
import { SnippetCompletionProvider } from './snippetCompletionProvider';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import { ResourceMap } from 'vs/base/common/map';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { isStringArray } from 'vs/base/common/types';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
namespace snippetExt {
@@ -124,6 +128,47 @@ function watch(service: IFileService, resource: URI, callback: () => any): IDisp
);
}
class SnippetEnablement {
private static _key = 'snippets.ignoredSnippets';
private readonly _ignored: Set<string>;
constructor(
@IStorageService private readonly _storageService: IStorageService,
@IStorageKeysSyncRegistryService storageKeysSyncService: IStorageKeysSyncRegistryService,
) {
storageKeysSyncService.registerStorageKey({ key: SnippetEnablement._key, version: 1 });
const raw = _storageService.get(SnippetEnablement._key, StorageScope.GLOBAL, '');
let data: string[] | undefined;
try {
data = JSON.parse(raw);
} catch { }
this._ignored = isStringArray(data) ? new Set(data) : new Set();
}
isIgnored(id: string): boolean {
return this._ignored.has(id);
}
updateIgnored(id: string, value: boolean): void {
let changed = false;
if (this._ignored.has(id) && !value) {
this._ignored.delete(id);
changed = true;
} else if (!this._ignored.has(id) && value) {
this._ignored.add(id);
changed = true;
}
if (changed) {
this._storageService.store(SnippetEnablement._key, JSON.stringify(Array.from(this._ignored)), StorageScope.GLOBAL);
}
}
}
class SnippetsService implements ISnippetsService {
declare readonly _serviceBrand: undefined;
@@ -131,6 +176,7 @@ class SnippetsService implements ISnippetsService {
private readonly _disposables = new DisposableStore();
private readonly _pendingWork: Promise<any>[] = [];
private readonly _files = new ResourceMap<SnippetFile>();
private readonly _enablement: SnippetEnablement;
constructor(
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@@ -140,6 +186,7 @@ class SnippetsService implements ISnippetsService {
@IFileService private readonly _fileService: IFileService,
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
@ILifecycleService lifecycleService: ILifecycleService,
@IInstantiationService instantiationService: IInstantiationService,
) {
this._pendingWork.push(Promise.resolve(lifecycleService.when(LifecyclePhase.Restored).then(() => {
this._initExtensionSnippets();
@@ -148,12 +195,24 @@ class SnippetsService implements ISnippetsService {
})));
setSnippetSuggestSupport(new SnippetCompletionProvider(this._modeService, this));
this._enablement = instantiationService.createInstance(SnippetEnablement);
}
dispose(): void {
this._disposables.dispose();
}
isEnabled(snippet: Snippet): boolean {
return !snippet.snippetIdentifier || !this._enablement.isIgnored(snippet.snippetIdentifier);
}
updateEnablement(snippet: Snippet, enabled: string): void {
if (snippet.snippetIdentifier) {
this._enablement.updateIgnored(snippet.snippetIdentifier, !enabled);
}
}
private _joinSnippets(): Promise<any> {
const promises = this._pendingWork.slice(0);
this._pendingWork.length = 0;
@@ -165,7 +224,7 @@ class SnippetsService implements ISnippetsService {
return this._files.values();
}
async getSnippets(languageId: LanguageId): Promise<Snippet[]> {
async getSnippets(languageId: LanguageId, includeIgnored?: boolean): Promise<Snippet[]> {
await this._joinSnippets();
const result: Snippet[] = [];
@@ -182,10 +241,10 @@ class SnippetsService implements ISnippetsService {
}
}
await Promise.all(promises);
return result;
return includeIgnored ? result : result.filter(this.isEnabled, this);
}
getSnippetsSync(languageId: LanguageId): Snippet[] {
getSnippetsSync(languageId: LanguageId, includeIgnored?: boolean): Snippet[] {
const result: Snippet[] = [];
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (languageIdentifier) {
@@ -197,7 +256,7 @@ class SnippetsService implements ISnippetsService {
file.select(langName, result);
}
}
return result;
return includeIgnored ? result : result.filter(this.isEnabled, this);
}
// --- loading, watching
@@ -16,8 +16,7 @@ import { CompletionContext, CompletionTriggerKind } from 'vs/editor/common/modes
class SimpleSnippetService implements ISnippetsService {
declare readonly _serviceBrand: undefined;
constructor(readonly snippets: Snippet[]) {
}
constructor(readonly snippets: Snippet[]) { }
getSnippets() {
return Promise.resolve(this.getSnippetsSync());
}
@@ -27,6 +26,12 @@ class SimpleSnippetService implements ISnippetsService {
getSnippetFiles(): any {
throw new Error();
}
isEnabled(): boolean {
throw new Error();
}
updateEnablement(): void {
throw new Error();
}
}
suite('SnippetsService', function () {