Skip to content
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

Fix #204. Go to step definition from a feature file with CTRL+click #290

Merged
merged 1 commit into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cucumber.eclipse.editor.editors;


import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.junit.Before;
import org.junit.Test;

import cucumber.eclipse.steps.integration.Step;

public class StepHyperlinkTest {

private StepHyperlink stepHyperlink;
IRegion region;

@Before
public void setUp() {
region = new Region(0, 10);
Step step = new Step();
step.setText("Given I have a cat");
stepHyperlink = new StepHyperlink(region, step);
}

@Test
public void shouldHaveATypeLabel() {
assertThat(stepHyperlink.getTypeLabel(), equalTo("Gherkin step"));
}

@Test
public void shouldHaveAnAlternateText() {
assertThat(stepHyperlink.getHyperlinkText(), equalTo("Open step definition"));
}

@Test
public void shouldReturnTheExpectedRegion() {
assertThat(stepHyperlink.getHyperlinkRegion(), equalTo(region));
}

// should have UI automate test to validate the step hyperlink open.
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cucumber.eclipse.editor.editors;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.util.Arrays;
Expand Down Expand Up @@ -180,4 +182,18 @@ private Step createStep(String text) {
return s;
}

@Test
public void shouldReturnExpressionWithoutStartingKeyword() {
String statement = stepMatcher.getTextStatement("en", "Given I have a cat");
assertThat(statement, equalTo("I have a cat"));

statement = stepMatcher.getTextStatement("en", "When I carress him");
assertThat(statement, equalTo("I carress him"));

statement = stepMatcher.getTextStatement("en", "Then he purrs");
assertThat(statement, equalTo("he purrs"));

statement = stepMatcher.getTextStatement("en", "And I am happy");
assertThat(statement, equalTo("I am happy"));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package cucumber.eclipse.editor.editors;

import org.eclipse.jface.preference.IPreferenceStore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

import org.eclipse.core.resources.IMarker;
Expand All @@ -10,6 +13,7 @@
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.presentation.PresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
Expand Down Expand Up @@ -161,4 +165,13 @@ public IReconciler getReconciler(ISourceViewer sourceViewer) {
public int getTabWidth(ISourceViewer sourceViewer) {
return 2;
}

@Override
public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
IHyperlinkDetector[] hyperlinkDetectors = super.getHyperlinkDetectors(sourceViewer);
StepHyperlinkDetector stepHyperlinkDetector = new StepHyperlinkDetector(this.editor);
IHyperlinkDetector[] gherkinHyperlinkDetectors = Arrays.copyOf(hyperlinkDetectors, hyperlinkDetectors.length + 1);
gherkinHyperlinkDetectors[hyperlinkDetectors.length] = stepHyperlinkDetector;
return gherkinHyperlinkDetectors;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cucumber.eclipse.editor.editors;

import java.util.HashMap;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;

import cucumber.eclipse.steps.integration.Step;

public class StepHyperlink implements IHyperlink {

private IRegion region;
private Step step;

public StepHyperlink(IRegion region, Step step) {
this.region = region;
this.step = step;
}

@Override
public IRegion getHyperlinkRegion() {
return this.region;
}

@Override
public String getHyperlinkText() {
return "Open step definition";
}

@Override
public String getTypeLabel() {
return "Gherkin step";
}

@Override
public void open() {
IResource file = this.step.getSource();
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put(IMarker.LINE_NUMBER, step.getLineNumber());
IMarker marker;
try {
marker = file.createMarker(IMarker.TEXT);
marker.setAttributes(map);
IDE.openEditor(page, marker);
marker.delete();
} catch (CoreException e) {
e.printStackTrace();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package cucumber.eclipse.editor.editors;

import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.texteditor.ITextEditor;

import cucumber.eclipse.editor.markers.MarkerIds;
import cucumber.eclipse.editor.markers.MarkerManager;
import cucumber.eclipse.editor.steps.IStepProvider;
import cucumber.eclipse.steps.integration.Step;
import gherkin.lexer.LexingError;
import gherkin.parser.Parser;

public class StepHyperlinkDetector implements IHyperlinkDetector {

private Editor editor;

public StepHyperlinkDetector(Editor editor) {
this.editor = editor;
}

@Override
public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) {
if (region == null || textViewer == null) {
return null;
}

IDocument document = textViewer.getDocument();
if (document == null) {
return null;
}

int offset = region.getOffset();
int lineStartOffset = 0;

IRegion lineInfo = null;
String currentLine = null;
try {
lineInfo = document.getLineInformationOfOffset(offset);
lineStartOffset = lineInfo.getOffset();
currentLine = document.get(lineStartOffset, lineInfo.getLength());
} catch (BadLocationException e) {
return null;
}

IStepProvider stepProvider = this.editor.getStepProvider();
Set<Step> steps = stepProvider.getStepsInEncompassingProject();

StepMatcher stepMatcher = new StepMatcher();
String language = DocumentUtil.getDocumentLanguage(document);

// hack to support scenario outline examples
int currentLineNumber = textViewer.getTextWidget().getLineAtOffset(offset) + 1;
List<String> resolvedStepsExpressions = resolveLineStep(editor, currentLineNumber);
Step step = null;
for (String variant : resolvedStepsExpressions) {
step = stepMatcher.matchSteps(language, steps, variant);
if(step != null) {
break;
}
}

if (step == null) {
return null;
}

// define the hyperlink region
String textStatement = stepMatcher.getTextStatement(language, currentLine);
int statementStartOffset = lineStartOffset + currentLine.indexOf(textStatement);

IRegion stepRegion = new Region(statementStartOffset, textStatement.length());

return new IHyperlink[] { new StepHyperlink(stepRegion, step) };
}

// go through all examples of current scenario outline and generate step strings with replaced variables values
protected static List<String> resolveLineStep(IEditorPart editorPart, int currentLineNumber) {
ITextEditor editor = (ITextEditor) editorPart;

IDocument document = editor.getDocumentProvider().getDocument(editorPart.getEditorInput());

IFileEditorInput fileEditorInput = (IFileEditorInput) editorPart.getEditorInput();
IFile featureFile = fileEditorInput.getFile();
MarkerManager markerManager = new MarkerManager();
PopupMenuFindStepFormatter findStepFormatter = new PopupMenuFindStepFormatter(currentLineNumber);
Parser p = new Parser(findStepFormatter, false);
try {
p.parse(document.get(), "", 0);
} catch (LexingError l) {
markerManager.add(MarkerIds.LEXING_ERROR, featureFile, IMarker.SEVERITY_ERROR, l.getLocalizedMessage(), 1, 0, 0);
}
return findStepFormatter.getResolvedStepNames();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,39 @@ class StepMatcher {
private Pattern groupPatternNonParameterMatch = Pattern.compile("(\\(\\?:.+?\\))");
private Pattern groupPattern = Pattern.compile("(\\(.+?\\))");

public String getTextStatement(String language, String expression) {
Matcher matcher = getBasicStatementMatcher(language, expression);
if(matcher == null) {
return null;
}
if(matcher.matches()) {
return matcher.group(1);
}
return null;
}

public Step matchSteps(String languageCode, Set<Step> steps, String currentLine) {

//System.out.println("StepMatcher matchSteps() steps = " + steps);
Pattern cukePattern = getLanguageKeyWordMatcher(languageCode);
/**
* Get a matcher to ensure text starts with a basic step keyword : Given, When,
* Then, etc
*
* @param language the document language
* @param text the text to match
* @return a matcher
*/
private Matcher getBasicStatementMatcher(String language, String text) {
Pattern cukePattern = getLanguageKeyWordMatcher(language);

if (cukePattern == null)
return null;

Matcher matcher = cukePattern.matcher(currentLine);
return cukePattern.matcher(text.trim());
}

public Step matchSteps(String languageCode, Set<Step> steps, String currentLine) {

//System.out.println("StepMatcher matchSteps() steps = " + steps);

Matcher matcher = getBasicStatementMatcher(languageCode, currentLine);

if (matcher.matches()) {

Expand Down