Skip to content

Commit

Permalink
Merge pull request #977 from mholo65/lsp-completionhandler
Browse files Browse the repository at this point in the history
Adds CompletionHandler.
  • Loading branch information
david-driscoll authored Oct 10, 2017
2 parents 93b3b6b + d08895c commit 78ef0e8
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
144 changes: 144 additions & 0 deletions src/OmniSharp.LanguageServerProtocol/Handlers/CompletionHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Capabilities.Client;
using OmniSharp.Extensions.LanguageServer.Models;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Mef;
using OmniSharp.Models.AutoComplete;
using OmniSharp.Models.TypeLookup;

namespace OmniSharp.LanguageServerProtocol.Handlers
{
[Shared, Export(typeof(CompletionHandler))]
class CompletionHandler : ICompletionHandler
{
public static IEnumerable<IJsonRpcHandler> Enumerate(RequestHandlers handlers)
{
foreach (var (selector, handler) in handlers
.OfType<Mef.IRequestHandler<AutoCompleteRequest, IEnumerable<AutoCompleteResponse>>>())
if (handler != null)
yield return new CompletionHandler(handler, selector);
}

private CompletionCapability _capability;
private readonly Mef.IRequestHandler<AutoCompleteRequest, IEnumerable<AutoCompleteResponse>> _autoCompleteHandler;
private readonly DocumentSelector _documentSelector;

private static readonly IDictionary<string, CompletionItemKind> _kind = new Dictionary<string, CompletionItemKind>{
// types
{ "Class", CompletionItemKind.Class },
{ "Delegate", CompletionItemKind.Class }, // need a better option for this.
{ "Enum", CompletionItemKind.Enum },
{ "Interface", CompletionItemKind.Interface },
{ "Struct", CompletionItemKind.Class }, // TODO: Is struct missing from enum?

// variables
{ "Local", CompletionItemKind.Variable },
{ "Parameter", CompletionItemKind.Variable },
{ "RangeVariable", CompletionItemKind.Variable },

// members
{ "Const", CompletionItemKind.Value }, // TODO: Is const missing from enum?
{ "EnumMember", CompletionItemKind.Enum },
{ "Event", CompletionItemKind.Function }, // TODO: Is event missing from enum?
{ "Field", CompletionItemKind.Field },
{ "Method", CompletionItemKind.Method },
{ "Property", CompletionItemKind.Property },

// other stuff
{ "Label", CompletionItemKind.Unit }, // need a better option for this.
{ "Keyword", CompletionItemKind.Keyword },
{ "Namespace", CompletionItemKind.Module }
};

private static CompletionItemKind GetCompletionItemKind(string key)
{
if (string.IsNullOrEmpty(key))
{
return CompletionItemKind.Property;
}
if(_kind.TryGetValue(key, out var completionItemKind))
{
return completionItemKind;
}
return CompletionItemKind.Property;
}

[ImportingConstructor]
public CompletionHandler(Mef.IRequestHandler<AutoCompleteRequest, IEnumerable<AutoCompleteResponse>> autoCompleteHandler, DocumentSelector documentSelector)
{
_autoCompleteHandler = autoCompleteHandler;
_documentSelector = documentSelector;
}

public async Task<CompletionList> Handle(TextDocumentPositionParams request, CancellationToken token)
{
var omnisharpRequest = new AutoCompleteRequest()
{
FileName = Helpers.FromUri(request.TextDocument.Uri),
Column = Convert.ToInt32(request.Position.Character),
Line = Convert.ToInt32(request.Position.Line),
WantKind = true,
WantDocumentationForEveryCompletionResult = true,
WantReturnType = true
};

var omnisharpResponse = await _autoCompleteHandler.Handle(omnisharpRequest);

var completions = new Dictionary<string, List<CompletionItem>>();
foreach (var response in omnisharpResponse)
{
var completionItem = new CompletionItem {
Label = response.CompletionText,
Detail = !string.IsNullOrEmpty(response.ReturnType) ?
response.DisplayText :
$"{response.ReturnType} {response.DisplayText}",
Documentation = response.Description,
Kind = GetCompletionItemKind(response.Kind),
InsertText = response.CompletionText,
};

if(!completions.ContainsKey(completionItem.Label))
{
completions[completionItem.Label] = new List<CompletionItem>();
}
completions[completionItem.Label].Add(completionItem);
}

var result = new List<CompletionItem>();
foreach (var key in completions.Keys)
{
var suggestion = completions[key][0];
var overloadCount = completions[key].Count - 1;

if (overloadCount > 0)
{
// indicate that there is more
suggestion.Detail = $"{suggestion.Detail} (+ {overloadCount} overload(s))";
}

result.Add(suggestion);
}

return new CompletionList(result);
}

public CompletionRegistrationOptions GetRegistrationOptions()
{
return new CompletionRegistrationOptions()
{
DocumentSelector = _documentSelector
};
}

public void SetCapability(CompletionCapability capability)
{
_capability = capability;
}
}
}
1 change: 1 addition & 0 deletions src/OmniSharp.LanguageServerProtocol/LanguageServerHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ private Task Initialize(InitializeParams initializeParams)
_server.AddHandlers(TextDocumentSyncHandler.Enumerate(_handlers, workspace));
_server.AddHandlers(DefinitionHandler.Enumerate(_handlers));
_server.AddHandlers(HoverHandler.Enumerate(_handlers));
_server.AddHandlers(CompletionHandler.Enumerate(_handlers));

_server.LogMessage(new LogMessageParams()
{
Expand Down

0 comments on commit 78ef0e8

Please sign in to comment.