From 68bca74bee42963121efbf91fd20c504b7e5dc8f Mon Sep 17 00:00:00 2001 From: Jason Dent Date: Sat, 14 Oct 2023 20:55:22 +0200 Subject: [PATCH] feat: Control which settings are passed to cspell (#2868) --- .../_includes/generated-docs/configuration.md | 98 ++++++++---- package.json | 138 ++++++++++++++++- .../_server/spell-checker-config.schema.json | 141 +++++++++++++++++- .../CSpellSettingsPackageProperties.mts | 20 +++ .../cspellConfig/SpellCheckerSettings.mts | 27 ++++ .../src/config/cspellConfig/cspellConfig.mts | 2 + .../config/cspellConfig/cspellMergeFields.mts | 64 ++++++++ .../cspellConfig/cspellMergeFields.test.mts | 17 +++ .../_server/src/config/documentSettings.mts | 32 ++-- .../src/config/documentSettings.test.mts | 3 +- packages/_server/src/server.mts | 2 +- packages/client/src/settings/configFields.ts | 1 + 12 files changed, 481 insertions(+), 64 deletions(-) create mode 100644 packages/_server/src/config/cspellConfig/cspellMergeFields.mts create mode 100644 packages/_server/src/config/cspellConfig/cspellMergeFields.test.mts diff --git a/docs/_includes/generated-docs/configuration.md b/docs/_includes/generated-docs/configuration.md index 10e87e50ea..af20158db2 100644 --- a/docs/_includes/generated-docs/configuration.md +++ b/docs/_includes/generated-docs/configuration.md @@ -52,6 +52,7 @@ Default | [`cSpell.language`](#cspelllanguage) | resource | Current active spelling language. | | [`cSpell.languageSettings`](#cspelllanguagesettings) | resource | Additional settings for individual programming languages and locales. | | [`cSpell.noSuggestDictionaries`](#cspellnosuggestdictionaries) | resource | Optional list of dictionaries that will not be used for suggestions. Words in these dictionaries… | +| [`cSpell.suggestWords`](#cspellsuggestwords) | | A list of suggested replacements for words. Suggested words provide a way to make preferred… | | [`cSpell.userWords`](#cspelluserwords) | resource | Words to add to global dictionary -- should only be in the user config file. | | [`cSpell.words`](#cspellwords) | resource | List of words to be considered correct. | @@ -277,6 +278,35 @@ Default --- +### `cSpell.suggestWords` + +Name +: `cSpell.suggestWords` + +Type +: string[] + +Scope +: + +Description +: A list of suggested replacements for words. +Suggested words provide a way to make preferred suggestions on word replacements. +To hint at a preferred change, but not to require it. + + Format of `suggestWords` + - Single suggestion (possible auto fix) + - `word: suggestion` + - `word->suggestion` + - Multiple suggestions (not auto fixable) + - `word: first, second, third` + - `word->first, second, third` + +Default +: _- none -_ + +--- + ### `cSpell.userWords` Name @@ -652,6 +682,7 @@ Default | [`cSpell.globRoot`](#cspellglobroot) | resource | The root to use for glob patterns found in this configuration. Default: The current workspace… | | [`cSpell.ignorePaths`](#cspellignorepaths) | resource | Glob patterns of files to be ignored | | [`cSpell.import`](#cspellimport) | resource | Allows this configuration to inherit configuration for one or more other files. | +| [`cSpell.mergeCSpellSettings`](#cspellmergecspellsettings) | resource | Specify which fields from `.vscode/settings.json` are passed to the spell checker. This only… | | [`cSpell.noConfigSearch`](#cspellnoconfigsearch) | resource | Prevents searching for local configuration when checking individual documents. | | [`cSpell.spellCheckOnlyWorkspaceFiles`](#cspellspellcheckonlyworkspacefiles) | window | Spell Check Only Workspace Files | | [`cSpell.useGitignore`](#cspellusegitignore) | resource | Tells the spell checker to load `.gitignore` files and skip files that match the globs in the… | @@ -833,6 +864,43 @@ Default --- +### `cSpell.mergeCSpellSettings` + +Name +: `cSpell.mergeCSpellSettings` + +Type +: + +Scope +: resource + +Description +: Specify which fields from `.vscode/settings.json` are passed to the spell checker. +This only applies when there is a CSpell configuration file in the workspace. + + The purpose of this setting to help provide a consistent result compared to the + CSpell spell checker command line tool. + + Values: + - `true` - all settings will be merged + - `false` - only use `.vscode/settings.json` if a CSpell configuration is not found. + - `{ words: true, userWords: false }` - specify which fields to pass through to the spell checker. + + Note: + + If specific fields are specified, they provide the ability to block settings even if a CSpell configuration + is not found. The following example could be used to block "cSpell.userWords" from a workspace. + + ```jsonc + "cSpell.mergeCSpellSettings": { "userWords": false }, + ``` + +Default +: _`false`_ + +--- + ### `cSpell.noConfigSearch` Name @@ -1110,7 +1178,6 @@ Default | [`cSpell.includeRegExpList`](#cspellincluderegexplist) | resource | List of regular expression patterns or defined pattern names to match for spell checking. | | [`cSpell.overrides`](#cspelloverrides) | resource | Overrides are used to apply settings for specific files in your project. | | [`cSpell.patterns`](#cspellpatterns) | resource | Defines a list of patterns that can be used with the `#cSpell.ignoreRegExpList#` and `#cSpell.includeRegExpList#`… | -| [`cSpell.suggestWords`](#cspellsuggestwords) | | A list of suggested replacements for words. Suggested words provide a way to make preferred… | ## Definitions @@ -1238,35 +1305,6 @@ Default --- -### `cSpell.suggestWords` - -Name -: `cSpell.suggestWords` - -Type -: string[] - -Scope -: - -Description -: A list of suggested replacements for words. -Suggested words provide a way to make preferred suggestions on word replacements. -To hint at a preferred change, but not to require it. - - Format of `suggestWords` - - Single suggestion (possible auto fix) - - `word: suggestion` - - `word->suggestion` - - Multiple suggestions (not auto fixable) - - `word: first, second, third` - - `word->first, second, third` - -Default -: _- none -_ - ---- - # Advanced | Setting | Scope | Description | diff --git a/package.json b/package.json index c905038209..fe266ce4d3 100644 --- a/package.json +++ b/package.json @@ -1188,13 +1188,6 @@ "markdownDescription": "Defines a list of patterns that can be used with the `#cSpell.ignoreRegExpList#` and\n`#cSpell.includeRegExpList#` options.\n\n**Example:**\n\n```jsonc\n\"cSpell.patterns\": [\n {\n \"name\": \"comment-single-line\",\n \"pattern\": \"/#.*​/g\"\n },\n {\n \"name\": \"comment-multi-line\",\n \"pattern\": \"/(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)/g\"\n }\n]\n```", "scope": "resource", "type": "array" - }, - "cSpell.suggestWords": { - "items": { - "type": "string" - }, - "markdownDescription": "A list of suggested replacements for words.\nSuggested words provide a way to make preferred suggestions on word replacements.\nTo hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix)\n - `word: suggestion`\n - `word->suggestion`\n- Multiple suggestions (not auto fixable)\n - `word: first, second, third`\n - `word->first, second, third`", - "type": "array" } }, "title": "CSpell", @@ -1304,6 +1297,130 @@ "scope": "resource", "type": "array" }, + "cSpell.mergeCSpellSettings": { + "anyOf": [ + { + "type": "boolean" + }, + { + "additionalProperties": false, + "properties": { + "allowCompoundWords": { + "type": "boolean" + }, + "caseSensitive": { + "type": "boolean" + }, + "dictionaries": { + "type": "boolean" + }, + "dictionaryDefinitions": { + "type": "boolean" + }, + "enableFiletypes": { + "type": "boolean" + }, + "enableGlobDot": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "enabledLanguageIds": { + "type": "boolean" + }, + "features": { + "type": "boolean" + }, + "files": { + "type": "boolean" + }, + "flagWords": { + "type": "boolean" + }, + "gitignoreRoot": { + "type": "boolean" + }, + "globRoot": { + "type": "boolean" + }, + "ignorePaths": { + "type": "boolean" + }, + "ignoreRegExpList": { + "type": "boolean" + }, + "ignoreWords": { + "type": "boolean" + }, + "import": { + "type": "boolean" + }, + "includeRegExpList": { + "type": "boolean" + }, + "language": { + "type": "boolean" + }, + "languageId": { + "type": "boolean" + }, + "languageSettings": { + "type": "boolean" + }, + "loadDefaultConfiguration": { + "type": "boolean" + }, + "minWordLength": { + "type": "boolean" + }, + "noConfigSearch": { + "type": "boolean" + }, + "noSuggestDictionaries": { + "type": "boolean" + }, + "numSuggestions": { + "type": "boolean" + }, + "overrides": { + "type": "boolean" + }, + "patterns": { + "type": "boolean" + }, + "pnpFiles": { + "type": "boolean" + }, + "reporters": { + "type": "boolean" + }, + "suggestWords": { + "type": "boolean" + }, + "useGitignore": { + "type": "boolean" + }, + "usePnP": { + "type": "boolean" + }, + "userWords": { + "type": "boolean" + }, + "validateDirectives": { + "type": "boolean" + }, + "words": { + "type": "boolean" + } + }, + "type": "object" + } + ], + "default": false, + "markdownDescription": "Specify which fields from `.vscode/settings.json` are passed to the spell checker.\nThis only applies when there is a CSpell configuration file in the workspace.\n\nThe purpose of this setting to help provide a consistent result compared to the\nCSpell spell checker command line tool.\n\nValues:\n- `true` - all settings will be merged\n- `false` - only use `.vscode/settings.json` if a CSpell configuration is not found.\n- `{ words: true, userWords: false }` - specify which fields to pass through to the spell checker.\n\nNote:\n\nIf specific fields are specified, they provide the ability to block settings even if a CSpell configuration\nis not found. The following example could be used to block \"cSpell.userWords\" from a workspace.\n\n```jsonc\n\"cSpell.mergeCSpellSettings\": { \"userWords\": false },\n```", + "scope": "resource" + }, "cSpell.noConfigSearch": { "markdownDescription": "Prevents searching for local configuration when checking individual documents.", "scope": "resource", @@ -1823,6 +1940,13 @@ "scope": "resource", "type": "array" }, + "cSpell.suggestWords": { + "items": { + "type": "string" + }, + "markdownDescription": "A list of suggested replacements for words.\nSuggested words provide a way to make preferred suggestions on word replacements.\nTo hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix)\n - `word: suggestion`\n - `word->suggestion`\n- Multiple suggestions (not auto fixable)\n - `word: first, second, third`\n - `word->first, second, third`", + "type": "array" + }, "cSpell.userWords": { "items": { "type": "string" diff --git a/packages/_server/spell-checker-config.schema.json b/packages/_server/spell-checker-config.schema.json index f3c9889789..d5fd0ec7cc 100644 --- a/packages/_server/spell-checker-config.schema.json +++ b/packages/_server/spell-checker-config.schema.json @@ -808,14 +808,6 @@ "markdownDescription": "Defines a list of patterns that can be used with the `#cSpell.ignoreRegExpList#` and\n`#cSpell.includeRegExpList#` options.\n\n**Example:**\n\n```jsonc\n\"cSpell.patterns\": [\n {\n \"name\": \"comment-single-line\",\n \"pattern\": \"/#.*​/g\"\n },\n {\n \"name\": \"comment-multi-line\",\n \"pattern\": \"/(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)/g\"\n }\n]\n```", "scope": "resource", "type": "array" - }, - "cSpell.suggestWords": { - "description": "A list of suggested replacements for words. Suggested words provide a way to make preferred suggestions on word replacements. To hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix) - `word: suggestion` - `word->suggestion`\n- Multiple suggestions (not auto fixable) - `word: first, second, third` - `word->first, second, third`", - "items": { - "type": "string" - }, - "markdownDescription": "A list of suggested replacements for words.\nSuggested words provide a way to make preferred suggestions on word replacements.\nTo hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix)\n - `word: suggestion`\n - `word->suggestion`\n- Multiple suggestions (not auto fixable)\n - `word: first, second, third`\n - `word->first, second, third`", - "type": "array" } }, "title": "CSpell", @@ -922,6 +914,131 @@ "scope": "resource", "type": "array" }, + "cSpell.mergeCSpellSettings": { + "anyOf": [ + { + "type": "boolean" + }, + { + "additionalProperties": false, + "properties": { + "allowCompoundWords": { + "type": "boolean" + }, + "caseSensitive": { + "type": "boolean" + }, + "dictionaries": { + "type": "boolean" + }, + "dictionaryDefinitions": { + "type": "boolean" + }, + "enableFiletypes": { + "type": "boolean" + }, + "enableGlobDot": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "enabledLanguageIds": { + "type": "boolean" + }, + "features": { + "type": "boolean" + }, + "files": { + "type": "boolean" + }, + "flagWords": { + "type": "boolean" + }, + "gitignoreRoot": { + "type": "boolean" + }, + "globRoot": { + "type": "boolean" + }, + "ignorePaths": { + "type": "boolean" + }, + "ignoreRegExpList": { + "type": "boolean" + }, + "ignoreWords": { + "type": "boolean" + }, + "import": { + "type": "boolean" + }, + "includeRegExpList": { + "type": "boolean" + }, + "language": { + "type": "boolean" + }, + "languageId": { + "type": "boolean" + }, + "languageSettings": { + "type": "boolean" + }, + "loadDefaultConfiguration": { + "type": "boolean" + }, + "minWordLength": { + "type": "boolean" + }, + "noConfigSearch": { + "type": "boolean" + }, + "noSuggestDictionaries": { + "type": "boolean" + }, + "numSuggestions": { + "type": "boolean" + }, + "overrides": { + "type": "boolean" + }, + "patterns": { + "type": "boolean" + }, + "pnpFiles": { + "type": "boolean" + }, + "reporters": { + "type": "boolean" + }, + "suggestWords": { + "type": "boolean" + }, + "useGitignore": { + "type": "boolean" + }, + "usePnP": { + "type": "boolean" + }, + "userWords": { + "type": "boolean" + }, + "validateDirectives": { + "type": "boolean" + }, + "words": { + "type": "boolean" + } + }, + "type": "object" + } + ], + "default": false, + "description": "Specify which fields from `.vscode/settings.json` are passed to the spell checker. This only applies when there is a CSpell configuration file in the workspace.\n\nThe purpose of this setting to help provide a consistent result compared to the CSpell spell checker command line tool.\n\nValues:\n- `true` - all settings will be merged\n- `false` - only use `.vscode/settings.json` if a CSpell configuration is not found.\n- `{ words: true, userWords: false }` - specify which fields to pass through to the spell checker.\n\nNote:\n\nIf specific fields are specified, they provide the ability to block settings even if a CSpell configuration is not found. The following example could be used to block \"cSpell.userWords\" from a workspace.\n\n```jsonc \"cSpell.mergeCSpellSettings\": { \"userWords\": false }, ```", + "markdownDescription": "Specify which fields from `.vscode/settings.json` are passed to the spell checker.\nThis only applies when there is a CSpell configuration file in the workspace.\n\nThe purpose of this setting to help provide a consistent result compared to the\nCSpell spell checker command line tool.\n\nValues:\n- `true` - all settings will be merged\n- `false` - only use `.vscode/settings.json` if a CSpell configuration is not found.\n- `{ words: true, userWords: false }` - specify which fields to pass through to the spell checker.\n\nNote:\n\nIf specific fields are specified, they provide the ability to block settings even if a CSpell configuration\nis not found. The following example could be used to block \"cSpell.userWords\" from a workspace.\n\n```jsonc\n\"cSpell.mergeCSpellSettings\": { \"userWords\": false },\n```", + "scope": "resource" + }, "cSpell.noConfigSearch": { "description": "Prevents searching for local configuration when checking individual documents.", "markdownDescription": "Prevents searching for local configuration when checking individual documents.", @@ -1477,6 +1594,14 @@ "scope": "resource", "type": "array" }, + "cSpell.suggestWords": { + "description": "A list of suggested replacements for words. Suggested words provide a way to make preferred suggestions on word replacements. To hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix) - `word: suggestion` - `word->suggestion`\n- Multiple suggestions (not auto fixable) - `word: first, second, third` - `word->first, second, third`", + "items": { + "type": "string" + }, + "markdownDescription": "A list of suggested replacements for words.\nSuggested words provide a way to make preferred suggestions on word replacements.\nTo hint at a preferred change, but not to require it.\n\nFormat of `suggestWords`\n- Single suggestion (possible auto fix)\n - `word: suggestion`\n - `word->suggestion`\n- Multiple suggestions (not auto fixable)\n - `word: first, second, third`\n - `word->first, second, third`", + "type": "array" + }, "cSpell.userWords": { "description": "Words to add to global dictionary -- should only be in the user config file.", "items": { diff --git a/packages/_server/src/config/cspellConfig/CSpellSettingsPackageProperties.mts b/packages/_server/src/config/cspellConfig/CSpellSettingsPackageProperties.mts index 42d7a8b5e6..a9a883a10f 100644 --- a/packages/_server/src/config/cspellConfig/CSpellSettingsPackageProperties.mts +++ b/packages/_server/src/config/cspellConfig/CSpellSettingsPackageProperties.mts @@ -353,6 +353,26 @@ export interface CSpellSettingsPackageProperties extends CSpellSettings { validateDirectives?: CSpellSettings['validateDirectives']; } +export type CSpellFields = keyof CSpellSettingsPackageProperties; + +export type CSpellMergeFields = Exclude< + CSpellFields, + | '$schema' + | 'cache' + | 'description' + | 'failFast' + | 'id' + | 'maxDuplicateProblems' + | 'maxNumberOfProblems' + | 'name' + | 'readonly' + | 'showStatus' + | 'spellCheckDelayMs' + | 'suggestionNumChanges' + | 'suggestionsTimeout' + | 'version' +>; + /** * @hidden */ diff --git a/packages/_server/src/config/cspellConfig/SpellCheckerSettings.mts b/packages/_server/src/config/cspellConfig/SpellCheckerSettings.mts index 40780b0b35..38a5356de2 100644 --- a/packages/_server/src/config/cspellConfig/SpellCheckerSettings.mts +++ b/packages/_server/src/config/cspellConfig/SpellCheckerSettings.mts @@ -1,4 +1,5 @@ import type { EnableFileTypeId, RegExpString } from './annotatedTypes.mjs'; +import type { CSpellMergeFields } from './CSpellSettingsPackageProperties.mjs'; import type { CustomDictionaries, CustomDictionaryEntry } from './CustomDictionary.mjs'; import type { SpellCheckerShouldCheckDocSettings } from './SpellCheckerShouldCheckDocSettings.mjs'; @@ -322,6 +323,32 @@ export interface SpellCheckerSettings extends SpellCheckerShouldCheckDocSettings * @hidden */ // addWordsTo?: AddToTargets; + + /** + * Specify which fields from `.vscode/settings.json` are passed to the spell checker. + * This only applies when there is a CSpell configuration file in the workspace. + * + * The purpose of this setting to help provide a consistent result compared to the + * CSpell spell checker command line tool. + * + * Values: + * - `true` - all settings will be merged + * - `false` - only use `.vscode/settings.json` if a CSpell configuration is not found. + * - `{ words: true, userWords: false }` - specify which fields to pass through to the spell checker. + * + * Note: + * + * If specific fields are specified, they provide the ability to block settings even if a CSpell configuration + * is not found. The following example could be used to block "cSpell.userWords" from a workspace. + * + * ```jsonc + * "cSpell.mergeCSpellSettings": { "userWords": false }, + * ``` + * + * @scope resource + * @default false + */ + mergeCSpellSettings?: boolean | Partial>; } type AutoOrBoolean = boolean | 'auto'; diff --git a/packages/_server/src/config/cspellConfig/cspellConfig.mts b/packages/_server/src/config/cspellConfig/cspellConfig.mts index 4bec7baad9..3494fbb5c6 100644 --- a/packages/_server/src/config/cspellConfig/cspellConfig.mts +++ b/packages/_server/src/config/cspellConfig/cspellConfig.mts @@ -123,6 +123,7 @@ type _VSConfigLanguageAndDictionaries = Pick< | 'language' | 'languageSettings' | 'noSuggestDictionaries' + | 'suggestWords' | 'userWords' | 'words' >; @@ -197,6 +198,7 @@ type _VSConfigFilesAndFolders = Pick< | 'globRoot' | 'ignorePaths' | 'import' + | 'mergeCSpellSettings' | 'noConfigSearch' | 'spellCheckOnlyWorkspaceFiles' | 'useGitignore' diff --git a/packages/_server/src/config/cspellConfig/cspellMergeFields.mts b/packages/_server/src/config/cspellConfig/cspellMergeFields.mts new file mode 100644 index 0000000000..c0ac8265af --- /dev/null +++ b/packages/_server/src/config/cspellConfig/cspellMergeFields.mts @@ -0,0 +1,64 @@ +import type { CSpellUserSettings } from './cspellConfig.mjs'; +import type { CSpellMergeFields } from './CSpellSettingsPackageProperties.mjs'; + +export const cspellMergeFields: Record = { + allowCompoundWords: true, + caseSensitive: true, + dictionaries: true, + dictionaryDefinitions: true, + enabled: true, + enabledLanguageIds: true, + enableFiletypes: true, + enableGlobDot: true, + features: true, + files: true, + flagWords: true, + gitignoreRoot: true, + globRoot: true, + ignorePaths: true, + ignoreRegExpList: true, + ignoreWords: true, + import: true, + includeRegExpList: true, + language: true, + languageId: true, + languageSettings: true, + loadDefaultConfiguration: true, + minWordLength: true, + noConfigSearch: true, + noSuggestDictionaries: true, + numSuggestions: true, + overrides: true, + parser: true, + patterns: true, + pnpFiles: true, + reporters: true, + suggestWords: true, + useGitignore: true, + usePnP: true, + userWords: true, + validateDirectives: true, + words: true, +}; + +const fields = Object.keys(cspellMergeFields) as CSpellMergeFields[]; + +/** + * Filter fields to be passed to cspell. + * @param settings - settings from vscode and imports + * @param mergeCSpellSettings - the filter + * @returns filtered settings + */ +export function filterMergeFields( + settings: Readonly, + mergeCSpellSettings: CSpellUserSettings['mergeCSpellSettings'], +): CSpellUserSettings { + if (mergeCSpellSettings === true) return settings; + const copy = { ...settings }; + mergeCSpellSettings = mergeCSpellSettings || {}; + for (const field of fields) { + if (mergeCSpellSettings[field]) continue; + delete copy[field]; + } + return copy; +} diff --git a/packages/_server/src/config/cspellConfig/cspellMergeFields.test.mts b/packages/_server/src/config/cspellConfig/cspellMergeFields.test.mts new file mode 100644 index 0000000000..731b681e94 --- /dev/null +++ b/packages/_server/src/config/cspellConfig/cspellMergeFields.test.mts @@ -0,0 +1,17 @@ +import { describe, expect, test } from 'vitest'; + +import { filterMergeFields } from './cspellMergeFields.mjs'; + +describe('cspellMergeFields', () => { + test.each` + settings | filter | expected + ${{}} | ${true} | ${{}} + ${{ words: [] }} | ${true} | ${{ words: [] }} + ${{ words: [] }} | ${undefined} | ${{}} + ${{ words: [] }} | ${false} | ${{}} + ${{ words: [], enabled: true }} | ${{ words: false, enabled: true }} | ${{ enabled: true }} + ${{ words: [], spellCheckDelayMs: 500 }} | ${{ enabled: true }} | ${{ spellCheckDelayMs: 500 }} + `('filterMergeFields $settings $filter', ({ settings, filter, expected }) => { + expect(filterMergeFields(settings, filter)).toEqual(expected); + }); +}); diff --git a/packages/_server/src/config/documentSettings.mts b/packages/_server/src/config/documentSettings.mts index 465128b0f0..25e56fb309 100644 --- a/packages/_server/src/config/documentSettings.mts +++ b/packages/_server/src/config/documentSettings.mts @@ -38,6 +38,7 @@ import { URI as Uri, Utils as UriUtils } from 'vscode-uri'; import type { DocumentUri, ServerSideApi, VSCodeSettingsCspell, WorkspaceConfigForDocument } from '../api.js'; import { extensionId } from '../constants.mjs'; import { uniqueFilter } from '../utils/index.mjs'; +import { filterMergeFields } from './cspellConfig/cspellMergeFields.mjs'; import type { CSpellUserSettings } from './cspellConfig/index.mjs'; import { canAddWordsToDictionary } from './customDictionaries.mjs'; import { handleSpecialUri } from './docUriHelper.mjs'; @@ -307,6 +308,7 @@ export class DocumentSettings { id: 'VSCode-Config', ignorePaths: ignorePaths.concat(ExclusionHelper.extractGlobsFromExcludeFilesGlobMap(exclude)), }; + return cSpellConfigSettings; } @@ -318,26 +320,21 @@ export class DocumentSettings { return this.fetchSettingsForUri(uriSpecial.toString()); } const fsPath = path.normalize(uri.fsPath); - const cSpellConfigSettingsRel = await this.fetchSettingsFromVSCode(docUri); - const cSpellConfigSettings = await this.resolveWorkspacePaths(cSpellConfigSettingsRel, docUri); - const settings = await searchForConfig(fsPath); + const vscodeCSpellConfigSettingsRel = await this.fetchSettingsFromVSCode(docUri); + const vscodeCSpellConfigSettingsForDocument = await this.resolveWorkspacePaths(vscodeCSpellConfigSettingsRel, docUri); + const settings = vscodeCSpellConfigSettingsForDocument.noConfigSearch ? undefined : await searchForConfig(fsPath); const rootFolder = this.rootFolderForUri(docUri); const folders = await this.folders; const folder = await this.findMatchingFolder(docUri, rootFolder); - const cSpellFolderSettings = resolveConfigImports(cSpellConfigSettings, folder.uri); + const vscodeCSpellSettings = resolveConfigImports(vscodeCSpellConfigSettingsForDocument, folder.uri); const globRootFolder = folder !== rootFolder ? folder : folders[0] || folder; - const settingsToMerge: CSpellUserSettings[] = []; - if (this.defaultSettings !== _defaultSettings) { - settingsToMerge.push(this.defaultSettings); - } - settingsToMerge.push(this.importedSettings()); - settingsToMerge.push(cSpellFolderSettings); - if (settings) { - settingsToMerge.push(settings); - } - - const mergedSettings = mergeSettings(settingsToMerge[0], ...settingsToMerge.slice(1)); + const mergedSettingsFromVSCode = mergeSettings(this.importedSettings(), vscodeCSpellSettings); + const mergedSettings = mergeSettings( + this.defaultSettings, + filterMergeFields(mergedSettingsFromVSCode, !settings || vscodeCSpellSettings['mergeCSpellSettings']), + settings, + ); const enabledFiletypes = extractEnableFiletypes(mergedSettings); const spellSettings = applyEnableFiletypes(enabledFiletypes, mergedSettings); @@ -345,7 +342,7 @@ export class DocumentSettings { const { ignorePaths = [], files = [] } = fileSettings; const globRoot = Uri.parse(globRootFolder.uri).fsPath; - if (!files.length && cSpellConfigSettings.spellCheckOnlyWorkspaceFiles !== false) { + if (!files.length && vscodeCSpellConfigSettingsForDocument.spellCheckOnlyWorkspaceFiles !== false) { // Add file globs that will match the entire workspace. folders.forEach((folder) => files.push({ glob: '/**', root: Uri.parse(folder.uri).fsPath })); fileSettings.enableGlobDot = fileSettings.enableGlobDot ?? true; @@ -358,7 +355,7 @@ export class DocumentSettings { setIfDefined(includeOptions, 'dot', fileSettings.enableGlobDot); const includeGlobMatcher = new GlobMatcher(files, includeOptions); - const cSpell = cSpellConfigSettings; + const cSpell = vscodeCSpellConfigSettingsForDocument; const ext: ExtSettings = { uri: docUri, vscodeSettings: { cSpell }, @@ -411,6 +408,7 @@ function readSettingsFiles(paths: string[]) { // log('readSettingsFiles:', paths); const existingPaths = paths.filter((filename) => exists(filename)); log('readSettingsFiles:', existingPaths); + console.error('readSettingsFiles: %o', existingPaths); return existingPaths.map((file) => cspellReadSettingsFile(file)); } diff --git a/packages/_server/src/config/documentSettings.test.mts b/packages/_server/src/config/documentSettings.test.mts index 9cef0dd6e1..32dfeb921c 100644 --- a/packages/_server/src/config/documentSettings.test.mts +++ b/packages/_server/src/config/documentSettings.test.mts @@ -54,6 +54,7 @@ const cspellConfigInVsCode: CSpellUserSettings = { '${workspaceFolder:_server}/sampleSourceFiles/cSpell.json', ], enabledLanguageIds: ['typescript', 'javascript', 'php', 'json', 'jsonc'], + mergeCSpellSettings: true, }; const sampleFiles = { @@ -303,7 +304,7 @@ describe('Validate DocumentSettings', () => { `('isExcludedBy $filename', async ({ filename, expected }: IsExcludeByTest) => { const mockFolders: WorkspaceFolder[] = [workspaceFolderRoot, workspaceFolderClient, workspaceFolderServer]; mockGetWorkspaceFolders.mockReturnValue(Promise.resolve(mockFolders)); - mockGetConfiguration.mockReturnValue(Promise.resolve([{}, {}])); + mockGetConfiguration.mockReturnValue(Promise.resolve([{ mergeCSpellSettings: true }, {}])); const docSettings = newDocumentSettings(); const configFile = Path.join(pathSampleSourceFiles, 'cspell-exclude-tests.json'); await docSettings.registerConfigurationFile(configFile); diff --git a/packages/_server/src/server.mts b/packages/_server/src/server.mts index eb7089878a..594aec137c 100644 --- a/packages/_server/src/server.mts +++ b/packages/_server/src/server.mts @@ -67,7 +67,7 @@ const overRideDefaults: CSpellUserSettings = { const defaultSettings: CSpellUserSettings = { ...CSpell.mergeSettings(getDefaultSettings(), CSpell.getGlobalSettings(), overRideDefaults), checkLimit: defaultCheckLimit, - enabled: false, + // enabled: false, }; const defaultDebounceMs = 50; // Refresh the dictionary cache every 1000ms. diff --git a/packages/client/src/settings/configFields.ts b/packages/client/src/settings/configFields.ts index f14e444a78..43a1919384 100644 --- a/packages/client/src/settings/configFields.ts +++ b/packages/client/src/settings/configFields.ts @@ -34,6 +34,7 @@ export const ConfigFields: CSpellUserSettingsFields = { mapOfEnabledFileTypes: 'mapOfEnabledFileTypes', maxDuplicateProblems: 'maxDuplicateProblems', maxNumberOfProblems: 'maxNumberOfProblems', + mergeCSpellSettings: 'mergeCSpellSettings', noSuggestDictionaries: 'noSuggestDictionaries', showAutocompleteSuggestions: 'showAutocompleteSuggestions', showCommandsInEditorContextMenu: 'showCommandsInEditorContextMenu',