From 2c797bee28e7e4b9fe606f5ce95f8f80edb35589 Mon Sep 17 00:00:00 2001 From: dobbydobap Date: Sun, 5 Jul 2026 18:02:08 +0530 Subject: [PATCH 1/3] Show active editor language first in Configure Snippets --- .../browser/commands/configureSnippets.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts index 6add03050d132..b6d06f450986c 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts @@ -20,6 +20,7 @@ import { IWorkspaceContextService } from '../../../../../platform/workspace/comm import { SnippetsAction } from './abstractSnippetsActions.js'; import { ISnippetsService } from '../snippets.js'; import { SnippetSource } from '../snippetsFile.js'; +import { IEditorService } from '../../../../services/editor/common/editorService.js'; import { ITextFileService } from '../../../../services/textfile/common/textfiles.js'; import { IUserDataProfileService } from '../../../../services/userDataProfile/common/userDataProfile.js'; @@ -34,7 +35,7 @@ interface ISnippetPick extends IQuickPickItem { hint?: true; } -async function computePicks(snippetService: ISnippetsService, userDataProfileService: IUserDataProfileService, languageService: ILanguageService, labelService: ILabelService) { +async function computePicks(snippetService: ISnippetsService, userDataProfileService: IUserDataProfileService, languageService: ILanguageService, labelService: ILabelService, activeLanguageId: string | undefined) { const existing: ISnippetPick[] = []; const future: ISnippetPick[] = []; @@ -138,6 +139,18 @@ async function computePicks(snippetService: ISnippetsService, userDataProfileSer return a.label.localeCompare(b.label); }); + if (activeLanguageId) { + // list the language of the active editor first + const existingIdx = existing.findIndex(pick => basename(pick.filepath) === `${activeLanguageId}.json`); + if (existingIdx > 0) { + existing.unshift(existing.splice(existingIdx, 1)[0]); + } + const futureIdx = future.findIndex(pick => pick.label === activeLanguageId); + if (futureIdx > 0) { + future.unshift(future.splice(futureIdx, 1)[0]); + } + } + return { existing, future }; } @@ -265,13 +278,14 @@ export class ConfigureSnippetsAction extends SnippetsAction { const quickInputService = accessor.get(IQuickInputService); const opener = accessor.get(IOpenerService); const languageService = accessor.get(ILanguageService); + const editorService = accessor.get(IEditorService); const userDataProfileService = accessor.get(IUserDataProfileService); const workspaceService = accessor.get(IWorkspaceContextService); const fileService = accessor.get(IFileService); const textFileService = accessor.get(ITextFileService); const labelService = accessor.get(ILabelService); - const picks = await computePicks(snippetService, userDataProfileService, languageService, labelService); + const picks = await computePicks(snippetService, userDataProfileService, languageService, labelService, editorService.activeTextEditorLanguageId); const existing: QuickPickInput[] = picks.existing; type SnippetPick = IQuickPickItem & { uri: URI } & { scope: string }; From 88be2d18c1c75d7b08a194ac2bfb7a05287ed930 Mon Sep 17 00:00:00 2001 From: dobbydobap Date: Mon, 6 Jul 2026 22:14:06 +0530 Subject: [PATCH 2/3] Test language ordering and add detected-language indicator --- .../browser/commands/configureSnippets.ts | 39 ++++++++---- .../test/browser/configureSnippets.test.ts | 63 +++++++++++++++++++ 2 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 src/vs/workbench/contrib/snippets/test/browser/configureSnippets.test.ts diff --git a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts index b6d06f450986c..fbbdd63539ce2 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts @@ -139,21 +139,38 @@ async function computePicks(snippetService: ISnippetsService, userDataProfileSer return a.label.localeCompare(b.label); }); - if (activeLanguageId) { - // list the language of the active editor first - const existingIdx = existing.findIndex(pick => basename(pick.filepath) === `${activeLanguageId}.json`); - if (existingIdx > 0) { - existing.unshift(existing.splice(existingIdx, 1)[0]); - } - const futureIdx = future.findIndex(pick => pick.label === activeLanguageId); - if (futureIdx > 0) { - future.unshift(future.splice(futureIdx, 1)[0]); - } - } + promoteActiveLanguage(existing, future, activeLanguageId); return { existing, future }; } +/** + * Surfaces the active editor's language: moves its snippet file and its "new language" entry + * to the front of their groups and marks them, so the language you're working in shows up + * first and it's clear why. No-op when there is no active language; a group is left untouched + * when the language is absent from it. + */ +export function promoteActiveLanguage(existing: ISnippetPick[], future: ISnippetPick[], activeLanguageId: string | undefined): void { + if (!activeLanguageId) { + return; + } + const detectedHint = nls.localize('detected', "This file type was detected from the current file."); + promote(existing, existing.findIndex(pick => basename(pick.filepath) === `${activeLanguageId}.json`), detectedHint); + promote(future, future.findIndex(pick => pick.label === activeLanguageId), detectedHint); +} + +function promote(picks: ISnippetPick[], index: number, hint: string): void { + if (index < 0) { + return; + } + const pick = picks[index]; + pick.tooltip = hint; + pick.description = pick.description ? `${pick.description} *` : '*'; + if (index > 0) { + picks.unshift(picks.splice(index, 1)[0]); + } +} + async function createSnippetFile(scope: string, defaultPath: URI, quickInputService: IQuickInputService, fileService: IFileService, textFileService: ITextFileService, opener: IOpenerService) { function createSnippetUri(input: string) { diff --git a/src/vs/workbench/contrib/snippets/test/browser/configureSnippets.test.ts b/src/vs/workbench/contrib/snippets/test/browser/configureSnippets.test.ts new file mode 100644 index 0000000000000..c33fe4fa9a833 --- /dev/null +++ b/src/vs/workbench/contrib/snippets/test/browser/configureSnippets.test.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import assert from 'assert'; +import { URI } from '../../../../../base/common/uri.js'; +import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; +import { promoteActiveLanguage } from '../../browser/commands/configureSnippets.js'; + +suite('Configure Snippets', () => { + + ensureNoDisposablesAreLeakedInTestSuite(); + + type TestPick = { label: string; filepath: URI }; + + function file(name: string): TestPick { + return { label: name, filepath: URI.file(`/snippets/${name}`) }; + } + + function lang(id: string): TestPick { + return { label: id, filepath: URI.file(`/snippets/${id}.json`) }; + } + + function reorder(existing: TestPick[], future: TestPick[], activeLanguageId: string | undefined) { + promoteActiveLanguage(existing, future, activeLanguageId); + return { existing: existing.map(p => p.label), future: future.map(p => p.label) }; + } + + test('promotes the active language in both groups', () => { + // existing file for python, and a new-language entry for python -> both jump to front + const existing = [file('global.code-snippets'), file('javascript.json'), file('python.json')]; + const future = [lang('csharp'), lang('go'), lang('python')]; + + assert.deepStrictEqual(reorder(existing, future, 'python'), { + existing: ['python.json', 'global.code-snippets', 'javascript.json'], + future: ['python', 'csharp', 'go'] + }); + }); + + test('no-op cases: no active language, already first, or not present', () => { + const existing = () => [file('javascript.json'), file('python.json')]; + const future = () => [lang('go'), lang('python')]; + + // undefined active language leaves order untouched + assert.deepStrictEqual(reorder(existing(), future(), undefined), { + existing: ['javascript.json', 'python.json'], + future: ['go', 'python'] + }); + + // already first in the existing group -> untouched + assert.deepStrictEqual(reorder(existing(), future(), 'javascript'), { + existing: ['javascript.json', 'python.json'], + future: ['go', 'python'] // no future entry for javascript, so future untouched too + }); + + // language absent from both groups -> untouched + assert.deepStrictEqual(reorder(existing(), future(), 'rust'), { + existing: ['javascript.json', 'python.json'], + future: ['go', 'python'] + }); + }); +}); From 99adb5192339a99d15be9d4a6ae1ff47d9e8734e Mon Sep 17 00:00:00 2001 From: dobbydobap Date: Tue, 7 Jul 2026 11:11:09 +0530 Subject: [PATCH 3/3] Simplify promoteActiveLanguage comment --- .../contrib/snippets/browser/commands/configureSnippets.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts index fbbdd63539ce2..3c70dbcef4caf 100644 --- a/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts +++ b/src/vs/workbench/contrib/snippets/browser/commands/configureSnippets.ts @@ -144,12 +144,7 @@ async function computePicks(snippetService: ISnippetsService, userDataProfileSer return { existing, future }; } -/** - * Surfaces the active editor's language: moves its snippet file and its "new language" entry - * to the front of their groups and marks them, so the language you're working in shows up - * first and it's clear why. No-op when there is no active language; a group is left untouched - * when the language is absent from it. - */ +// Move the active editor's language to the front of each group and mark it as detected. export function promoteActiveLanguage(existing: ISnippetPick[], future: ISnippetPick[], activeLanguageId: string | undefined): void { if (!activeLanguageId) { return;