-
Notifications
You must be signed in to change notification settings - Fork 416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Miscellaneous Files #1252
Changes from 28 commits
a784769
f0cc59e
b26552b
48548a7
774cc9b
2d46149
27266dd
6f972d0
7bb4708
bf59f02
0db4d70
8e6baec
439e9ad
2bbfe5b
35e2630
999bf3f
81321cd
7e6ba33
eba6ae2
af435a6
895cf5b
c422035
57bfbc5
48b4c26
9a9cfa9
36af94b
11251b0
dd73d39
2b599a6
42c9049
d0574cb
6d8201a
7a419ed
def58ec
5788c37
9a8d447
c7158ba
c243202
3cf76e6
98e4de3
6228db3
069d6f0
2e5e7fc
850f3fd
f89946d
20bf194
4163f3f
9e2e0b9
6dfca92
c5db9c9
2a3666a
7a70a07
ce3a437
2355ded
b8d11e2
67003aa
4d3e853
f0d3255
cdecdad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Composition; | ||
using Microsoft.CodeAnalysis; | ||
using OmniSharp.Services; | ||
|
||
namespace OmniSharp.Mef | ||
{ | ||
[MetadataAttribute] | ||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] | ||
public class ExportIProjectSystemAttribute: ExportAttribute | ||
{ | ||
public string Name { get; } | ||
|
||
public ExportIProjectSystemAttribute(string name) : base(typeof(IProjectSystem)) | ||
{ | ||
Name = name; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace OmniSharp.Mef | ||
{ | ||
public class ProjectSystemMetadata | ||
{ | ||
public string Name { get; set; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.CodeAnalysis" Version="2.8.2" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this breaks layering. IIRC, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that was definitely the idea, that's also why |
||
<PackageReference Include="Microsoft.Extensions.Configuration" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" /> | ||
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// Adapted from ExtensionOrderer in Roslyn | ||
using System.Collections.Generic; | ||
|
||
namespace OmniSharp.Utilities | ||
{ | ||
static partial class ExtensionOrderer | ||
{ | ||
internal class Graph<T> | ||
{ | ||
//Dictionary to map between nodes and the names | ||
private Dictionary<string, Node<T>> Nodes { get; } | ||
private List<Node<T>> AllNodes { get; } | ||
private Graph(List<Node<T>> nodesList) | ||
{ | ||
Nodes = new Dictionary<string, Node<T>>(); | ||
AllNodes = nodesList; | ||
} | ||
internal static Graph<T> GetGraph(List<Node<T>> nodesList) | ||
{ | ||
var graph = new Graph<T>(nodesList); | ||
|
||
foreach (Node<T> node in graph.AllNodes) | ||
{ | ||
graph.Nodes[node.Name] = node; | ||
} | ||
|
||
foreach (Node<T> node in graph.AllNodes) | ||
{ | ||
foreach (var before in node.Before) | ||
{ | ||
if (graph.Nodes.ContainsKey(before)) | ||
{ | ||
var beforeNode = graph.Nodes[before]; | ||
beforeNode.NodesBeforeMeSet.Add(node); | ||
} | ||
} | ||
|
||
foreach (var after in node.After) | ||
{ | ||
if (graph.Nodes.ContainsKey(after)) | ||
{ | ||
var afterNode = graph.Nodes[after]; | ||
node.NodesBeforeMeSet.Add(afterNode); | ||
} | ||
} | ||
} | ||
|
||
return graph; | ||
} | ||
|
||
public bool HasCycles() | ||
{ | ||
foreach (var node in this.AllNodes) | ||
{ | ||
if (node.CheckForCycles()) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
public List<T> TopologicalSort() | ||
{ | ||
List<T> result = new List<T>(); | ||
var seenNodes = new HashSet<Node<T>>(); | ||
|
||
foreach (var node in AllNodes) | ||
{ | ||
Visit(node, result, seenNodes); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private void Visit(Node<T> node, List<T> result, HashSet<Node<T>> seenNodes) | ||
{ | ||
if (seenNodes.Add(node)) | ||
{ | ||
foreach (var before in node.NodesBeforeMeSet) | ||
{ | ||
Visit(before, result, seenNodes); | ||
} | ||
|
||
result.Add(node.Extension); | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Adapted from ExtensionOrderer in Roslyn | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace OmniSharp.Utilities | ||
{ | ||
static partial class ExtensionOrderer | ||
{ | ||
internal class Node<TNode> | ||
{ | ||
public string Name { get; set; } | ||
public List<string> Before { get; set; } | ||
public List<string> After { get; set; } | ||
public TNode Extension { get; set; } | ||
public HashSet<Node<TNode>> NodesBeforeMeSet { get; set; } | ||
|
||
public static Node<TNode> From<TNodeAttribute>(TNode extension, Func<TNodeAttribute, string> nameExtractor) where TNodeAttribute : Attribute | ||
{ | ||
string name = string.Empty; | ||
var attribute = extension.GetType().GetCustomAttribute<TNodeAttribute>(); | ||
if (attribute is TNodeAttribute && !string.IsNullOrEmpty(nameExtractor(attribute))) | ||
{ | ||
name = nameExtractor(attribute); | ||
} | ||
var orderAttributes = extension.GetType().GetCustomAttributes<ExtensionOrderAttribute>(true); | ||
return new Node<TNode>(extension, name, orderAttributes); | ||
} | ||
|
||
private Node(TNode extension, string name, IEnumerable<ExtensionOrderAttribute> orderAttributes) | ||
{ | ||
Extension = extension; | ||
Name = name; | ||
Before = new List<string>(); | ||
After = new List<string>(); | ||
NodesBeforeMeSet = new HashSet<Node<TNode>>(); | ||
foreach (var attribute in orderAttributes) | ||
{ | ||
AddAttribute(attribute); | ||
} | ||
} | ||
|
||
private void AddAttribute(ExtensionOrderAttribute attribute) | ||
{ | ||
if (attribute.Before != null) | ||
Before.Add(attribute.Before); | ||
if (attribute.After != null) | ||
After.Add(attribute.After); | ||
} | ||
|
||
internal bool CheckForCycles() | ||
{ | ||
return CheckForCycles(new HashSet<Node<TNode>>()); | ||
} | ||
|
||
private bool CheckForCycles(HashSet<Node<TNode>> seenNodes) | ||
{ | ||
if (!seenNodes.Add(this)) | ||
{ | ||
//Cycle detected | ||
return true; | ||
} | ||
|
||
foreach (var before in this.NodesBeforeMeSet) | ||
{ | ||
if (before.CheckForCycles(seenNodes)) | ||
return true; | ||
} | ||
|
||
seenNodes.Remove(this); | ||
return false; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace OmniSharp.Utilities | ||
{ | ||
static partial class ExtensionOrderer | ||
{ | ||
/* Returns a sorted order of the nodes if such a sorting exists, else returns the unsorted list */ | ||
public static IEnumerable<TExtension> GetOrderedOrUnorderedList<TExtension, TAttribute>(IEnumerable<TExtension> unsortedList, Func<TAttribute, string> nameExtractor) where TAttribute: Attribute | ||
{ | ||
var nodesList = unsortedList.Select(elem => Node<TExtension>.From(elem, nameExtractor)); | ||
var graph = Graph<TExtension>.GetGraph(nodesList.ToList()); | ||
return graph.HasCycles() ? unsortedList : graph.TopologicalSort(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1,13 +1,19 @@ | ||||
using System; | ||||
using System.Collections.Generic; | ||||
using System.ComponentModel; | ||||
using System.Composition; | ||||
using System.Composition.Hosting; | ||||
using System.Linq; | ||||
using Microsoft.Extensions.Configuration; | ||||
using Microsoft.Extensions.DependencyInjection; | ||||
using Microsoft.Extensions.Logging; | ||||
using Microsoft.Extensions.Options; | ||||
using OmniSharp.Mef; | ||||
using OmniSharp.Options; | ||||
using OmniSharp.Roslyn; | ||||
using OmniSharp.Roslyn.Options; | ||||
using OmniSharp.Services; | ||||
using OmniSharp.Utilities; | ||||
|
||||
namespace OmniSharp | ||||
{ | ||||
|
@@ -24,9 +30,11 @@ public static void Initialize( | |||
|
||||
var projectEventForwarder = compositionHost.GetExport<ProjectEventForwarder>(); | ||||
projectEventForwarder.Initialize(); | ||||
var projectSystems = compositionHost.GetExports<Lazy<IProjectSystem, ProjectSystemMetadata>>(); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should hide that logic in some generic extension method? this way it could be reused in the future against other potentially ordered look ups like i.e.
|
||||
var ps = projectSystems.Select(n => n.Value); | ||||
var orderedProjectSystems = ExtensionOrderer.GetOrderedOrUnorderedList<IProjectSystem, ExportIProjectSystemAttribute>(ps, eps => eps.Name); | ||||
|
||||
// Initialize all the project systems | ||||
foreach (var projectSystem in compositionHost.GetExports<IProjectSystem>()) | ||||
foreach (var projectSystem in orderedProjectSystems) | ||||
{ | ||||
try | ||||
{ | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
using OmniSharp.Eventing; | ||
using OmniSharp.FileSystem; | ||
using OmniSharp.FileWatching; | ||
using OmniSharp.Mef; | ||
using OmniSharp.Models.WorkspaceInformation; | ||
using OmniSharp.MSBuild.Discovery; | ||
using OmniSharp.MSBuild.Models; | ||
|
@@ -20,7 +21,7 @@ | |
|
||
namespace OmniSharp.MSBuild | ||
{ | ||
[Export(typeof(IProjectSystem)), Shared] | ||
[ExportIProjectSystem(nameof(ProjectSystem)), Shared] | ||
public class ProjectSystem : IProjectSystem | ||
{ | ||
private readonly IOmniSharpEnvironment _environment; | ||
|
@@ -209,5 +210,10 @@ async Task<object> IProjectSystem.GetProjectModelAsync(string filePath) | |
|
||
return new MSBuildProjectInfo(projectFileInfo); | ||
} | ||
|
||
public async Task HasCompletedUpdateRequest() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this needs a better name. "HasCompletedUpdateRequest" implies that this would return a boolean and doesn't really indicate that it's asynchronous. How about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, if you decide to introduce a different interface for this behavior, maybe a |
||
{ | ||
await _manager.WaitForQueueEmptyAsync(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming: remove the "I" and go with "ExportProjectSystemAttribute".