vscode-spell-checker icon indicating copy to clipboard operation
vscode-spell-checker copied to clipboard

[Bug] [Suggestion]: A collection of problems with "cSpell.words" settings + suggestions for (logical) improvements

Open Trummler12 opened this issue 2 months ago • 1 comments

TL;DR

  • "cSpell.words" in folder settings currently overwrites workspace settings, even if set to an empty list, instead of merging as expected.
  • "userWords" and "words" are not clearly differentiated or documented, leading to confusion.
  • "Quick Fix..." actions do not always add words where the user expects, especially in multi-root or submodule setups.
  • There is no way to control or visualize the precedence/merging/overwriting of word lists.
  • Suggestions: Make merging the default, add explicit overwrite options, clarify documentation, and improve the Quick Fix UX. (More below)

User Story

Setup

My git workspace is quite complex: There's one large mother repository (called "ProgrammierZeugs") I'm working in for all kinds of mainly school-related stuff - with one (Project) Folder each for (almost) every School Module we've had so far + some other semi-school-related and one or two school-unrelated project folders; Currently I'm at about 20 Project Folders in total, most of which being simple directories but some of them (currently 5) having their own repository, being added to the "ProgrammierZeugs" repo as Submodules. This mother repository of mine is cloned on 2 different devices: on my School Laptop (Win11, Lenovo) and on a Laboratory PC at work (Win10, Lenovo; 1 Submodule (company project) is exclusive to this location) and of necessity, I'm switching between them almost every day. Now, a few weeks ago, I've been annoyed about the differences between the code --list-extensions that's built up between these devices; That's why I've created an Extensions.md to document the code --list-extensions on each device as well as all differences between those lists, to then analyze the usefulness of, the compatibility between and explore some recommended extensions - all with the help of the CustomGPT https://chatgpt.com/g/g-ZpZUQbCxM-vs-code-copilot; The result was a cleaned-up and extended consolidated list of extensions which I could satisfyingly sync the Extensions on both devices with and of course also use as a comfortable long-term way to easily keep track of any changes to Extensions on any device (and as an easy copy/paste source of personal Extension Recommendations + specify Warnings, Settings recommendations and lots of other useful stuff)! I've also taken a very similar approach to sync up & update the User Settings on both devices.

Experiences with cSpell - a long story of solving mysteries

In the course of syncing the Extensions between both devices and looking for recommendations, the VS Code Copilot mentioned the Extension streetsidesoftware.code-spell-checker to be quite useful; So I've tried it. Despite some starting difficulties, I've quickly learned to like this Extension a lot since it successfully managed to point out quite some typos, not only done by me but also by others - which is already really fun to me xD I've used the "Quick Fix..." action "Add: [word] to workspace settings" (=>saved in the "cSpell.words" list in ProgrammierZeugs.code-workspace) on every reasonable occasion I could lay my hands upon - starting with Extensions.md (since many Extension name( element)s are indeed valid but (rightfully) not detected as such) and then moving to other .md files; But then, some days after falling in love with this extension, I've entered the Submodule "M450-Testing" and used the "Quick Fix..." action "Add: [word] to folder settings" on the words "airdata", "endmacro" and "weatherdata" in order to add those words to the folder settings of "M450-Testing" (M450-Testing\.vscode\settings.json) - or so I thought... After doing that (but sadly only realized that days afterwards, by then losing all connection to what I had done in M450-Testing), the Workspace "cSpell.words" (in ProgrammierZeugs.code-workspace) didn't have any effect anymore, thus the "Quick Fix..." action "Add: [word] to workspace settings" also (seemingly) not doing anything anymore and resulting in the Workspace's "cSpell.words" entries themselves being marked as "unknown word"; I've tried to investigate and observed that words are still being added to the Workspace's "cSpell.words", but hours of investigating didn't let me find the cause of them not having any effect anymore; Instead, after hours of trial and error, I've figured out that changing "cSpell.words" to "cSpell.userWords" somehow managed to have the extension recognize the words again. ~Still no idea how and why and how "cSpell.userWords" is supposed to be any different from "cSpell.words". Annoyingly, the "Quick Fix..." action "Add: [word] to workspace settings" only added words to "cSpell.words" (restoring that setting if deleted), always initially taking no effect whatsoever and being marked themselves as "unknown word". For weeks (until) now, I've settled in the routine of manually copying the contents of "cSpell.words" over to the list of "cSpell.userWords" - after every single word I've added to the Workspace - (later adopting a simpler strategy of simply replacing the distance between with a "," - but still needlessly laborious). Today, I've tried to add "**/*.code-workspace" to "cSpell.ignorePaths" or to add "*.code-workspace": false"/""code-workspace": false" to "cSpell.enabledFileTypes" in order to exclude the ProgrammierZeugs.code-workspace from cSpell checks, hoping that the Spelling Issues list of the Spell checker stops updating after every single word added to the Workspace "cSpell.words" - but no matter what I tried, nothing here worked either; Then, after some Copilot "fix" attempts, some combination of "cSpell.enabledFileTypes": { ..., "json": false, "jsonc": false }" and "cSpell.ignorePaths": [ "**/*.code-workspace" ]" finally did the trick and successfully excluded ProgrammierZeugs.code-workspace from the Spell Checker; After some testing around, I've deduced specifically the "cSpell.enabledFileTypes": { "jsonc": false }" to be responsible for successfully excluding ProgrammierZeugs.code-workspace from the Spell Checker; Man, can you imagine how insanely confused this left me to be?! At least I now knew that the Workspace Settings at least work given certain (mysterious) circumstances. I've tested the same thing with a .puml file that's been successfully excluded with "cSpell.enabledFileTypes": { "plantuml": false }"; Here, I've also been confused about why "puml": false" didn't work but at some point found "files.associations": { "*.puml": "plantuml" }" in the Workspace settings - which explained a lot - but for "*.code-workspace", no matter where I've tried to look, I couldn't find anything that resembled a file association such as "files.associations": { "*.code-workspace": "jsonc" }"; Only when I've finally asked Copilot for help, I've got an explanation: Apparently, VS Code natively defines a files.association for "*.code-workspace": "jsonc"; Okay, one more mystery solved - But that still doesn't explain why "cSpell.ignorePaths": [ "**/*.code-workspace" ]" doesn't work! This is where I've started to plan creating an issue with the title "[Bug]: unable to specifically disable FileType "code-workspace" or ignorePath "**/*.code-workspace" due to built-in associations with "jsonc". But that plan quickly got interrupted: While double-checking for any "files.associations" settings I may have missed in either the User, Workspace of any relevant Folder Settings, I've found the following segment at the bottom of .vscode\settings.json (the root folder settings of my mother repository):

  "cSpell.words": [
    "airdata",
    "endmacro",
    "weatherdata"
  ],

What I then wondered about (knowing how in the ProgrammierZeugs.code-workspace, almost every "cSpell.words" entry is itself marked as an "unknown word"):

  • Even though the setting "cSpell.words" is being used, none of those words are marked as "unknown word";
  • Aren't those words supposed to belong to M450-Testing\.vscode\settings.json? Then, I've proceeded with the following steps:
  • open ProgrammierZeugs.code-workspace and copied all of "cSpell.userWords" to "cSpell.words" => as expected, no entry of "cSpell.userWords" was marked as "Unknown word" 'thanks' to "cSpell.userWords"
  • empty the list of "cSpell.userWords" => Most entries of "cSpell.words" were now marked as "Unknown word"
  • copy the "cSpell.words" from .vscode\settings.json to the "cSpell.words" of ProgrammierZeugs.code-workspace => None of those words were marked as "Unknown word"
  • delete the "cSpell.words" entry in .vscode\settings.json (expecting those 3 words to be marked as "Unknown word" again in ProgrammierZeugs.code-workspace) => All of a sudden, the number of issues reported by the Spell Checker went down from >150 to <10 and ALL words in ProgrammierZeugs.code-workspace were now being recognized as valid words again - including all of those that had been marked as "Unknown word" before! => Apparently, the mere presence of a "cSpell.words" entry in any Folder Settings on the same or a higher level (even if it's an empty list) completely disables & overwrites the Workspace "cSpell.words" - even if the Folder "cSpell.words" is defined as an empty list ("cSpell.words": [])! Man, what a relief that has been when I've finally realized what was actually happening all those weeks!

Summary of key Observations

  • The "cSpell.words" setting in Folder Settings takes overwriting precedence over the Workspace setting, even when "cSpell.words" is defined as an empty list.
  • The purpose of "cSpell.userWords" is unclear when trying to compare it with "cSpell.words".
  • The "Quick Fix..." action "Add: [word] to folder settings" only recognizes the root .vscode\settings.json, ignoring any local .vscode\settings.json
  • The "Quick Fix..." action "Add: [word] to workspace settings" doesn't recognize Submodules, instead only adds words to the mother Repo's [Workspace].code-workspace, leaving the Submodule's Workspace settings shared with other Team Members unchanged
  • It still needs to be investigated how other cSpell settings (other than "cSpell.words") may or may not overwrite each other in a similar manner as "cSpell.words" does.
  • "cSpell.ignorePaths" doesn't seem to work, at least not as intended
  • "cSpell.enabledFileTypes" also seems to have some (partially) related issues but I don't know much the Developer of this Extension can do about that; but since *.code-workspace is natively associated with jsonc, this currently leaves an empty spot for *.code-workspace files; Wouldn't that still allow room for specific targeting of *.code-workspace files despite file associations? I don't see any reason for conflicts here.

Suggestions for Improvements

  1. Merge "cSpell.words" Across Settings by Default
    Currently, "cSpell.words" in a folder settings file completely overwrites the workspace-level list, even if the folder list is empty.
    Suggestion:

    • Change the default behavior so that "cSpell.words" from all relevant settings levels (user, workspace, folder) are merged (additive), unless an explicit overwrite is requested.
    • This would match the behavior of most other VS Code settings and reduce confusion.
    • Make sure that priorities are always respected, e.g.: [Explicit overwrite settings] > Folder > Workspace > User > Global/Defaults.
  2. Add Overwrite Control Options
    Not all users may want merging in every scenario.
    Suggestion:

    • Introduce a setting such as "cSpell.overwriteGlobalWords": true|false (default: false) to allow explicit control over whether a local "cSpell.words" list should overwrite or merge with higher-level lists.
    • Optionally, add "cSpell.overwriteLocalWords" for the reverse direction (though this is relevant less often, some people might still find this useful).
    • Provide clear visual indicators and warnings in the UI when a local setting is being overwritten due to an overwrite setting. That way, a User never needs to be confused again and is given all context needed to easily find where to take action in case they don't like an overwrite interaction.
  3. Clarify and Document the Role of "userWords" vs. "words"
    The distinction between "cSpell.userWords" and "cSpell.words" is currently unclear and not well documented.
    Suggestion:

    • Update the documentation to clearly explain the intended use cases and precedence of both settings.
    • Consider whether "userWords" is still needed, or if its functionality could be unified with "words" (e.g., by treating "words" in user settings as user-wide words).
    • In practice, "cSpell.words" defined in the User Settings (currently not having any effect) would be practically synonym to what "cSpell.userWords" were meant to be; Therefore, I would recommend dropping "cSpell.userWords" altogether and instead allowing "cSpell.words" to be supported in the User Settings as well.
    • If "userWords" is kept, allow it to be unaffected by "overwriteGlobalWords" (i.e., always additive), or introduce a separate "cSpell.overrideGlobalUserWords" for full control; However, for a consistent full implementation, it would require 4 distinct overwrite settings (words => words, userWords => userWords, words => userWords, userWords => words) which would be unnecessarily complicated; So instead of risking implementing something too complicated or some possibly confusing/inconsistent in-between-approach, I'd like to use this as an additional argument to just simplify "cSpell.userWords" and "cSpell.words" to just "cSpell.words".
  4. Improve "Quick Fix..." Actions and UX
    The "Quick Fix..." actions for adding words to workspace or folder settings do not always target the expected settings file, especially in multi-root or submodule setups.
    Suggestion:

    • Fix true folder Settings to be recognized by cSpell (any "cSpell.words" defined in a settings.json file that is not in the workspace root (e.g., M450-Testing\.vscode\settings.json or any other subfolder) currently has no effect).
    • Make "Add: [word] to workspace settings" aware of submodules and multi-root workspaces, so words are added to the correct workspace or submodule settings.
    • Maybe even add a distinction between "Add: [word] to workspace settings" and "Add: [word] to mother workspace settings" when cSpell detects the User being in a Submodule.
    • Make "Add: [word] to folder settings" always target the closest relevant .vscode/settings.json (not just the root; always looking upwards - after looking at the current level of course).
    • Show a confirmation or info message indicating where the word was actually added.
  5. Functional distinction between "Workspace settings" and "Folder settings": Currently, "folder settings" (e.g., .vscode/settings.json) affect all files and subfolders below their location, including submodules. In contrast,"workspace settings" (e.g., [workspace].code-workspace) should ideally only apply to the workspace itself and explicitly not to any submodules or folders that are themselves separate repositories/workspaces.
    This would allow users to define spelling rules that apply to the main project, while submodules (which may have their own teams, conventions, or wordlists) remain unaffected by the parent workspace's settings.
    Suggestion:

    • Make "folder settings" always apply recursively to all files/folders below, including submodules.
    • Make "workspace settings" only apply to the workspace root and its direct contents, but not to submodules or nested repositories.
    • This separation would make it much easier to manage large, multi-repo setups and avoid accidental word list conflicts between main projects and submodules.
  6. Allow Fine-Grained Ignore and Enable Controls for File Types
    Excluding specific files (e.g., *.code-workspace) from spell checking is currently unintuitive due to VS Code's built-in file associations.
    Suggestion:

    • Improve the interaction between "cSpell.ignorePaths" and "cSpell.enabledFileTypes" so that users can reliably exclude or include files by pattern, regardless of file associations.
    • Document the effect of VS Code's built-in file associations on cSpell's behavior, and provide examples for common cases.
  7. Visualize and Debug Word List Precedence
    Users currently have no way to see which "cSpell.words" list is active or why a word is (not) recognized.
    Suggestion:

    • Add a command or UI panel to show the effective word list for the current file, including the source (user, workspace, folder) and any overrides.
    • When a word is not recognized due to an override, show a warning or info message with the reason.
  8. General Documentation and UX Improvements

    • Provide a clear table or diagram in the documentation showing how "cSpell.words" and "cSpell.userWords" are resolved and merged/overwritten across all settings levels.
    • Add best-practice recommendations for teams working with multi-root workspaces and submodules.
  9. Flag Suboptimal Spellings / Maintain a Blacklist of Discouraged Words
    Some words (e.g., "consistant", "alltogether") are technically valid but considered suboptimal or outdated.
    Suggestion:

    • Add a setting "cSpell.flagSuboptimalSpellings": true|false (default: false).
    • Of course, this would also require maintaining an individual list of suboptimal words for each and every language.
    • Allow users to define a "cSpell.suboptimalWords" object mapping discouraged words to their preferred alternatives.
    • When enabled, cSpell should flag these words and suggest the preferred spelling.
    • This would help teams enforce style guides and avoid common "false friends" or outdated spellings.
    • UPDATE: After 'finalizing' the Text for this Issue, I've attempted to clean up my Workspace "cSpell.words" list, removing words I had added at some point but now being covered by cSpell Language Extensions I've installed in the meantime; For this, I've temporarily added an empty "cSpell.words" to my root folder settings; And since my settings only allow a maximum of 100 Spelling Issues to be reported per file, I've also temporarily copied the cleaned list of the first 100 words to a "cSpell.userWords" so they won't be reported anymore, allowing me to then clean the rest of the list; And after removing those temporary setting instances again, cSpell suddenly started to (correctly) report "consistant" and "alltogether" as "Misspelled words"; However, I've changed nothing that could possibly be related to these two words; I did test-wise remove "cSpell.allowCompoundWords": true, from both ProgrammierZeugs.code-workspace and .vscode\settings.json (root folder Settings), but that was dozens of minutes prior. ... Okay, it is indeed related to removing those "cSpell.allowCompoundWords": true,instances - but why did it take that long to take effect? Well, anyhow, this shouldn't affect the suggestion itself all that much since distinguishing between "unknown", "incorrect", "suboptimal" (new) and "correct" being reasonable holds true regardless ^^

Optional/Advanced:

  • Consider allowing "cSpell.words" to support both the current global array form and an extended, language-aware or pattern-aware form. Two possible approaches:

a) Backwards-compatible and simple (recommended):

  • Keep the current array form for global words:
    "cSpell.words": [ "AKSEP", "Trummler", "iconify", "openai" ]
    
  • Optionally, allow an object for language-specific or pattern-specific words, which is merged with the global array:
    "cSpell.words": {
      // [optional] Global words (applies to all languages), maybe even allow Key Word Aliases such as "all"
      "global": [ "AKSEP", "Trummler", "iconify", "openai" ],
      // English-specific words
      "en": [ "rizz", "yeet", "bussin", "grindset", "lowkey", "highkey", "stan", "sneakerhead" ],
      // German-specific words
      "de": [ "rizz", "digga", "sheesh", "babo", "Alphakevin", "flexen", "yeet", "delulu", "grindset", "sliden", "lowkey", "highkey" ]
      // Optionally, file pattern keys could be supported as well
      // "*.md": [ "MarkdownOnlyWord" ]
    }
    
  • The extension should merge both forms if present, so users can keep things simple for global words and add language- or pattern-specific words only when needed.

b) Explicit separation (alternative):

  • Keep "cSpell.words" as a global array, as today:
    "cSpell.words": [ "AKSEP", "Trummler", "iconify", "openai" ]
    
  • Add a new setting for language- or pattern-specific words, e.g.:
    "cSpell.languageWords": {
      "en": [ "rizz", "yeet", "bussin", "grindset", "lowkey", "highkey", "stan", "sneakerhead" ],
      "de": [ "rizz", "digga", "sheesh", "babo", "Alphakevin", "flexen", "yeet", "delulu", "grindset", "sliden", "lowkey", "highkey" ]
    }
    
    or
    "cSpell.wordsByLanguage": {
      "en": [ "rizz", "yeet", "bussin", "grindset", "lowkey", "highkey", "stan", "sneakerhead" ],
      "de": [ "rizz", "digga", "sheesh", "babo", "Alphakevin", "flexen", "yeet", "delulu", "grindset", "sliden", "lowkey", "highkey" ]
    }
    
  • This keeps the global list simple and allows advanced users to opt into more granular control only if needed.

In both cases, the default remains as simple as possible for most users, while advanced users gain the flexibility to define language- or pattern-specific word lists.

A similar language-specific logic could be applied to Flag Suboptimal Spellings as well, but without the need for distinct global definitions.

Closing words

Thank you for your work on cSpell and for considering these suggestions!
I really like cSpell and also that wide-range language support you provide!
I’m happy to provide further details or help test improvements if needed.

-# Aw man, I'm really wondering how many Sub-Issues the contents of this post will result in 😅

Trummler12 avatar Oct 08 '25 12:10 Trummler12

@Trummler12,

Thank you for the feedback. I can address the tldr, but it will take me a bit to evaluate the design.

You are right, the way words are merged in the settings is unintuitive and I wish it was better.

At the core is the way VS Code manages settings: Please see VS Code Settings Precedence. VS Code supports a very limit merge capability for settings. It does not merge arrays. Extensions do not control that behavior. As a work around, cSpell.userWords was added in addition to cSpell.words.

My suggestion is to add a cspell.config.yaml or cspell.json file in each of your workspaces / folders. The merge rules apply.

I would like to improve the usability experience when using command & menu items to add words. It is not clear where a user wants a word stored. So, the extension asks based upon the configuration settings it can find. But that can get annoying if it keeps asking.

I'll read your proposal above and see how it can be used to improve the overall experience.

Jason3S avatar Oct 27 '25 06:10 Jason3S