Skip to content

Commit

Permalink
Fixed configuration issue where data was being cleared of previous se…
Browse files Browse the repository at this point in the history
…ctions (#317)

* Fixed configuration issue where data was being cleared of previous sections
* Updated scoped configuration to better handler on reload
  • Loading branch information
david-driscoll authored Aug 15, 2020
1 parent 1497f35 commit 5571121
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 121 deletions.
2 changes: 1 addition & 1 deletion sample/SampleServer/TextDocumentHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public async Task<Unit> Handle(DidOpenTextDocumentParams notification, Cancellat
{
await Task.Yield();
_logger.LogInformation("Hello world!");
await _configuration.GetScopedConfiguration(notification.TextDocument.Uri);
await _configuration.GetScopedConfiguration(notification.TextDocument.Uri, token);
return Unit.Value;
}

Expand Down
30 changes: 29 additions & 1 deletion src/Protocol/Models/ConfigurationItem.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
using System;
using OmniSharp.Extensions.LanguageServer.Protocol.Serialization;

namespace OmniSharp.Extensions.LanguageServer.Protocol.Models
{
public class ConfigurationItem
public class ConfigurationItem : IEquatable<ConfigurationItem>
{
[Optional] public DocumentUri ScopeUri { get; set; }
[Optional] public string Section { get; set; }

public bool Equals(ConfigurationItem other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(ScopeUri, other.ScopeUri) && Section == other.Section;
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((ConfigurationItem) obj);
}

public override int GetHashCode()
{
unchecked
{
return ( ( ScopeUri != null ? ScopeUri.GetHashCode() : 0 ) * 397 ) ^ ( Section != null ? Section.GetHashCode() : 0 );
}
}

public static bool operator ==(ConfigurationItem left, ConfigurationItem right) => Equals(left, right);

public static bool operator !=(ConfigurationItem left, ConfigurationItem right) => !Equals(left, right);
}
}
23 changes: 20 additions & 3 deletions src/Protocol/Server/ILanguageServerConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;

namespace OmniSharp.Extensions.LanguageServer.Protocol.Server
{
public interface ILanguageServerConfiguration : IConfiguration
{
/// <summary>
/// Adds a set of configuration items to be tracked by the server
/// </summary>
/// <param name="configurationItems"></param>
/// <returns></returns>
ILanguageServerConfiguration AddConfigurationItems(IEnumerable<ConfigurationItem> configurationItems);

/// <summary>
/// Stops tracking a given set of configuration items
/// </summary>
/// <param name="configurationItems"></param>
/// <returns></returns>
ILanguageServerConfiguration RemoveConfigurationItems(IEnumerable<ConfigurationItem> configurationItems);

/// <summary>
/// Gets the current configuration values from the client
/// This configuration object is stateless such that it won't change with any other configuration changes
Expand All @@ -18,12 +34,13 @@ public interface ILanguageServerConfiguration : IConfiguration
/// Gets the current configuration for a given document uri
/// This re-uses all the sections from the <see cref="ConfigurationItem" />s that
/// the root configuration uses.
///
///
/// This will watch for changes of the scoped documents and update the configuration.
/// </summary>
/// <param name="scopeUri"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<IScopedConfiguration> GetScopedConfiguration(DocumentUri scopeUri);
Task<IScopedConfiguration> GetScopedConfiguration(DocumentUri scopeUri, CancellationToken cancellationToken);

/// <summary>
/// Attempt to get an existing scoped configuration so that it can be disposed
Expand Down
79 changes: 79 additions & 0 deletions src/Protocol/Server/LanguageServerConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Linq;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;

namespace OmniSharp.Extensions.LanguageServer.Protocol.Server
{
public static class LanguageServerConfigurationExtensions
{
/// <summary>
/// Adds a set of configuration items to be tracked by the server
/// </summary>
/// <param name="configuration"></param>
/// <param name="configurationItem"></param>
/// <param name="configurationItems"></param>
/// <returns></returns>
public static ILanguageServerConfiguration AddConfigurationItem(this ILanguageServerConfiguration configuration, ConfigurationItem configurationItem, params ConfigurationItem[] configurationItems)
{
return configuration.AddConfigurationItems(new[] { configurationItem }.Concat(configurationItems));
}

/// <summary>
/// Stops tracking a given set of configuration items
/// </summary>
/// <param name="configuration"></param>
/// <param name="configurationItem"></param>
/// <param name="configurationItems"></param>
/// <returns></returns>
public static ILanguageServerConfiguration RemoveConfigurationItem(this ILanguageServerConfiguration configuration, ConfigurationItem configurationItem, params ConfigurationItem[] configurationItems)
{
return configuration.RemoveConfigurationItems(new[] { configurationItem }.Concat(configurationItems));
}

/// <summary>
/// Adds a set of configuration items to be tracked by the server
/// </summary>
/// <param name="configuration"></param>
/// <param name="section"></param>
/// <param name="sections"></param>
/// <returns></returns>
public static ILanguageServerConfiguration AddSection(this ILanguageServerConfiguration configuration, string section, params string[] sections)
{
return configuration.AddConfigurationItems(new[] { section }.Concat(sections).Select(z => new ConfigurationItem() { Section = z}));
}

/// <summary>
/// Stops tracking a given set of configuration items
/// </summary>
/// <param name="configuration"></param>
/// <param name="section"></param>
/// <param name="sections"></param>
/// <returns></returns>
public static ILanguageServerConfiguration RemoveSection(this ILanguageServerConfiguration configuration, string section, params string[] sections)
{
return configuration.RemoveConfigurationItems(new[] { section }.Concat(sections).Select(z => new ConfigurationItem() { Section = z}));
}

/// <summary>
/// Adds a set of configuration items to be tracked by the server
/// </summary>
/// <param name="configuration"></param>
/// <param name="sections"></param>
/// <returns></returns>
public static ILanguageServerConfiguration AddSections(this ILanguageServerConfiguration configuration, IEnumerable<string> sections)
{
return configuration.AddConfigurationItems(sections.Select(z => new ConfigurationItem() { Section = z}));
}

/// <summary>
/// Stops tracking a given set of configuration items
/// </summary>
/// <param name="configuration"></param>
/// <param name="sections"></param>
/// <returns></returns>
public static ILanguageServerConfiguration RemoveSections(this ILanguageServerConfiguration configuration, IEnumerable<string> sections)
{
return configuration.RemoveConfigurationItems(sections.Select(z => new ConfigurationItem() { Section = z}));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.LanguageServer.Protocol;

namespace OmniSharp.Extensions.LanguageServer.Server.Configuration
{
internal class BaseWorkspaceConfigurationProvider : ConfigurationProvider
class ConfigurationConverter
{
protected void ParseClientConfiguration(JToken settings, string prefix = null)
{
public void ParseClientConfiguration(IDictionary<string, string> data, JToken settings, string prefix = null)
{
if (settings == null || settings.Type == JTokenType.Null || settings.Type == JTokenType.None) return;
// The null request (appears) to always come second
// this handler is set to use the SerialAttribute

Data.Clear();

// TODO: Figure out the best way to plugin to handle additional configurations (toml, yaml?)
try
{
Expand All @@ -35,7 +34,7 @@ protected void ParseClientConfiguration(JToken settings, string prefix = null)
)
))
{
Data[item.Key] = item.Value;
data[item.Key] = item.Value;
}
}
catch (JsonReaderException)
Expand All @@ -50,12 +49,12 @@ protected void ParseClientConfiguration(JToken settings, string prefix = null)
new KeyValuePair<string, string>(GetKey(item, prefix), item.ToString())
))
{
Data[item.Key] = item.Value;
data[item.Key] = item.Value;
}
}
}

private string GetKey(JToken token, string prefix)
private static string GetKey(JToken token, string prefix)
{
var items = new Stack<string>();

Expand All @@ -82,7 +81,7 @@ private string GetKey(JToken token, string prefix)
return string.Join(":", items);
}

private string GetKey(XElement token, string prefix)
private static string GetKey(XElement token, string prefix)
{
var items = new Stack<string>();

Expand Down
Loading

0 comments on commit 5571121

Please sign in to comment.