Skip to content

Conversation

@Zamiell
Copy link

@Zamiell Zamiell commented Dec 25, 2025

Closes #168411.

Here's the summary from Claude:

Fix for Bug #168411: Multi-language workspace setting should override single-language user setting

Problem Description

When a user has a single-language override in their user settings (e.g., [javascript]) and a multi-language override in their workspace settings (e.g., [javascript][typescript]), the single-language user setting was incorrectly taking precedence over the multi-language workspace setting.

Expected Behavior

Workspace settings should always override user settings, regardless of whether they are single-language or multi-language overrides.

Actual Behavior (Before Fix)

Single-language overrides were always given priority over multi-language overrides, even when the multi-language override came from a higher-priority configuration source (workspace).

Root Cause

The issue was in the configuration merging logic. When merging user and workspace configurations:

  1. Both the single-language [javascript] override from user settings and the multi-language [javascript][typescript] override from workspace settings were kept in the merged result
  2. The getContentsForOverrideIdentifer method had logic that always gave single-language overrides precedence over multi-language ones
  3. This precedence was applied globally without considering the configuration source (user vs workspace)

After merging, there was no way to distinguish which override came from which source, so the single-language override always won.

Solution

The fix modifies the merge function in ConfigurationModel to remove single-language overrides from earlier configuration sources when a multi-language override is added from a later source.

Changes Made

1. Modified ConfigurationModel.merge() (configurationModels.ts)

When merging configurations, if a multi-language override is being added and it doesn't match any existing override by identifier array, the merge function now:

  • Checks each identifier in the multi-language override
  • Removes any existing single-language override for that identifier
  • Then adds the new multi-language override
for (const otherOverride of other.overrides) {
    const [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));
    if (override) {
        // Merge if identifiers match exactly
        this.mergeContents(override.contents, otherOverride.contents);
        override.keys.push(...otherOverride.keys);
        override.keys = arrays.distinct(override.keys);
    } else {
        // When adding a multi-language override, remove any existing single-language overrides
        // for the same identifiers to allow workspace multi-language settings to override
        // user single-language settings
        if (otherOverride.identifiers.length > 1) {
            for (const identifier of otherOverride.identifiers) {
                const singleLangIndex = overrides.findIndex(
                    o => o.identifiers.length === 1 && o.identifiers[0] === identifier
                );
                if (singleLangIndex !== -1) {
                    overrides.splice(singleLangIndex, 1);
                }
            }
        }
        overrides.push(objects.deepClone(otherOverride));
    }
}

2. Added a test (configurationModels.test.ts)

n/a

Behavior Analysis

Scenario 1: User single-language + Workspace multi-language (Bug #168411)

// User: [javascript] with tabSize: 2
// Workspace: [javascript][typescript] with tabSize: 4
// Result: The [javascript] override is removed, only [javascript][typescript] remains
// Getting value for 'javascript': 4 ✓ (workspace wins)

Scenario 2: Single config with both override types (Existing test)

// Single config: [x] with a: 3, then [x][y] with a: 2
// Result: Both overrides remain
// Getting value for 'x': 3 ✓ (single-language wins due to specificity)

Why This Works

  1. Configuration source precedence is preserved: When merging user and workspace configs, workspace overrides can remove user overrides, ensuring workspace always wins
  2. Specificity within the same source is preserved: When both overrides exist in a single configuration (not merged), single-language still takes precedence over multi-language
  3. The distinction is maintained: By removing conflicting overrides during merge, the merged result can properly apply the single-language precedence rule only within the same source

Testing

The fix includes a test case that verifies:

  1. User configuration with [javascript] override setting editor.tabSize: 2
  2. Workspace configuration with [javascript][typescript] override setting editor.tabSize: 4
  3. After merging, querying the configuration for javascript returns 4 (workspace value)

Test Output

✓ Workspace multi-language setting should override user single-language setting

Files Changed

  • src/vs/platform/configuration/common/configurationModels.ts - Modified merge() function
  • src/vs/platform/configuration/test/common/configurationModels.test.ts - Fixed test case structure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

local language specific setting priority is lower than user level language specific setting

2 participants