Skip to content

Instantly share code, notes, and snippets.

@rcdailey
Created December 14, 2025 16:31
Show Gist options
  • Select an option

  • Save rcdailey/a2d6845082cddfd2ae3475b7b7cd3527 to your computer and use it in GitHub Desktop.

Select an option

Save rcdailey/a2d6845082cddfd2ae3475b7b7cd3527 to your computer and use it in GitHub Desktop.

To implement settings layers support in a JetBrains Rider plugin, you need to understand Rider's three-layer settings system and use the ReSharper Platform SDK APIs. Here's how to do it:

Understanding Settings Layers

JetBrains Rider uses a layered settings system where higher layers override lower ones1:

  1. Personal layer - User-specific settings for the current solution
  2. Team-shared layer - Settings shared across the team (stored in VCS)
  3. Computer/Global layer - Settings stored on the local machine for all instances

The layers are applied top-down, with more specific layers overriding general ones2:

  • Computer-level settings: Stored in user's LocalAppData, accessible to all ReSharper instances
  • Solution-level settings:
    • .sln.dotSettings (team-shared, stored in VCS)
    • .sln.dotSettings.user (private user settings)
  • Project-level settings:
    • .csproj.dotSettings (team-shared)
    • .csproj.dotSettings.user (private user settings)

Creating Settings with Layer Support

1. Define Your Settings Class

Create a settings key class decorated with the SettingsKey attribute:

[SettingsKey(typeof(EnvironmentSettings), "My Plugin Settings")]
public class MyPluginSettingsKey
{
    [SettingsEntry(false, "Enable Feature")]
    public bool EnableFeature;
    
    [SettingsEntry("Default Value", "My String Setting")]
    public string MyStringSetting;
}

2. Create an Options Page

Implement an options page that supports layer-based settings:

[OptionsPage(Pid, "My Plugin", typeof(FeaturesEnvironmentOptionsThemedIcons.CodeInspections), 
    ParentId = ToolsPage.PID)]
public class MyPluginOptionsPage : SimpleOptionsPage
{
    private const string Pid = "MyPluginOptions";
    
    public MyPluginOptionsPage([NotNull] Lifetime lifetime, 
        [NotNull] OptionsSettingsSmartContext optionsSettingsSmartContext) 
        : base(lifetime, optionsSettingsSmartContext)
    {
        // Add boolean option that respects layers
        AddBoolOption((MyPluginSettingsKey key) => key.EnableFeature, 
            "Enable my plugin feature");
            
        // Add string option
        AddStringOption((MyPluginSettingsKey key) => key.MyStringSetting, 
            "My string setting");
    }
}

3. Reading Settings with Layer Awareness

Use ISettingsStore with appropriate ContextRange to read settings:

public class MyPluginComponent
{
    private readonly ISettingsStore _settingsStore;
    
    public MyPluginComponent(ISettingsStore settingsStore)
    {
        _settingsStore = settingsStore;
    }
    
    public bool GetFeatureEnabled(IDataContext context)
    {
        // Use ContextRange.Smart to respect current layer editing mode
        var contextBoundStore = _settingsStore.BindToContextTransient(
            ContextRange.Smart.GetDataContext(context));
            
        return contextBoundStore.GetValue((MyPluginSettingsKey key) => key.EnableFeature);
    }
    
    // Alternative: Bind to specific context ranges
    public bool GetGlobalSetting()
    {
        var contextBoundStore = _settingsStore.BindToContextTransient(ContextRange.ApplicationWide);
        return contextBoundStore.GetValue((MyPluginSettingsKey key) => key.EnableFeature);
    }
}

4. Layer-Aware Settings Access

The key to layer support is using the correct ContextRange2:

  • ContextRange.ApplicationWide: Accesses computer-level settings
  • ContextRange.Smart: Context depends on user's current settings editing mode, automatically respecting the active layer
  • ContextRange.ManuallyRestrictWritesToOneContext: For more granular control
public class LayerAwareSettingsViewModel : AAutomation
{
    public IProperty<bool> FeatureEnabled { get; }
    
    public LayerAwareSettingsViewModel(Lifetime lifetime, ISettingsStore settingsStore, 
        IDataContext dataContext)
    {
        // Bind to live context that respects layers
        var contextBoundStore = settingsStore.BindToContextLive(lifetime, 
            ContextRange.Smart.GetDataContext(dataContext));
            
        FeatureEnabled = contextBoundStore.GetValueProperty(lifetime, 
            (MyPluginSettingsKey key) => key.EnableFeature);
    }
}

Key Points

  • The OptionsSettingsSmartContext in your options page automatically handles layer-aware reading and writing2
  • Use ContextRange.Smart when you want the system to automatically determine the appropriate layer based on user context2
  • Settings defined this way will automatically appear in Rider's layer management UI and respect the layer hierarchy
  • Team-shared settings will be stored in .sln.dotSettings files that can be committed to version control

This approach ensures your plugin settings integrate seamlessly with Rider's existing layer-based configuration system, allowing users to configure settings at the appropriate scope (personal, team, or global) just like built-in Rider features.

Footnotes

  1. Settings | ReSharper Platform SDK Documentation (19%)

  2. Add Settings to ReShaper Options | ReSharper Platform SDK (81%) 2 3 4

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