Skip to content

Commit

Permalink
full step autocomplete, first version
Browse files Browse the repository at this point in the history
  • Loading branch information
gasparnagy committed Mar 11, 2011
1 parent 7ec4373 commit 95034c9
Show file tree
Hide file tree
Showing 31 changed files with 1,086 additions and 229 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ protected void FilterAutoComplete()
if (!IsAutoCompleteSessionActive)
return;

currentAutoCompleteSession.SelectedCompletionSet.Filter();
currentAutoCompleteSession.SelectedCompletionSet.SelectBestMatch();
currentAutoCompleteSession.SelectedCompletionSet.Recalculate();
}
Expand Down
105 changes: 31 additions & 74 deletions IdeIntegration/Vs2010Integration/AutoComplete/CompletionSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using TechTalk.SpecFlow.Parser;
using TechTalk.SpecFlow.Parser.Gherkin;
using TechTalk.SpecFlow.Utils;
using TechTalk.SpecFlow.Vs2010Integration.Bindings;
using TechTalk.SpecFlow.Vs2010Integration.LanguageService;
using ScenarioBlock = TechTalk.SpecFlow.Parser.Gherkin.ScenarioBlock;

Expand All @@ -34,6 +35,27 @@ public ICompletionSource TryCreateCompletionSource(ITextBuffer textBuffer)
}
}

internal class CustomCompletionSet : CompletionSet
{
public CustomCompletionSet()
{
}

public CustomCompletionSet(string moniker, string displayName, ITrackingSpan applicableTo, IEnumerable<Completion> completions, IEnumerable<Completion> completionBuilders) : base(moniker, displayName, applicableTo, completions, completionBuilders)
{
}

public override void Filter()
{
Filter(CompletionMatchType.MatchInsertionText, false);
}

public override void SelectBestMatch()
{
SelectBestMatch(CompletionMatchType.MatchInsertionText, false);
}
}

internal class GherkinStepCompletionSource : ICompletionSource
{
private bool disposed = false;
Expand Down Expand Up @@ -62,12 +84,12 @@ public void AugmentCompletionSession(ICompletionSession session, IList<Completio
if (scenarioBlock == null)
return;

IEnumerable<Completion> completions = GetCompletionsForBlock(scenarioBlock.Value);
IEnumerable<Completion> completions = GetCompletionsForBindingType((BindingType)scenarioBlock.Value);
ITrackingSpan applicableTo = GetApplicableToSpan(snapshot, triggerPoint.Value);

string displayName = string.Format("All {0} Steps", scenarioBlock);
completionSets.Add(
new CompletionSet(
new CustomCompletionSet(
displayName,
displayName,
applicableTo,
Expand Down Expand Up @@ -126,81 +148,16 @@ private static string GetFirstWordOfLine(ITextSnapshot snapshot, int lineNumer)
return theLine.GetText().TrimStart().Split(' ')[0];
}

private IEnumerable<Completion> GetCompletionsForBlock(ScenarioBlock scenarioBlock)
private IEnumerable<Completion> GetCompletionsForBindingType(BindingType bindingType)
{
var project = specFlowServices.GetProject(textBuffer);

List<Completion> result = new List<Completion>();
GetCompletionsFromProject(project, scenarioBlock, result);

var specFlowProject = languageService.ProjectScope.SpecFlowProjectConfiguration;
if (specFlowProject != null)
{
foreach (var assemblyName in specFlowProject.RuntimeConfiguration.AdditionalStepAssemblies)
{
string simpleName = assemblyName.Split(new[] {',' }, 2)[0];

var stepProject = VsxHelper.FindProjectByAssemblyName(project.DTE, simpleName);
if (stepProject != null)
GetCompletionsFromProject(stepProject, scenarioBlock, result);
}
}

result.Sort((c1, c2) => string.Compare(c1.DisplayText, c2.DisplayText));
var suggestionProvider = languageService.ProjectScope.StepSuggestionProvider;
if (suggestionProvider == null)
return Enumerable.Empty<Completion>();

return result;
}
if (!suggestionProvider.Populated)
return new Completion[] {new Completion("step suggestion list is being populated...")};

private void GetCompletionsFromProject(Project project, ScenarioBlock scenarioBlock, List<Completion> result)
{
foreach (ProjectItem projectItem in VsxHelper.GetAllProjectItem(project).Where(pi => pi.FileCodeModel != null))
{
FileCodeModel codeModel = projectItem.FileCodeModel;
GetCompletitionsFromCodeElements(codeModel.CodeElements, scenarioBlock, result);
}
}

private void GetCompletitionsFromCodeElements(CodeElements codeElements, ScenarioBlock scenarioBlock, List<Completion> result)
{
foreach (CodeElement codeElement in codeElements)
{
if (codeElement.Kind == vsCMElement.vsCMElementFunction)
{
CodeFunction codeFunction = (CodeFunction)codeElement;
result.AddRange(
codeFunction.Attributes.Cast<CodeAttribute>()
.Where(attr => attr.FullName.Equals(string.Format("TechTalk.SpecFlow.{0}Attribute", scenarioBlock)))
.Select(attr => CreateCompletion(GetRecommendedStepText(attr.Value, codeFunction))));
}
else
{
GetCompletitionsFromCodeElements(codeElement.Children, scenarioBlock, result);
}
}
}

private string UnmaskAttributeValue(string attrValue)
{
if (attrValue.StartsWith("@"))
{
return attrValue.Substring(2, attrValue.Length - 3).Replace("\"\"", "\"");
}

return attrValue.Substring(1, attrValue.Length - 2); //TODO: handle \ maskings
}

private string GetRecommendedStepText(string regexAttrValue, CodeFunction codeFunction)
{
string unmaskAttributeValue = UnmaskAttributeValue(regexAttrValue);

var parameters = codeFunction.Parameters.Cast<CodeParameter>().Select(p => p.Name).ToArray();

return RegexSampler.GetRegexSample(unmaskAttributeValue, parameters);
}

private Completion CreateCompletion(string stepText)
{
return new Completion(stepText);
return suggestionProvider.GetNativeSuggestionItems(bindingType);
}

public void Dispose()
Expand Down
69 changes: 69 additions & 0 deletions IdeIntegration/Vs2010Integration/Bindings/BindingType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TechTalk.SpecFlow.Parser.Gherkin;

namespace TechTalk.SpecFlow.Vs2010Integration.Bindings
{
public enum BindingType
{
Given = ScenarioBlock.Given,
When = ScenarioBlock.When,
Then = ScenarioBlock.Then
}

public interface IBindingType
{
string Name { get; }
string FullName { get; }
}

public interface IBindingParameter
{
IBindingType Type { get; }
string ParameterName { get; }
}

public interface IBindingMethod
{
IBindingType Type { get; }
IEnumerable<IBindingParameter> Parameters { get; }
string ShortDisplayText { get; }
}

public class StepBinding
{
public IBindingMethod Method { get; private set; }
public BindingType BindingType { get; private set; }
public Regex Regex { get; private set; }

public BindingScope BindingScope { get; private set; }
public bool IsScoped { get { return BindingScope != null; } }

public StepBinding(IBindingMethod method, BindingType bindingType, Regex regex, BindingScope bindingScope)
{
Method = method;
BindingType = bindingType;
Regex = regex;
BindingScope = bindingScope;
}
}

public class BindingScope
{
public string Tag { get; private set; }
public string FeatureTitle { get; private set; }
public string ScenarioTitle { get; private set; }

public BindingScope(string tag, string featureTitle, string scenarioTitle)
{
Tag = tag;
FeatureTitle = featureTitle;
ScenarioTitle = scenarioTitle;
}
}


}
1 change: 1 addition & 0 deletions IdeIntegration/Vs2010Integration/DteProjectReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using EnvDTE;
using TechTalk.SpecFlow.Generator.Configuration;
using TechTalk.SpecFlow.Vs2010Integration.LanguageService;
using TechTalk.SpecFlow.Vs2010Integration.Utils;

namespace TechTalk.SpecFlow.Vs2010Integration
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Text;
using TechTalk.SpecFlow.Vs2010Integration.Tracing;
using TechTalk.SpecFlow.Vs2010Integration.Utils;

namespace TechTalk.SpecFlow.Vs2010Integration.LanguageService
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ private void ColorizeKeywordLine(string keyword, GherkinBufferSpan headerSpan, I
var textSpan = new GherkinBufferSpan(
headerSpan.StartPosition.ShiftByCharacters(keyword.Length),
headerSpan.EndPosition);
ColorizeSpan(textSpan, classificationType);
if (textSpan.StartPosition < textSpan.EndPosition)
ColorizeSpan(textSpan, classificationType);
}

private void AddOutline(int startLine, int endLine, string collapseText, string hooverText = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public GherkinScopeAnalyzer GherkinScopeAnalyzer
get { return null; }
}

public VsStepSuggestionProvider StepSuggestionProvider
{
get { return null; }
}

public NoProjectScope(GherkinFileEditorClassifications classifications, IVisualStudioTracer visualStudioTracer)
{
GherkinTextBufferParser = new GherkinTextBufferParser(this, visualStudioTracer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Threading;
using EnvDTE;
using TechTalk.SpecFlow.Generator;
Expand All @@ -14,6 +15,7 @@

namespace TechTalk.SpecFlow.Vs2010Integration.LanguageService
{

public class FeatureFileInfo
{
public string ProjectRelativePath { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public interface IProjectScope : IDisposable
GherkinFileEditorClassifications Classifications { get; }
GherkinProcessingScheduler GherkinProcessingScheduler { get; }
SpecFlowProjectConfiguration SpecFlowProjectConfiguration { get; }
VsStepSuggestionProvider StepSuggestionProvider { get; }

event EventHandler SpecFlowProjectConfigurationChanged;
event EventHandler GherkinDialectServicesChanged;
Expand Down
Loading

0 comments on commit 95034c9

Please sign in to comment.