diff --git a/org.agileware.natural.common.feature/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
similarity index 100%
rename from org.agileware.natural.common.feature/.settings/org.eclipse.core.resources.prefs
rename to .settings/org.eclipse.core.resources.prefs
diff --git a/LaunchNatural.launch b/LaunchNatural.launch
index 00e60790..cee476a0 100644
--- a/LaunchNatural.launch
+++ b/LaunchNatural.launch
@@ -1,35 +1,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.common.feature/.project b/org.agileware.natural.common.feature/.project
deleted file mode 100644
index 4880be54..00000000
--- a/org.agileware.natural.common.feature/.project
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
- org.agileware.natural.common.feature
-
-
-
-
-
- org.eclipse.pde.FeatureBuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.pde.FeatureNature
- org.eclipse.m2e.core.maven2Nature
-
-
diff --git a/org.agileware.natural.common.feature/build.properties b/org.agileware.natural.common.feature/build.properties
deleted file mode 100644
index 64f93a9f..00000000
--- a/org.agileware.natural.common.feature/build.properties
+++ /dev/null
@@ -1 +0,0 @@
-bin.includes = feature.xml
diff --git a/org.agileware.natural.common.feature/feature.xml b/org.agileware.natural.common.feature/feature.xml
deleted file mode 100644
index b4243dcb..00000000
--- a/org.agileware.natural.common.feature/feature.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
- [Enter Feature Description here.]
-
-
-
- [Enter Copyright Description here.]
-
-
-
- [Enter License Description here.]
-
-
-
-
-
diff --git a/org.agileware.natural.common.feature/pom.xml b/org.agileware.natural.common.feature/pom.xml
deleted file mode 100644
index d38b3660..00000000
--- a/org.agileware.natural.common.feature/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
- 4.0.0
-
- org.agileware
- natural
- 1.0.0-SNAPSHOT
-
- org.agileware.natural.common.feature
- eclipse-feature
- 1.3.0-SNAPSHOT
-
-
-
-
diff --git a/org.agileware.natural.common/META-INF/MANIFEST.MF b/org.agileware.natural.common/META-INF/MANIFEST.MF
deleted file mode 100644
index 59f35422..00000000
--- a/org.agileware.natural.common/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,25 +0,0 @@
-Manifest-Version: 1.0
-Bundle-ManifestVersion: 2
-Bundle-Name: Natural Core SDK
-Bundle-SymbolicName: org.agileware.natural.common
-Bundle-Version: 1.3.0.qualifier
-Bundle-Activator: org.agileware.natural.common.Activator
-Require-Bundle: org.eclipse.core.runtime;bundle-version="3.17.100";visibility:=reexport,
- org.eclipse.jface.text;bundle-version="3.16.200";visibility:=reexport,
- org.eclipse.ui;bundle-version="3.116.0",
- org.eclipse.ui.ide;bundle-version="3.17.0",
- org.eclipse.jdt.ui;bundle-version="3.21.0",
- org.eclipse.jdt.core;bundle-version="3.21.0",
- org.eclipse.core.resources;bundle-version="3.13.700",
- com.google.guava;bundle-version="27.1.0",
- com.google.inject;bundle-version="3.0.0",
- org.eclipse.emf.ecore
-Bundle-ActivationPolicy: lazy
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Bundle-Vendor: Roberto Lo Giacco
-Export-Package: org.agileware.natural.common;
- uses:="org.osgi.framework,
- org.eclipse.jdt.core,
- org.eclipse.jface.text,
- org.eclipse.jface.text.hyperlink,
- org.eclipse.jdt.core.search"
diff --git a/org.agileware.natural.common/category.xml b/org.agileware.natural.common/category.xml
deleted file mode 100644
index 446905e0..00000000
--- a/org.agileware.natural.common/category.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- Rich editors for behavioral testing definition files
-
-
-
diff --git a/org.agileware.natural.common/src/org/agileware/natural/common/Activator.java b/org.agileware.natural.common/src/org/agileware/natural/common/Activator.java
deleted file mode 100644
index 7d9da098..00000000
--- a/org.agileware.natural.common/src/org/agileware/natural/common/Activator.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.agileware.natural.common;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-public class Activator implements BundleActivator {
-
- private static BundleContext context;
-
- static BundleContext getContext() {
- return context;
- }
-
- /**
- * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
- */
- public void start(BundleContext bundleContext) throws Exception {
- Activator.context = bundleContext;
- }
-
- /**
- * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
- */
- public void stop(BundleContext bundleContext) throws Exception {
- Activator.context = null;
- }
-
-}
diff --git a/org.agileware.natural.common/src/org/agileware/natural/common/JavaAnnotationMatcher.java b/org.agileware.natural.common/src/org/agileware/natural/common/JavaAnnotationMatcher.java
deleted file mode 100644
index 2c1a23bc..00000000
--- a/org.agileware.natural.common/src/org/agileware/natural/common/JavaAnnotationMatcher.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package org.agileware.natural.common;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeSet;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.IAnnotation;
-import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.search.IJavaSearchConstants;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.core.search.SearchMatch;
-import org.eclipse.jdt.core.search.SearchParticipant;
-import org.eclipse.jdt.core.search.SearchPattern;
-import org.eclipse.jdt.core.search.SearchRequestor;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class JavaAnnotationMatcher {
-
- @Inject
- private AbstractAnnotationDescriptor descriptor;
-
- private Map> cache = new HashMap>();
-
- protected IJavaSearchScope getScope(String filter) {
- if (filter == null)
- return SearchEngine.createWorkspaceScope();
-
- String[] names = filter.split(",");
- final List packages = new ArrayList();
-
- SearchPattern pattern = null;
- for (String name : names) {
- SearchPattern current = SearchPattern.createPattern(name.trim(),
- IJavaSearchConstants.PACKAGE,
- IJavaSearchConstants.ALL_OCCURRENCES,
- SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
- if (pattern == null) {
- pattern = current;
- } else {
- pattern = SearchPattern.createOrPattern(pattern, current);
- }
- }
- try {
- new SearchEngine().search(pattern,
- new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() }, SearchEngine.createWorkspaceScope(), new SearchRequestor() {
- public void acceptSearchMatch(SearchMatch match) throws CoreException {
- packages.add((IJavaElement) match.getElement());
- }
- }, null);
- } catch (CoreException e) {
- e.printStackTrace();
- }
- return SearchEngine.createJavaSearchScope(packages.toArray(new IJavaElement[0]));
- }
-
- public void findMatches(final String description, final Command command) {
- long time = System.currentTimeMillis();
- if (!cache.isEmpty()) {
- for (List entries : cache.values()) {
- for (Entry entry : entries) {
- if (description.matches(entry.annotationValue)) {
- command.match(entry.annotationValue, entry.method);
- }
- }
- }
- return;
- }
-
- // combine search patterns
- SearchPattern pattern = null;
- for (final String annotationName : descriptor.getNames()) {
- SearchPattern current = SearchPattern.createPattern(annotationName,
- IJavaSearchConstants.ANNOTATION_TYPE,
- IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE,
- SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
- if (pattern == null) {
- pattern = current;
- } else {
- pattern = SearchPattern.createOrPattern(pattern, current);
- }
- }
- // execute search
- try {
- new SearchEngine().search(pattern,
- new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() },
- this.getScope(null),
- new SearchRequestor() {
- public void acceptSearchMatch(SearchMatch match) throws CoreException {
- if (match.getElement() instanceof IMethod) {
- IMethod method = (IMethod) match.getElement();
- IAnnotation[] annotations = method.getAnnotations();
- for (IAnnotation type : annotations) {
- // check annotation package
- if (AbstractAnnotationDescriptor.checkPackage(type, descriptor.getPackage())) {
- // verify pattern
- String annotationValue = (String) type.getMemberValuePairs()[0].getValue();
- List entries = cache.get(method.getCompilationUnit());
- if (entries == null) {
- entries = new ArrayList();
- cache.put(method.getCompilationUnit(), entries);
- }
- entries.add(new Entry(annotationValue, method));
- if (description.matches(annotationValue)) {
- command.match(annotationValue, method);
- }
- }
- }
- }
- }
- },
- null);
- } catch (CoreException e) {
- e.printStackTrace();
- }
- System.out.println("stepdef match lookup completed in " + (System.currentTimeMillis() - time) + "ms");
- }
-
- public Collection findProposals() {
- if (cache.isEmpty()) {
- findMatches("", new Command() {
- @Override
- public void match(String annotationValue, IMethod method) { }
- });
- }
-
- Collection proposals = new TreeSet();
- for (List entries : cache.values()) {
- for (Entry entry : entries) {
- proposals.add(entry.getAnnotationValue());
- }
- }
- return proposals;
- }
-
- public void evict(ICompilationUnit element) {
- cache.clear();
- System.out.println(">>> cache cleared");
- }
-
- public static interface Command {
- void match(String annotationValue, IMethod method);
- }
-
- public static class Entry {
- private String annotationValue;
- private IMethod method;
-
- private Entry(String annotationValue, IMethod method) {
- this.annotationValue = annotationValue;
- this.method = method;
- }
-
- public String getAnnotationValue() {
- return annotationValue;
- }
- }
-}
diff --git a/org.agileware.natural.cucumber.feature/feature.xml b/org.agileware.natural.cucumber.feature/feature.xml
index c8493837..f50c86fe 100644
--- a/org.agileware.natural.cucumber.feature/feature.xml
+++ b/org.agileware.natural.cucumber.feature/feature.xml
@@ -66,7 +66,14 @@ to corresponding Java annotated classes.
unpack="false"/>
+
+
4.0.0
@@ -8,7 +9,6 @@
org.agileware.natural.cucumber.tests
eclipse-test-plugin
- 1.0.0-SNAPSHOT
@@ -16,14 +16,15 @@
org.eclipse.xtend
xtend-maven-plugin
+
+ org.eclipse.tycho
+ tycho-surefire-plugin
+
+ org.agileware.natural.cucumber.tests
+ org.agileware.natural.cucumber.tests.CucumberTestSuite
+
+
-
-
- org.hamcrest
- hamcrest
- 2.2
-
-
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/Constants.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/Constants.xtend
index 9cd2c38e..9b3be2c5 100644
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/Constants.xtend
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/Constants.xtend
@@ -8,49 +8,52 @@ class Constants {
@version:1.0.0
@pet_store
Feature: Add a new pet
+
In order to sell a pet
As a store owner
I want to add a new pet to the catalog
- Background: Add a dog
- Given I have the following pet
- | name | status |
- | Fido | available |
- And I add the pet to the store
- But the pet is not yet mine
+ Background: Add a dog
+ Given I have the following pet
+ | name | status |
+ | Fido | available |
+ And I add the pet to the store
+ But the pet is not yet mine
- @add @fido
- Scenario: Add another dog
- Then the should be available in the store
+ @add
+ @fido
+ Scenario: Add another dog
+ Then the should be available in the store
- @update @fido
- Scenario:
- Given the pet is available in the store -9.8
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- When I update the pet with
- | name | status |
- | Fido | unavailable |
- Then the pet should be "unavailable" in the store
+ @update
+ @fido
+ Scenario:
+ Given the pet is available in the store -9.8
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ When I update the pet with
+ | name | status |
+ | Fido | unavailable |
+ Then the pet should be "unavailable" in the store
- @eat-pickles
- Scenario Outline: Eating pickles
- Given there are pickles
- When I eat pickles
- Then I should have pickles
+ @eat-pickles
+ Scenario Outline: Eating pickles
+ Given there are pickles
+ When I eat pickles
+ Then I should have pickles
- @hungry
- Examples:
- | start | eat | left |
- | 12 | 10 | 2 |
- | 20 | 15 | 5 |
+ @hungry
+ Examples:
+ | start | eat | left |
+ | 12 | 10 | 2 |
+ | 20 | 15 | 5 |
- @full
- Examples: With a title
- | start | eat | left |
- | 12 | 2 | 10 |
- | 20 | 5 | 15 |
+ @full
+ Examples: With a title
+ | start | eat | left |
+ | 12 | 2 | 10 |
+ | 20 | 5 | 15 |
'''
}
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExampleTestSuite.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExampleTestSuite.xtend
deleted file mode 100644
index 5aae77ac..00000000
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExampleTestSuite.xtend
+++ /dev/null
@@ -1,194 +0,0 @@
-package org.agileware.natural.cucumber.tests
-
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Suite
-
-@RunWith(Suite)
-@Suite.SuiteClasses(BackgroundExamples, ScenarioExamples, ScenarioOutlineExamples, PathologicalExamples)
-class CucumberExampleTestSuite {
-
- static class BackgroundExamples extends CucumberExamplesTest {
-
- @Test
- def void background_01() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
-
- Background: Foo
- Given "Jack" went up the hill
-
- Scenario:
- Given a step
- ''')
- }
-
- @Test
- def void background_02() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
-
- @foo @bar
- Background: Jack and Jill
- The quick brown fox
- Jumps over the lazy dog
-
- Given the stock is traded at 5.0
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- And the alert status should be OFF
- When the stock is traded at 11.0
- | precondition | be-captured |
- | abc | be captured |
- | xyz | not be captured |
- Then the alert status should be ON
-
- Scenario:
- Given a step
- ''')
- }
- }
-
- static class ScenarioExamples extends CucumberExamplesTest {
-
- @Test
- def void scenario_01() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
- Scenario: A
- Given a step
- ''')
- }
-
- @Test
- def void scenario_02() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
- The quick brown fox
- Jumps over the lazy dog
-
- Scenario:
- The quick brown fox
- Jumps over the lazy dog
-
- Given a step
-
- Scenario: B
- And another
- ''')
- }
-
- @Test
- def void scenario_03() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
-
- @foo @bar
- Scenario: Stock Symbols
- The quick brown fox
- Jumps over the lazy dog
-
- Given the stock is traded at 5.0
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- And the alert status should be OFF
- When the stock is traded at 11.0
- | precondition | be-captured |
- | abc | be captured |
- | xyz | not be captured |
- Then the alert status should be ON
- ''')
- }
- }
-
- static class ScenarioOutlineExamples extends CucumberExamplesTest {
- @Test
- def void scenario_outline_01() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
-
- Scenario Outline: Eating pickles
- Given there are pickles
- When I eat pickles
- Then I should have pickles
-
- Examples:
- | start | eat | left |
- | 12 | 10 | 2 |
- | 20 | 15 | 5 |
- ''')
- }
-
- @Test
- def void scenario_outline_02() {
- assertExampleParses('''
- # language: en
- Feature: Hello, Cucumber!
-
- @eating-pickles
- Scenario Outline: Eating pickles
- Given there are pickles
- When I eat pickles
- Then I should have pickles
-
- @foo
- Examples: A
- | start | eat | left |
- | 12 | 10 | 2 |
-
- @bar
- Examples: B
- | start | eat | left |
- | 20 | 15 | 5 |
- ''')
- }
-
- }
-
- static class PathologicalExamples extends CucumberExamplesTest {
-
- @Test
- def void pathological_01() {
- assertExampleParses('''
- # language: en
- Feature: ASCII punctuation
- ,./;'[]\-=
- <>?:"{}|_+
- !@#$%^&*()`~
-
- Scenario:
- Given a step
- ''')
- }
-
- @Test
- def void pathological_03() {
- assertExampleParses('''
- # language: en
- Feature: Two-Byte Characters
- 田中さんにあげて下さい
- パーティーへ行かないか
- 和製漢語
- 部落格
- 사회과학원 어학연구소
- 찦차를 타고 온 펲시맨과 쑛다리 똠방각하
- 社會科學院語學研究所
- 울란바토르
- 𠜎𠜱𠝹𠱓𠱸𠲖𠳏
-
- Scenario:
- Given a step
- ''')
- }
- }
-}
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExamplesTest.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExamplesTest.xtend
index 06d46267..708a89f1 100644
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExamplesTest.xtend
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberExamplesTest.xtend
@@ -1,11 +1,211 @@
package org.agileware.natural.cucumber.tests
-import org.agileware.natural.cucumber.cucumber.Feature
+import org.agileware.natural.cucumber.cucumber.CucumberModel
import org.agileware.natural.testing.AbstractExamplesTest
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
import org.junit.runner.RunWith
@RunWith(XtextRunner)
@InjectWith(CucumberInjectorProvider)
-class CucumberExamplesTest extends AbstractExamplesTest {}
+class CucumberExamplesTest extends AbstractExamplesTest {
+
+ @Test
+ def void background_01() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+
+ Background: Foo
+ Given "Jack" went up the hill
+
+ Scenario:
+ Given a step
+ ''')
+ }
+
+ @Test
+ def void background_02() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+
+ @foo @bar
+ Background: Jack and Jill
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Given the stock is traded at 5.0
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ And the alert status should be OFF
+ When the stock is traded at 11.0
+ | precondition | be-captured |
+ | abc | be captured |
+ | xyz | not be captured |
+ Then the alert status should be ON
+
+ Scenario:
+ Given a step
+ ''')
+ }
+
+ @Test
+ def void scenario_01() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+ Scenario: A
+ Given a step
+ ''')
+ }
+
+ @Test
+ def void scenario_02() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Scenario:
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Given a step
+
+ Scenario: B
+ And another
+ ''')
+ }
+
+ @Test
+ def void scenario_03() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+
+ @foo @bar
+ Scenario: Stock Symbols
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Given the stock is traded at 5.0
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ And the alert status should be OFF
+ When the stock is traded at 11.0
+ | precondition | be-captured |
+ | abc | be captured |
+ | xyz | not be captured |
+ Then the alert status should be ON
+ ''')
+ }
+
+ @Test
+ def void scenario_outline_01() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+
+ Scenario Outline: Eating pickles
+ Given there are pickles
+ When I eat pickles
+ Then I should have pickles
+
+ Examples:
+ | start | eat | left |
+ | 12 | 10 | 2 |
+ | 20 | 15 | 5 |
+ ''')
+ }
+
+ @Test
+ def void scenario_outline_02() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, Cucumber!
+
+ @eating-pickles
+ Scenario Outline: Eating pickles
+ Given there are pickles
+ When I eat pickles
+ Then I should have pickles
+
+ @foo
+ Examples: A
+ | start | eat | left |
+ | 12 | 10 | 2 |
+
+ @bar
+ Examples: B
+ | start | eat | left |
+ | 20 | 15 | 5 |
+ ''')
+ }
+
+ @Test
+ def void pathological_01() {
+ assertExampleParses('''
+ # language: en
+ Feature: ASCII punctuation
+ # ,./;'[]\-=
+ # <>?:"{}|_+
+ # !@#$%^&*()`~
+
+ Scenario:
+ Given a step
+ ''')
+ }
+
+ @Test
+ def void pathological_02() {
+ assertExampleParses('''
+ # language: en
+ Feature: Two-Byte Characters
+ 田中さんにあげて下さい
+ パーティーへ行かないか
+ 和製漢語
+ 部落格
+ 사회과학원 어학연구소
+ 찦차를 타고 온 펲시맨과 쑛다리 똠방각하
+ 社會科學院語學研究所
+ 울란바토르
+ 𠜎𠜱𠝹𠱓𠱸𠲖𠳏
+
+ Scenario:
+ Given a step
+ ''')
+ }
+
+ @Test
+ def void pathological_03() {
+ assertExampleParses('''
+ # language: en
+ ''')
+ }
+
+ @Test
+ def void pathological_04() {
+ assertExampleParses('''
+ # language: en
+ Feature: Hello, World!
+ ''')
+ }
+
+ @Test
+ def void pathological_05() {
+ assertExampleParses('''
+ # language: en
+ Feature:
+ Background:
+ Scenario: A
+ Scenario: B
+ ''')
+ }
+}
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberFormatterTest.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberFormatterTest.xtend
index becc924a..8fb6cf25 100644
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberFormatterTest.xtend
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberFormatterTest.xtend
@@ -1,6 +1,6 @@
package org.agileware.natural.cucumber.tests
-import org.agileware.natural.cucumber.cucumber.Feature
+import org.agileware.natural.cucumber.cucumber.CucumberModel
import org.agileware.natural.testing.AbstractFormatterTest
import org.eclipse.xtext.testing.InjectWith
import org.eclipse.xtext.testing.XtextRunner
@@ -11,7 +11,7 @@ import static org.agileware.natural.cucumber.tests.Constants.EXAMPLE_FEATURE
@RunWith(XtextRunner)
@InjectWith(CucumberInjectorProvider)
-class CucumberFormatterTest extends AbstractFormatterTest {
+class CucumberFormatterTest extends AbstractFormatterTest {
@Test
def void preserveValidFormatting() {
@@ -24,13 +24,13 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val toBeFormatted = '''
# language: en
Feature: Jack and Jill
-
- Background:
- Given a precondition
-
- Scenario: Jack falls down
- When Jack falls down
- Then Jill comes tumbling after
+
+ Background:
+ Given a precondition
+
+ Scenario: Jack falls down
+ When Jack falls down
+ Then Jill comes tumbling after
'''
assertFormatted(toBeFormatted)
}
@@ -52,13 +52,13 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
Feature: Jack and Jill
+
+ Background:
+ Given a precondition
- Background:
- Given a precondition
-
- Scenario: Jack falls down
- When Jack falls down
- Then Jill comes tumbling after
+ Scenario: Jack falls down
+ When Jack falls down
+ Then Jill comes tumbling after
'''
assertFormatted(toBeFormatted, expectation)
}
@@ -69,7 +69,7 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val toBeFormatted = '''
# language: en
@foo
- @bar:1
+ @bar
Feature: Jack and Jill
Background:
@@ -88,21 +88,22 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
@foo
- @bar:1
+ @bar
Feature: Jack and Jill
+
+ Background:
+ Given a precondition
- Background:
- Given a precondition
-
- @foo @bar
- Scenario: A
- And another
+ @foo
+ @bar
+ Scenario: A
+ And another
- @foo
- @bar
- Scenario: B
- When something happens
- Then there should be a result
+ @foo
+ @bar
+ Scenario: B
+ When something happens
+ Then there should be a result
'''
assertFormatted(toBeFormatted, expectation)
}
@@ -113,15 +114,15 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val toBeFormatted = '''
# language: en
Feature: With a title
-
- Scenario Outline:
- Given
- And
-
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
+
+ Scenario Outline:
+ Given
+ And
+
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
'''
assertFormatted(toBeFormatted)
}
@@ -144,15 +145,15 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
Feature: With a title
-
- Scenario Outline:
- Given
- And
-
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
+
+ Scenario Outline:
+ Given
+ And
+
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
'''
assertFormatted(toBeFormatted, expectation)
}
@@ -163,22 +164,22 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val toBeFormatted = '''
# language: en
Feature: With a title
-
- Scenario Outline:
- Given
- And
-
- @foo
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
-
- @bar
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
+
+ Scenario Outline:
+ Given
+ And
+
+ @foo
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
+
+ @bar
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
'''
assertFormatted(toBeFormatted)
}
@@ -208,27 +209,26 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
Feature: With a title
-
- Scenario Outline:
- Given
- And
-
- @foo
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
-
- @bar
- Examples:
- | foo | bar |
- | 12 | 10 |
- | 20 | 15 |
+
+ Scenario Outline:
+ Given
+ And
+
+ @foo
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
+
+ @bar
+ Examples:
+ | foo | bar |
+ | 12 | 10 |
+ | 20 | 15 |
'''
assertFormatted(toBeFormatted, expectation)
}
-
-
+
@Test
def void indentDocString_01() {
// SHOULD DocString to column 1
@@ -246,44 +246,43 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
Feature: With a title
-
- Scenario:
- Given the DocString
- """
- The quick brown fox
- Jumps over the lazy dog
- """
+
+ Scenario:
+ Given the DocString
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
'''
assertFormatted(toBeFormatted, expectation)
}
-
+
@Test
def void indentStepInterior_01() {
// MUST preserve existing formatting
val toBeFormatted = '''
# language: en
Feature: With a title
-
- Scenario: Stock Symbols
- The quick brown fox
- Jumps over the lazy dog
-
- Given the stock is traded at 5.0
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- And the alert status should be OFF
- When the stock is traded at 11.0
- | precondition | be-captured |
- | abc | be captured |
- | xyz | not be captured |
- Then the alert status should be ON
+
+ Scenario: Stock Symbols
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Given the stock is traded at 5.0
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ And the alert status should be OFF
+ When the stock is traded at 11.0
+ | precondition | be-captured |
+ | abc | be captured |
+ | xyz | not be captured |
+ Then the alert status should be ON
'''
assertFormatted(toBeFormatted)
}
-
-
+
@Test
def void indentStepInterior_02() {
// SHOULD align Table and DocString to column 1
@@ -307,19 +306,19 @@ class CucumberFormatterTest extends AbstractFormatterTest {
val expectation = '''
# language: en
Feature: With a title
-
- Scenario:
- Given the stock is traded at 5.0
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- And the alert status should be OFF
- When the stock is traded at 11.0
- | precondition | be-captured |
- | abc | be captured |
- | xyz | not be captured |
- Then the alert status should be ON
+
+ Scenario:
+ Given the stock is traded at 5.0
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ And the alert status should be OFF
+ When the stock is traded at 11.0
+ | precondition | be-captured |
+ | abc | be captured |
+ | xyz | not be captured |
+ Then the alert status should be ON
'''
assertFormatted(toBeFormatted, expectation)
}
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberParsingTest.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberParsingTest.xtend
index ebd50e72..4f3f644c 100644
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberParsingTest.xtend
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberParsingTest.xtend
@@ -1,7 +1,7 @@
package org.agileware.natural.cucumber.tests
import com.google.inject.Inject
-import org.agileware.natural.cucumber.cucumber.Feature
+import org.agileware.natural.cucumber.cucumber.CucumberModel
import org.agileware.natural.cucumber.cucumber.ScenarioOutline
import org.agileware.natural.cucumber.serializer.CucumberSerializer
import org.agileware.natural.testing.AbstractParserTest
@@ -16,7 +16,7 @@ import static org.hamcrest.Matchers.*
@RunWith(XtextRunner)
@InjectWith(CucumberInjectorProvider)
-class CucumberParsingTest extends AbstractParserTest {
+class CucumberParsingTest extends AbstractParserTest {
@Inject CucumberSerializer serializer
@@ -34,11 +34,8 @@ class CucumberParsingTest extends AbstractParserTest {
assertThat(model, notNullValue())
assertThat(validate(model), empty())
-
- println(serializer.serialize(model))
}
-
-
+
@Test
def void parseTableData() {
val model = parse('''
@@ -61,14 +58,17 @@ class CucumberParsingTest extends AbstractParserTest {
assertThat(model, notNullValue())
assertThat(validate(model), empty())
-
- val t1 = model.scenarios.get(0).steps.get(0).table
- assertThat(t1, notNullValue())
- assertThat(t1.rows, hasSize(1))
-
- val t2 = (model.scenarios.get(1) as ScenarioOutline).examples.get(0).table
- assertThat(t2, notNullValue())
- assertThat(t2.rows, hasSize(3))
+
+ val doc = model.document
+ assertThat(doc, notNullValue())
+
+// val t1 = doc.scenarios.get(0).steps.get(0).table
+// assertThat(t1, notNullValue())
+// assertThat(t1.rows, hasSize(1))
+//
+// val t2 = (doc.scenarios.get(1) as ScenarioOutline).examples.get(0).table
+// assertThat(t2, notNullValue())
+// assertThat(t2.rows, hasSize(3))
}
@Test
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberTestSuite.java b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberTestSuite.java
index c8683c39..edad0f63 100644
--- a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberTestSuite.java
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberTestSuite.java
@@ -5,8 +5,9 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
- CucumberExampleTestSuite.class,
+ CucumberExamplesTest.class,
CucumberParsingTest.class,
- CucumberFormatterTest.class
+ CucumberFormatterTest.class,
+ CucumberValidatorTest.class
})
public class CucumberTestSuite {}
diff --git a/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberValidatorTest.xtend b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberValidatorTest.xtend
new file mode 100644
index 00000000..6701e386
--- /dev/null
+++ b/org.agileware.natural.cucumber.tests/src/org/agileware/natural/cucumber/tests/CucumberValidatorTest.xtend
@@ -0,0 +1,51 @@
+package org.agileware.natural.cucumber.tests
+
+import org.agileware.natural.cucumber.cucumber.CucumberModel
+import org.agileware.natural.testing.AbstractParserTest
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import static org.agileware.natural.cucumber.validation.CucumberIssueCodes.*
+import static org.agileware.natural.testing.Matchers.*
+import static org.hamcrest.MatcherAssert.*
+import static org.hamcrest.Matchers.*
+
+@RunWith(XtextRunner)
+@InjectWith(CucumberInjectorProvider)
+class CucumberValidatorTest extends AbstractParserTest {
+
+ @Test
+ def void featureMissingTitle() {
+ val issues = validate(parse('''
+ # language: en
+ Feature:
+ Scenario: A
+ Given a step
+ '''))
+
+ assertThat(issues, hasItems(theWarning(MISSING_FEATURE_TITLE)))
+ }
+
+ @Test
+ def void featureMissingScenarios() {
+ val issues = validate(parse('''
+ # language: en
+ Feature: With a title
+ '''))
+
+ assertThat(issues, hasItems(theWarning(MISSING_SCENARIOS)))
+ }
+
+ @Test
+ def void scenarioMissingSteps() {
+ val issues = validate(parse('''
+ # language: en
+ Feature: With a title
+ Background:
+ '''))
+
+ assertThat(issues, hasItems(theWarning(MISSING_SCENARIO_STEPS)))
+ }
+}
diff --git a/org.agileware.natural.cucumber.ui.tests/build.properties b/org.agileware.natural.cucumber.ui.tests/build.properties
index d2866c42..5c6bbf99 100644
--- a/org.agileware.natural.cucumber.ui.tests/build.properties
+++ b/org.agileware.natural.cucumber.ui.tests/build.properties
@@ -4,4 +4,3 @@ source.. = src/,\
bin.includes = .,\
META-INF/
bin.excludes = **/*.xtend
-jars.extra.classpath = platform:/plugin/org.agileware.natural.testing/lib/hamcrest-2.2.jar
diff --git a/org.agileware.natural.cucumber.ui.tests/pom.xml b/org.agileware.natural.cucumber.ui.tests/pom.xml
index ecc4857e..c09645fd 100644
--- a/org.agileware.natural.cucumber.ui.tests/pom.xml
+++ b/org.agileware.natural.cucumber.ui.tests/pom.xml
@@ -1,4 +1,5 @@
-
4.0.0
@@ -19,11 +20,14 @@
org.eclipse.tycho
tycho-surefire-plugin
+ false
true
+ true
+ org.agileware.natural.cucumber.ui.tests
+ org.agileware.natural.cucumber.ui.tests.CucumberUiTestSuite
- 1.0.0-SNAPSHOT
diff --git a/org.agileware.natural.cucumber.ui.tests/src/org/agileware/natural/cucumber/ui/tests/CucumberHighlightingTest.xtend b/org.agileware.natural.cucumber.ui.tests/src/org/agileware/natural/cucumber/ui/tests/CucumberHighlightingTest.xtend
index dbfbf72e..4d92b705 100644
--- a/org.agileware.natural.cucumber.ui.tests/src/org/agileware/natural/cucumber/ui/tests/CucumberHighlightingTest.xtend
+++ b/org.agileware.natural.cucumber.ui.tests/src/org/agileware/natural/cucumber/ui/tests/CucumberHighlightingTest.xtend
@@ -5,12 +5,334 @@ import org.eclipse.xtext.testing.XtextRunner
import org.eclipse.xtext.ui.testing.AbstractHighlightingTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.agileware.natural.cucumber.ui.syntaxcoloring.HighlightingConfiguration
+import com.google.inject.Inject
@RunWith(XtextRunner)
@InjectWith(CucumberUiInjectorProvider)
class CucumberHighlightingTest extends AbstractHighlightingTest {
+
+ @Inject extension HighlightingConfiguration
+
@Test
- def void helloHighlighting() {
- // TODO...
+ def void featureKeyword() {
+ '''
+ Feature:
+ '''.testHighlighting("Feature:", keywordTextStyle)
+ }
+
+ @Test
+ def void backgroundKeyword() {
+ '''
+ Feature:
+ Background:
+ '''.testHighlighting("Background:", keywordTextStyle)
+ }
+
+ @Test
+ def void scenarioKeyword() {
+ '''
+ Feature:
+ Scenario:
+ '''.testHighlighting("Scenario:", keywordTextStyle)
+ }
+
+ @Test
+ def void scenarioOutlineKeyword() {
+ '''
+ Feature:
+ Scenario Outline:
+ '''.testHighlighting("Scenario Outline:", keywordTextStyle)
+ }
+
+ @Test
+ def void examplesKeyword() {
+ '''
+ Feature:
+ Scenario Outline:
+ Examples:
+ | foo |
+ '''.testHighlighting("Examples:", keywordTextStyle)
+ }
+
+ @Test
+ def void givenStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ Given foo
+ '''.testHighlighting("Given", keywordTextStyle)
+ }
+
+ @Test
+ def void whenStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ When foo
+ '''.testHighlighting("When", keywordTextStyle)
+ }
+
+ @Test
+ def void thenStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ Then foo
+ '''.testHighlighting("Then", keywordTextStyle)
+ }
+
+ @Test
+ def void andStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ And foo
+ '''.testHighlighting("And", keywordTextStyle)
+ }
+
+ @Test
+ def void butStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ But foo
+ '''.testHighlighting("But", keywordTextStyle)
+ }
+
+ @Test
+ def void anyStepKeyword() {
+ '''
+ Feature:
+ Scenario:
+ * foo
+ '''.testHighlighting("*", keywordTextStyle)
+ }
+
+ @Test
+ def void docString_01() {
+ '''
+ Feature:
+ """
+ The quick brown fox
+ Jumps pver the lazy dog
+ """
+ '''.testHighlighting('''
+ """
+ The quick brown fox
+ Jumps pver the lazy dog
+ """
+ ''', docStringTextStyle)
+ }
+
+ @Test
+ def void docString_02() {
+ '''
+ Feature:
+ Scenario:
+ Given foo
+ """
+ The quick brown fox
+ Jumps pver the lazy dog
+ """
+ '''.testHighlighting('''
+ """
+ The quick brown fox
+ Jumps pver the lazy dog
+ """
+ ''', docStringTextStyle)
+ }
+
+ @Test
+ def void table_01() {
+ '''
+ Feature:
+ | x | 0 |
+ | y | 1 |
+ '''.testHighlighting('''
+ | x | 0 |
+ | y | 1 |
+ ''', tableTextStyle)
+ }
+
+ @Test
+ def void table_02() {
+ '''
+ Feature:
+ Scenario:
+ Given foo
+ | x | 0 |
+ | y | 1 |
+ '''.testHighlighting('''
+ | x | 0 |
+ | y | 1 |
+ ''', docStringTextStyle)
+ }
+
+ @Test
+ def void table_03() {
+ '''
+ Feature:
+ Scenario Outline:
+ Given and
+ Examples:
+ | x | 0 |
+ | y | 1 |
+ '''.testHighlighting('''
+ | x | 0 |
+ | y | 1 |
+ ''', docStringTextStyle)
+ }
+
+ @Test
+ def void comment_01() {
+ '''
+ # language: en
+ Feature:
+ '''.testHighlighting("# language: en", commentTextStyle)
+ }
+
+ @Test
+ def void comment_02() {
+ '''
+ Feature: #Foo
+ '''.testHighlighting("#Foo", commentTextStyle)
+ }
+
+ @Test
+ def void string_01() {
+ '''
+ Feature:
+ Scenario:
+ Given "foo"
+ '''.testHighlighting("\"foo\"", stringTextStyle)
+ }
+
+ @Test
+ def void string_02() {
+ '''
+ Feature:
+ Scenario:
+ Given ullamcorper "pretium ut eu" neque.
+ '''.testHighlighting("\"pretium ut eu\"", stringTextStyle)
+ }
+
+ @Test
+ def void string_03() {
+ '''
+ Feature:
+ Scenario:
+ Given 'foo'
+ '''.testHighlighting("'foo'", stringTextStyle)
+ }
+
+ @Test
+ def void string_04() {
+ '''
+ Feature:
+ Scenario:
+ Given ullamcorper 'pretium ut eu' neque.
+ '''.testHighlighting("'pretium ut eu'", stringTextStyle)
+ }
+
+
+ @Test
+ def void number_01() {
+ '''
+ Feature:
+ Scenario:
+ Given 0
+ '''.testHighlighting("0", numberTextStyle)
+ }
+
+ @Test
+ def void number_02() {
+ '''
+ Feature:
+ Scenario:
+ Given 1
+ '''.testHighlighting("1", numberTextStyle)
+ }
+
+ @Test
+ def void number_03() {
+ '''
+ Feature:
+ Scenario:
+ Given -1
+ '''.testHighlighting("-1", numberTextStyle)
+ }
+
+
+ @Test
+ def void number_04() {
+ '''
+ Feature:
+ Scenario:
+ Given 1.0
+ '''.testHighlighting("1.0", numberTextStyle)
+ }
+
+ @Test
+ def void number_05() {
+ '''
+ Feature:
+ Scenario:
+ Given -1.0
+ '''.testHighlighting("-1.0", numberTextStyle)
+ }
+
+ @Test
+ def void number_06() {
+ '''
+ Feature:
+ Scenario:
+ Given 3.30e23
+ '''.testHighlighting("3.30e23", numberTextStyle)
+ }
+
+ @Test
+ def void number_07() {
+ '''
+ Feature:
+ Scenario:
+ Given 6.67E-11
+ '''.testHighlighting("6.67E-11", numberTextStyle)
+ }
+
+ @Test
+ def void number_08() {
+ '''
+ Feature:
+ Scenario:
+ Given -3.30e23
+ '''.testHighlighting("-3.30e23", numberTextStyle)
+ }
+
+ @Test
+ def void number_09() {
+ '''
+ Feature:
+ Scenario:
+ Given 0xFFFFFF
+ '''.testHighlighting("0xFFFFFF", numberTextStyle)
+ }
+
+ @Test
+ def void number_10() {
+ '''
+ Feature:
+ Scenario:
+ Given -0xFFFFFF
+ '''.testHighlighting("-0xFFFFFF", numberTextStyle)
+ }
+
+ @Test
+ def void number_11() {
+ '''
+ Feature:
+ Scenario:
+ Given 1.0.0
+ '''.testHighlighting("1.0.0", defaultTextStyle)
}
}
diff --git a/org.agileware.natural.cucumber.ui/META-INF/MANIFEST.MF b/org.agileware.natural.cucumber.ui/META-INF/MANIFEST.MF
index cab0ddab..d3f1a3b2 100644
--- a/org.agileware.natural.cucumber.ui/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.cucumber.ui/META-INF/MANIFEST.MF
@@ -8,6 +8,8 @@ Bundle-SymbolicName: org.agileware.natural.cucumber.ui; singleton:=true
Bundle-ActivationPolicy: lazy
Require-Bundle: org.agileware.natural.cucumber,
org.agileware.natural.cucumber.ide,
+ org.agileware.natural.lang.ui,
+ org.agileware.natural.stepmatcher.ui,
org.eclipse.xtext.ui,
org.eclipse.xtext.ui.shared,
org.eclipse.xtext.ui.codetemplates.ui,
@@ -24,11 +26,29 @@ Require-Bundle: org.agileware.natural.cucumber,
Import-Package: org.apache.log4j,
org.eclipse.xtext.ui.codemining;resolution:=optional
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.agileware.natural.cucumber.ui.contentassist;uses:="org.eclipse.emf.ecore,org.eclipse.xtext.ui.editor.contentassist,org.eclipse.xtext",
+Export-Package: org.agileware.natural.cucumber.ui.codemining;
+ uses:="org.eclipse.xtext.ui.codemining,
+ org.eclipse.jface.text,
+ org.eclipse.xtext.resource,
+ org.eclipse.xtext.util",
+ org.agileware.natural.cucumber.ui.contentassist;
+ uses:="org.eclipse.emf.ecore,
+ org.agileware.natural.lang.ui.contentassist,
+ org.eclipse.xtext.ui.editor.contentassist,
+ org.eclipse.xtext",
org.agileware.natural.cucumber.ui.internal;uses:="org.osgi.framework,com.google.inject,org.eclipse.ui.plugin",
- org.agileware.natural.cucumber.ui.labeling;uses:="org.eclipse.xtext.ui.label,org.eclipse.emf.edit.ui.provider,org.agileware.natural.cucumber.cucumber",
- org.agileware.natural.cucumber.ui.outline;uses:="org.eclipse.xtext.ui.editor.outline.impl,org.agileware.natural.cucumber.cucumber",
+ org.agileware.natural.cucumber.ui.labeling;
+ uses:="org.agileware.natural.lang.model,
+ org.eclipse.xtext.ui.label,
+ org.eclipse.emf.edit.ui.provider,
+ org.agileware.natural.cucumber.cucumber",
+ org.agileware.natural.cucumber.ui.outline;uses:="org.eclipse.xtext.ui.editor.outline.impl,org.agileware.natural.lang.model,org.agileware.natural.cucumber.cucumber",
org.agileware.natural.cucumber.ui.quickfix;uses:="org.eclipse.xtext.ui.editor.quickfix",
- org.agileware.natural.cucumber.ui.syntaxcoloring;uses:="org.eclipse.xtext.resource,org.eclipse.xtext.ui.editor.utils,org.eclipse.xtext.ui.editor.syntaxcoloring",
+ org.agileware.natural.cucumber.ui.syntaxcoloring;
+ uses:="org.eclipse.xtext.ide.editor.syntaxcoloring,
+ org.eclipse.xtext.resource,
+ org.eclipse.xtext.util,
+ org.eclipse.xtext.ui.editor.utils,
+ org.eclipse.xtext.ui.editor.syntaxcoloring",
org.agileware.natural.cucumber.validation;uses:="org.eclipse.swt.widgets,org.eclipse.jface.dialogs,org.eclipse.xtext.ui.validation"
-Bundle-Activator: org.agileware.natural.cucumber.ui.internal.CucumberActivator
+Bundle-Activator: org.agileware.natural.cucumber.ui.CucumberActivator
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/BuilderParticipant.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/BuilderParticipant.java
index a162d7f9..ebb78666 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/BuilderParticipant.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/BuilderParticipant.java
@@ -1,19 +1,21 @@
package org.agileware.natural.cucumber.ui;
-import org.agileware.natural.common.JavaAnnotationMatcher;
+import org.agileware.natural.stepmatcher.ui.JavaAnnotationMatcher;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import com.google.inject.Inject;
public class BuilderParticipant extends org.eclipse.xtext.builder.BuilderParticipant {
+
@Inject
private JavaAnnotationMatcher matcher;
-
- public void build(final IBuildContext context, IProgressMonitor monitor) throws CoreException {
+
+ @Override
+ public void build(final IBuildContext context, final IProgressMonitor monitor) throws CoreException {
super.build(context, monitor);
if (!context.getResourceSet().getResources().isEmpty()) {
- //TODO iterate over the resources to evict only those that have changed
+ // TODO iterate over the resources to evict only those that have changed
// matcher.evict(null);
}
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberActivator.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberActivator.java
index d8bd9a67..723ad49d 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberActivator.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberActivator.java
@@ -1,7 +1,6 @@
package org.agileware.natural.cucumber.ui;
-import org.agileware.natural.common.AbstractAnnotationDescriptor;
-import org.agileware.natural.common.JavaElementChangeReporter;
+import org.agileware.natural.stepmatcher.ui.JavaElementChangeReporter;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.JavaCore;
@@ -9,9 +8,9 @@
@SuppressWarnings("unused")
public class CucumberActivator extends org.agileware.natural.cucumber.ui.internal.CucumberActivator {
-
+
@Inject
- public void setJavaElementChangeReporter(JavaElementChangeReporter reporter) {
+ public void setJavaElementChangeReporter(final JavaElementChangeReporter reporter) {
// Listen to Java class changes
JavaCore.addElementChangedListener(reporter, ElementChangedEvent.POST_CHANGE);
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberHyperlinkHelper.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberHyperlinkHelper.java
index 9d40f76f..72ba4a3a 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberHyperlinkHelper.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberHyperlinkHelper.java
@@ -5,11 +5,10 @@
import java.util.Collection;
import java.util.List;
-import org.agileware.natural.common.JavaAnnotationMatcher;
-import org.agileware.natural.common.JavaHyperlink;
import org.agileware.natural.cucumber.cucumber.Step;
+import org.agileware.natural.stepmatcher.ui.JavaAnnotationMatcher;
+import org.agileware.natural.stepmatcher.ui.JavaHyperlink;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.jdt.core.IMethod;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.xtext.nodemodel.INode;
@@ -27,37 +26,34 @@ public class CucumberHyperlinkHelper extends HyperlinkHelper {
@Inject
private EObjectAtOffsetHelper helper;
-
+
@Inject
private JavaAnnotationMatcher matcher;
@Override
- public IHyperlink[] createHyperlinksByOffset(XtextResource resource, int offset, boolean createMultipleHyperlinks) {
- IHyperlink[] defaults = super.createHyperlinksByOffset(resource, offset, createMultipleHyperlinks);
- List hyperlinks = (defaults == null ? new ArrayList() : Arrays.asList(defaults));
+ public IHyperlink[] createHyperlinksByOffset(final XtextResource resource, final int offset,
+ final boolean createMultipleHyperlinks) {
+ final IHyperlink[] defaults = super.createHyperlinksByOffset(resource, offset, createMultipleHyperlinks);
+ final List hyperlinks = (defaults == null ? new ArrayList() : Arrays.asList(defaults));
- EObject eObject = helper.resolveElementAt(resource, offset);
+ final EObject eObject = helper.resolveElementAt(resource, offset);
if (eObject instanceof Step) {
- IParseResult parseResult = resource.getParseResult();
+ final IParseResult parseResult = resource.getParseResult();
INode node = NodeModelUtils.findLeafNodeAtOffset(parseResult.getRootNode(), offset);
while (!(node instanceof CompositeNode && node.getSemanticElement() instanceof Step)) {
node = node.getParent();
}
- String description = ((Step) eObject).getDescription();
- hyperlinks.addAll(findLinkTargets(description, new Region(node.getOffset(), node.getText().trim().length())));
+ final String description = ((Step) eObject).getDescription();
+ final Region region = new Region(node.getOffset(), node.getText().trim().length());
+ hyperlinks.addAll(findLinkTargets(description, region));
}
return hyperlinks.isEmpty() ? null : Iterables.toArray(hyperlinks, IHyperlink.class);
}
- private Collection extends IHyperlink> findLinkTargets(String description, final Region region) {
+ private Collection extends IHyperlink> findLinkTargets(final String description, final Region region) {
final List results = new ArrayList();
- matcher.findMatches(description.trim(), new JavaAnnotationMatcher.Command() {
-
- public void match(String annotationValue, IMethod method) {
- results.add(new JavaHyperlink("Open definition " + annotationValue, method, region));
-
- }
- });
+ matcher.findMatches(description.trim(), (annotationValue, method) -> results
+ .add(new JavaHyperlink("Open definition " + annotationValue, method, region)));
return results;
}
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberUiModule.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberUiModule.java
index 3d453f46..a71ab803 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberUiModule.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/CucumberUiModule.java
@@ -6,24 +6,25 @@
import org.agileware.natural.cucumber.ui.syntaxcoloring.HighlightingConfiguration;
import org.agileware.natural.cucumber.ui.syntaxcoloring.LexicalHighlightingCalculator;
import org.agileware.natural.cucumber.ui.syntaxcoloring.SemanticHighlightingCalculator;
+import org.agileware.natural.stepmatcher.IStepMatcher;
+import org.agileware.natural.stepmatcher.ui.AbstractAnnotationDescriptor;
+import org.agileware.natural.stepmatcher.ui.JavaAnnotationMatcher;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.xtext.builder.IXtextBuilderParticipant;
+import org.eclipse.xtext.ide.editor.syntaxcoloring.ISemanticHighlightingCalculator;
import org.eclipse.xtext.ui.editor.hyperlinking.IHyperlinkHelper;
import org.eclipse.xtext.ui.editor.syntaxcoloring.AbstractAntlrTokenToAttributeIdMapper;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;
/**
* Use this class to register components to be used within the IDE.
*/
public class CucumberUiModule extends AbstractCucumberUiModule {
-
- public CucumberUiModule(AbstractUIPlugin plugin) {
+
+ public CucumberUiModule(final AbstractUIPlugin plugin) {
super(plugin);
}
-
- // TODO requires Xbase
- // @Override
+
public Class extends IHyperlinkHelper> bindIHyperlinkHelper() {
return CucumberHyperlinkHelper.class;
}
@@ -35,7 +36,7 @@ public Class extends IHighlightingConfiguration> bindIHighlightingConfiguratio
public Class extends AbstractAntlrTokenToAttributeIdMapper> bindAbstractAntlrTokenToAttributeIdMapper() {
return LexicalHighlightingCalculator.class;
}
-
+
public Class extends ISemanticHighlightingCalculator> bindISemanticHighlightingCalculator() {
return SemanticHighlightingCalculator.class;
}
@@ -44,4 +45,28 @@ public Class extends ISemanticHighlightingCalculator> bindISemanticHighlightin
public Class extends IXtextBuilderParticipant> bindIXtextBuilderParticipant() {
return BuilderParticipant.class;
}
+
+ public Class extends IStepMatcher> bindIStepMatcher() {
+ return JavaAnnotationMatcher.class;
+ }
+
+ public final static String[] STEPS = { "Given", "When", "Then", "And", "But" };
+ private static final String CUCUMBER_PACKAGE = "io.cucumber.java.en";
+
+ public Class extends AbstractAnnotationDescriptor> bindAnnotationDescriptor() {
+ return CucumberAnnotationDescriptor.class;
+ }
+
+ public static class CucumberAnnotationDescriptor extends AbstractAnnotationDescriptor {
+
+ @Override
+ public String[] getNames() {
+ return STEPS;
+ }
+
+ @Override
+ public String getPackage() {
+ return CUCUMBER_PACKAGE;
+ }
+ }
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/contentassist/CucumberProposalProvider.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/contentassist/CucumberProposalProvider.java
index 98c8e4f7..66bfd366 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/contentassist/CucumberProposalProvider.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/contentassist/CucumberProposalProvider.java
@@ -5,8 +5,8 @@
import java.util.Collection;
-import org.agileware.natural.common.AbstractAnnotationDescriptor;
-import org.agileware.natural.common.JavaAnnotationMatcher;
+import org.agileware.natural.stepmatcher.ui.AbstractAnnotationDescriptor;
+import org.agileware.natural.stepmatcher.ui.JavaAnnotationMatcher;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.impl.RuleCallImpl;
@@ -16,28 +16,34 @@
import com.google.inject.Inject;
/**
- * see http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on how to customize content assistant
+ * see
+ * http://www.eclipse.org/Xtext/documentation/latest/xtext.html#contentAssist on
+ * how to customize content assistant
*/
public class CucumberProposalProvider extends AbstractCucumberProposalProvider {
@Inject
private JavaAnnotationMatcher matcher;
-
+
@Inject
private AbstractAnnotationDescriptor descriptor;
-
- public void complete_Step(EObject model, RuleCall ruleCall, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
- if (((RuleCallImpl)context.getLastCompleteNode().getGrammarElement()).getRule().getName().equals("EOL") && context.getPrefix().length() == 0) {
- for (String entry : descriptor.getNames()) {
+
+ @Override
+ public void complete_Step(final EObject model, final RuleCall ruleCall, final ContentAssistContext context,
+ final ICompletionProposalAcceptor acceptor) {
+ if (((RuleCallImpl) context.getLastCompleteNode().getGrammarElement()).getRule().getName().equals("NL")
+ && context.getPrefix().length() == 0) {
+ for (final String entry : descriptor.getNames()) {
acceptor.accept(createCompletionProposal(entry + " ", context));
}
}
}
-
- public void complete_StepDescription(EObject model, RuleCall ruleCall, ContentAssistContext context, ICompletionProposalAcceptor acceptor) {
- Collection proposals = matcher.findProposals();
+
+ public void complete_StepDescription(final EObject model, final RuleCall ruleCall,
+ final ContentAssistContext context, final ICompletionProposalAcceptor acceptor) {
+ final Collection proposals = matcher.findProposals();
for (String proposal : proposals) {
- String display = proposal;
+ final String display = proposal;
if (proposal.charAt(0) == '^') {
proposal = proposal.substring(1);
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/labeling/CucumberLabelProvider.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/labeling/CucumberLabelProvider.java
index 36f7ea31..7cd387b8 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/labeling/CucumberLabelProvider.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/labeling/CucumberLabelProvider.java
@@ -4,15 +4,15 @@
package org.agileware.natural.cucumber.ui.labeling;
import org.agileware.natural.cucumber.cucumber.Background;
-import org.agileware.natural.cucumber.cucumber.DocString;
import org.agileware.natural.cucumber.cucumber.Example;
import org.agileware.natural.cucumber.cucumber.Feature;
import org.agileware.natural.cucumber.cucumber.Scenario;
import org.agileware.natural.cucumber.cucumber.ScenarioOutline;
import org.agileware.natural.cucumber.cucumber.Step;
-import org.agileware.natural.cucumber.cucumber.Table;
-import org.agileware.natural.cucumber.cucumber.Tag;
-import org.eclipse.emf.common.util.EList;
+import org.agileware.natural.lang.model.DocString;
+import org.agileware.natural.lang.model.Meta;
+import org.agileware.natural.lang.model.MetaElement;
+import org.agileware.natural.lang.model.Table;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider;
@@ -20,92 +20,96 @@
/**
* Provides labels for a EObjects.
- *
+ *
* see
* http://www.eclipse.org/Xtext/documentation/latest/xtext.html#labelProvider
*/
public class CucumberLabelProvider extends DefaultEObjectLabelProvider {
@Inject
- public CucumberLabelProvider(AdapterFactoryLabelProvider delegate) {
+ public CucumberLabelProvider(final AdapterFactoryLabelProvider delegate) {
super(delegate);
}
-
- String text(Feature ele) {
- return ele.getTitle();
+
+ String text(final Feature ele) {
+ return ele.getTitle() == null ? "Feature" : merge("Feature: ", ele.getTitle());
}
- String image(Feature ele) {
+ String image(final Feature ele) {
return "feature.png";
}
- String text(Background ele) {
- return ele.getTitle() == null ? "Background" : ele.getTitle();
+ String text(final Background ele) {
+ return ele.getTitle() == null ? "Background" : merge("Background: ", ele.getTitle());
}
- String image(Background ele) {
+ String image(final Background ele) {
return "background.gif";
}
- String text(Scenario ele) {
- return ele.getTitle() == null ? "Scenario" : ele.getTitle();
+ String text(final Scenario ele) {
+ return ele.getTitle() == null ? "Scenario" : merge("Scenario: ", ele.getTitle());
}
- String image(Scenario ele) {
+ String image(final Scenario ele) {
return "scenario.png";
}
- String text(ScenarioOutline ele) {
- return ele.getTitle() == null ? "Scenario Outline" : ele.getTitle();
+ String text(final ScenarioOutline ele) {
+ return ele.getTitle() == null ? "Scenario Outline" : merge("Scenario Outline: ", ele.getTitle());
}
- String image(ScenarioOutline ele) {
+ String image(final ScenarioOutline ele) {
return "scenario_outline.png";
}
-
- String text(Step ele) {
- return ele.getDescription().trim();
+
+ String text(final Step ele) {
+ return ele.getDescription();
}
- String image(Step ele) {
+ String image(final Step ele) {
return "step.gif";
}
- String text(Table ele) {
+ String text(final Table ele) {
return "Table of " + ele.getRows().size() + " rows";
}
- String image(Table ele) {
+ String image(final Table ele) {
return "table.gif";
}
-
- String text(DocString ele) {
+
+ String text(final DocString ele) {
return "DocString";
}
- String image(DocString ele) {
+ String image(final DocString ele) {
return "code.gif";
}
- String text(Example ele) {
- return ele.getTitle().isEmpty() ? "Examples" : ele.getTitle();
+ String text(final Example ele) {
+ return ele.getTitle() == null ? "Examples" : merge("Examples: ", ele.getTitle());
}
- String image(Example ele) {
+ String image(final Example ele) {
return "example.gif";
}
- String text(Tag ele) {
- return ele.getId();
+ String text(final Meta ele) {
+ return "Meta";
}
- String image(Tag ele) {
+ String text(final MetaElement ele) {
+ return ele.getId().substring(1);
+ }
+
+ String image(final MetaElement ele) {
return "annotation.gif";
}
-
- private static String merge(EList strings) {
- StringBuilder builder = new StringBuilder();
- for (String string : strings) {
+
+ private static String merge(final String... strings) {
+ final StringBuilder builder = new StringBuilder();
+ for (final String string : strings) {
builder.append(string);
}
return builder.toString();
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/outline/CucumberOutlineTreeProvider.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/outline/CucumberOutlineTreeProvider.java
index 44d88c44..c2a3cc94 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/outline/CucumberOutlineTreeProvider.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/outline/CucumberOutlineTreeProvider.java
@@ -3,33 +3,79 @@
*/
package org.agileware.natural.cucumber.ui.outline;
-import org.agileware.natural.cucumber.cucumber.DocString;
+import org.agileware.natural.cucumber.cucumber.AbstractScenario;
+import org.agileware.natural.cucumber.cucumber.CucumberModel;
+import org.agileware.natural.cucumber.cucumber.Example;
+import org.agileware.natural.cucumber.cucumber.Feature;
+import org.agileware.natural.cucumber.cucumber.ScenarioOutline;
import org.agileware.natural.cucumber.cucumber.Step;
-import org.agileware.natural.cucumber.cucumber.Table;
-import org.agileware.natural.cucumber.cucumber.Text;
+import org.agileware.natural.lang.model.DocString;
+import org.agileware.natural.lang.model.Narrative;
+import org.agileware.natural.lang.model.Table;
import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider;
+import org.eclipse.xtext.ui.editor.outline.impl.DocumentRootNode;
/**
* customization of the default outline structure
- *
+ *
*/
public class CucumberOutlineTreeProvider extends DefaultOutlineTreeProvider {
-
- protected boolean _isLeaf(DocString modelElement) {
+
+ protected void _createChildren(final DocumentRootNode parentNode, final CucumberModel model) {
+ if (model.getDocument() != null) {
+ createNode(parentNode, model.getDocument());
+ }
+ }
+
+ protected void _createChildren(final DocumentRootNode parentNode, final Feature model) {
+ if (model.getMeta() != null) {
+ createNode(parentNode, model.getMeta());
+ }
+
+ for (final AbstractScenario scenario : model.getScenarios()) {
+ createNode(parentNode, scenario);
+ }
+ }
+
+ protected void _createChildren(final DocumentRootNode parentNode, final AbstractScenario model) {
+ if (model.getMeta() != null) {
+ createNode(parentNode, model.getMeta());
+ }
+
+ for (final Step step : model.getSteps()) {
+ createNode(parentNode, step);
+ }
+ }
+
+ protected void _createChildren(final DocumentRootNode parentNode, final ScenarioOutline model) {
+ if (model.getMeta() != null) {
+ createNode(parentNode, model.getMeta());
+ }
+
+ for (final Step step : model.getSteps()) {
+ createNode(parentNode, step);
+ }
+
+ for (final Example step : model.getExamples()) {
+ createNode(parentNode, step);
+ }
+ }
+
+ protected boolean _isLeaf(final Narrative modelElement) {
return true;
}
-
- protected boolean _isLeaf(Text modelElement) {
+
+ protected boolean _isLeaf(final DocString modelElement) {
return true;
}
-
- protected boolean _isLeaf(Table modelElement) {
+
+ protected boolean _isLeaf(final Table modelElement) {
// do not allow expansion of table nodes
return true;
}
-
- protected boolean _isLeaf(Step modelElement) {
+
+ protected boolean _isLeaf(final Step modelElement) {
// only allow expansion of step nodes with tables
- return modelElement.getTable() == null && modelElement.getCode() == null;
+ return modelElement.getTable() == null && modelElement.getText() == null;
}
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/HighlightingConfiguration.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/HighlightingConfiguration.java
index 29154a3f..5f2154f5 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/HighlightingConfiguration.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/HighlightingConfiguration.java
@@ -2,85 +2,56 @@
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.RGB;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfiguration;
+import org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightingConfigurationAcceptor;
import org.eclipse.xtext.ui.editor.utils.TextStyle;
-public class HighlightingConfiguration implements IHighlightingConfiguration {
+public class HighlightingConfiguration extends DefaultHighlightingConfiguration {
- public static final String STEP_KEYWORD = "stepCondition";
- public static final String TAG = "tag";
- public static final String TABLE = "table";
- public static final String PLACEHOLDER = "placeholder";
- public static final String DOC_STRING = "docstring";
- public static final String KEYWORD_ID = "keyword";
- public static final String COMMENT_ID = "comment";
- public static final String STRING_ID = "string";
- public static final String NUMBER_ID = "number";
- public static final String DEFAULT_ID = "default";
- public static final String INVALID_TOKEN_ID = "error";
+ public static final String TAG_ID = "tag";
+ public static final String TABLE_ID = "table";
+
+ public static final String PLACEHOLDER_ID = "placeholder";
+
+ public static final String DOC_STRING_ID = "docstring";
+
+ @Override
public void configure(IHighlightingConfigurationAcceptor acceptor) {
- acceptor.acceptDefaultHighlighting(KEYWORD_ID, "Keyword", keywordTextStyle());
- acceptor.acceptDefaultHighlighting(COMMENT_ID, "Comment", commentTextStyle());
- acceptor.acceptDefaultHighlighting(STRING_ID, "String", stringTextStyle());
- acceptor.acceptDefaultHighlighting(NUMBER_ID, "Number", numberTextStyle());
- acceptor.acceptDefaultHighlighting(DEFAULT_ID, "Default", defaultTextStyle());
- acceptor.acceptDefaultHighlighting(INVALID_TOKEN_ID, "Invalid Symbol", errorTextStyle());
- // Gherkin
- acceptor.acceptDefaultHighlighting(STEP_KEYWORD, "Step Condition", stepKeywordTextStyle());
- acceptor.acceptDefaultHighlighting(TAG, "Tag", tagTextStyle());
- acceptor.acceptDefaultHighlighting(TABLE, "Table", numberTextStyle());
- acceptor.acceptDefaultHighlighting(PLACEHOLDER, "Placeholder", tagTextStyle());
- acceptor.acceptDefaultHighlighting(DOC_STRING, "Doc String", numberTextStyle());
- }
+ acceptor.acceptDefaultHighlighting(TAG_ID, "Tag", tagTextStyle());
+ acceptor.acceptDefaultHighlighting(TABLE_ID, "Table", tableTextStyle());
+ acceptor.acceptDefaultHighlighting(PLACEHOLDER_ID, "Placeholder", placeholderTextStyle());
+ acceptor.acceptDefaultHighlighting(DOC_STRING_ID, "DocString", docStringTextStyle());
- public static TextStyle defaultTextStyle() {
- TextStyle textStyle = new TextStyle();
- // textStyle.setBackgroundColor(new RGB(255, 255, 255));
- textStyle.setColor(new RGB(0, 0, 0));
- return textStyle;
+ super.configure(acceptor);
}
- public static TextStyle errorTextStyle() {
- TextStyle textStyle = defaultTextStyle().copy();
- // textStyle.setColor(new RGB(255, 0, 0));
+ @Override
+ public TextStyle numberTextStyle() {
+ TextStyle textStyle = stringTextStyle().copy();
return textStyle;
}
-
- public static TextStyle numberTextStyle() {
- TextStyle textStyle = defaultTextStyle().copy();
- textStyle.setColor(new RGB(125, 125, 125));
+
+ public TextStyle placeholderTextStyle() {
+ TextStyle textStyle = stringTextStyle().copy();
return textStyle;
}
-
- public static TextStyle stringTextStyle() {
+
+ public TextStyle docStringTextStyle() {
TextStyle textStyle = defaultTextStyle().copy();
- textStyle.setColor(new RGB(42, 0, 255));
+ textStyle.setColor(new RGB(125, 125, 125));
return textStyle;
}
- public static TextStyle commentTextStyle() {
+ public TextStyle tableTextStyle() {
TextStyle textStyle = defaultTextStyle().copy();
- textStyle.setColor(new RGB(63, 127, 95));
+ textStyle.setColor(new RGB(125, 125, 125));
return textStyle;
}
- public static TextStyle keywordTextStyle() {
+ public TextStyle tagTextStyle() {
TextStyle textStyle = defaultTextStyle().copy();
- textStyle.setColor(new RGB(127, 0, 85));
- textStyle.setStyle(SWT.BOLD);
- return textStyle;
- }
-
- public static TextStyle stepKeywordTextStyle() {
- TextStyle textStyle = keywordTextStyle();
- textStyle.setStyle(SWT.ITALIC);
- return textStyle;
- }
-
- public static TextStyle tagTextStyle() {
- TextStyle textStyle = numberTextStyle();
+ textStyle.setColor(new RGB(125, 125, 125));
textStyle.setStyle(SWT.ITALIC);
return textStyle;
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/LexicalHighlightingCalculator.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/LexicalHighlightingCalculator.java
index 9e726295..45c44a9d 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/LexicalHighlightingCalculator.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/LexicalHighlightingCalculator.java
@@ -2,38 +2,46 @@
import java.util.regex.Pattern;
+import org.eclipse.xtext.ide.editor.syntaxcoloring.HighlightingStyles;
import org.eclipse.xtext.ui.editor.syntaxcoloring.AbstractAntlrTokenToAttributeIdMapper;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.DefaultHighlightingConfiguration;
-public class LexicalHighlightingCalculator extends
- AbstractAntlrTokenToAttributeIdMapper {
+public class LexicalHighlightingCalculator extends AbstractAntlrTokenToAttributeIdMapper {
private static final Pattern QUOTED = Pattern.compile("(?:^'([^']*)'$)|(?:^\"([^\"]*)\")$", Pattern.MULTILINE);
-
+
@Override
- protected String calculateId(String tokenName, int tokenType) {
- if(QUOTED.matcher(tokenName).matches()) {
- return DefaultHighlightingConfiguration.KEYWORD_ID;
+ protected String calculateId(final String tokenName, final int tokenType) {
+ if ("'|'".equals(tokenName)) {
+ return HighlightingConfiguration.TABLE_ID;
}
- if("RULE_STRING".equals(tokenName)) {
- return DefaultHighlightingConfiguration.STRING_ID;
+ if (QUOTED.matcher(tokenName).matches()) {
+ return HighlightingStyles.KEYWORD_ID;
}
- if("RULE_INT".equals(tokenName)) {
- return DefaultHighlightingConfiguration.NUMBER_ID;
+ if ("RULE_STRING".equals(tokenName)) {
+ return HighlightingStyles.STRING_ID;
}
- if("RULE_SL_COMMENT".equals(tokenName)) {
- return DefaultHighlightingConfiguration.COMMENT_ID;
+ if ("RULE_NUMBER".equals(tokenName)) {
+ return HighlightingStyles.NUMBER_ID;
}
- if("RULE_TAGNAME".equals(tokenName)) {
- return HighlightingConfiguration.TAG;
+ if ("RULE_SL_COMMENT".equals(tokenName)) {
+ return HighlightingStyles.COMMENT_ID;
}
- if("RULE_DOC_STRING".equals(tokenName)) {
- return HighlightingConfiguration.DOC_STRING;
+ if ("RULE_TAG".equals(tokenName)) {
+ return HighlightingConfiguration.TAG_ID;
}
- if("RULE_TABLE_ROW".equals(tokenName)) {
- return HighlightingConfiguration.TABLE;
+ if ("RULE_DOC_STRING_LITERAL".equals(tokenName)) {
+ return HighlightingConfiguration.DOC_STRING_ID;
+ }
+ if ("RULE_TABLE_CELL".equals(tokenName)) {
+ return HighlightingConfiguration.TABLE_ID;
+ }
+ if ("RULE_STEP_KEYWORD".equals(tokenName)) {
+ return HighlightingStyles.KEYWORD_ID;
+ }
+ if ("RULE_PLACEHOLDER".equals(tokenName)) {
+ return HighlightingConfiguration.PLACEHOLDER_ID;
}
- return DefaultHighlightingConfiguration.DEFAULT_ID;
- }
+ return HighlightingStyles.DEFAULT_ID;
+ }
}
diff --git a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/SemanticHighlightingCalculator.java b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/SemanticHighlightingCalculator.java
index 78d84bad..2ab7408c 100644
--- a/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/SemanticHighlightingCalculator.java
+++ b/org.agileware.natural.cucumber.ui/src/org/agileware/natural/cucumber/ui/syntaxcoloring/SemanticHighlightingCalculator.java
@@ -1,58 +1,91 @@
package org.agileware.natural.cucumber.ui.syntaxcoloring;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.ABSTRACT_SCENARIO__TITLE;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.EXAMPLE__TITLE;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.FEATURE__TITLE;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.STEP__DESCRIPTION;
+import static org.eclipse.xtext.nodemodel.util.NodeModelUtils.findNodesForFeature;
+
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.agileware.natural.cucumber.cucumber.AbstractScenario;
+import org.agileware.natural.cucumber.cucumber.CucumberModel;
+import org.agileware.natural.cucumber.cucumber.Example;
import org.agileware.natural.cucumber.cucumber.Feature;
-import org.agileware.natural.cucumber.cucumber.Scenario;
import org.agileware.natural.cucumber.cucumber.ScenarioOutline;
import org.agileware.natural.cucumber.cucumber.Step;
-import org.eclipse.emf.common.util.EList;
-import org.eclipse.xtext.nodemodel.INode;
-import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor;
+import org.eclipse.xtext.ide.editor.syntaxcoloring.ISemanticHighlightingCalculator;
+import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.resource.XtextResource;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightedPositionAcceptor;
-import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;
+import org.eclipse.xtext.util.CancelIndicator;
public class SemanticHighlightingCalculator implements ISemanticHighlightingCalculator {
-
- public void provideHighlightingFor(XtextResource resource, IHighlightedPositionAcceptor acceptor) {
- if (resource == null || resource.getParseResult() == null || resource.getContents().size() <= 0) {
+
+ private static final Pattern NUMBER_PATTERN = Pattern.compile("(0)|([1-9][0-9]*)|(0x[0-9a-fA-F]+)");
+
+ private static Stream allLeafNodesFor(final EObject semanticObject,
+ final EStructuralFeature structuralFeature) {
+ return findNodesForFeature(semanticObject, structuralFeature)
+ .stream()
+ .flatMap(n -> StreamSupport.stream(n.getLeafNodes().spliterator(), false))
+ .filter(n -> !n.isHidden());
+ }
+
+ @Override
+ public void provideHighlightingFor(final XtextResource resource, final IHighlightedPositionAcceptor acceptor,
+ CancelIndicator cancelIndicator) {
+ if (resource == null || resource.getParseResult() == null || resource.getContents().size() <= 0
+ || cancelIndicator.isCanceled()) {
return;
}
- Feature feature = (Feature) resource.getContents().get(0);
- if (feature.getBackground() != null) {
- provideHighlightingForSteps(feature.getBackground().getSteps(), acceptor);
+
+ final CucumberModel model = (CucumberModel) resource.getContents().get(0);
+ if (model.getDocument() != null) {
+ provideHighlightingFor(model.getDocument(), acceptor);
}
- for (Object child : feature.getScenarios()) {
- if (child instanceof Scenario) {
- Scenario scenario = (Scenario) child;
- provideHighlightingForSteps(scenario.getSteps(), acceptor);
- }
- if (child instanceof ScenarioOutline) {
- ScenarioOutline outline = (ScenarioOutline) child;
- provideHighlightingForSteps(outline.getSteps(), acceptor);
- }
+ }
+
+ private void provideHighlightingFor(final Feature feature, final IHighlightedPositionAcceptor acceptor) {
+ provideHighlightingForTextLiterals(allLeafNodesFor(feature, FEATURE__TITLE), acceptor);
+ for (final AbstractScenario scenario : feature.getScenarios()) {
+ provideHighlightingFor(scenario, acceptor);
}
}
- private void provideHighlightingForSteps(EList steps, IHighlightedPositionAcceptor acceptor) {
- for (Step step : steps) {
- INode node = NodeModelUtils.getNode(step);
- acceptor.addPosition(
- node.getOffset(),
- node.getText().trim().indexOf(" "),
- HighlightingConfiguration.STEP_KEYWORD);
- if (step.eContainer() instanceof ScenarioOutline && step.getDescription() != null) {
- this.provideHighlightingForPlaceholders(node.getText(), node, 0, acceptor);
+ private void provideHighlightingFor(final AbstractScenario scenario, final IHighlightedPositionAcceptor acceptor) {
+ provideHighlightingForTextLiterals(allLeafNodesFor(scenario, ABSTRACT_SCENARIO__TITLE), acceptor);
+ for (final Step step : scenario.getSteps()) {
+ provideHighlightingFor(step, acceptor);
+ if (scenario instanceof ScenarioOutline) {
+ for (final Example example : ((ScenarioOutline) scenario).getExamples()) {
+ provideHighlightingFor(example, acceptor);
+ }
}
}
}
- private void provideHighlightingForPlaceholders(String description, INode node, int current, IHighlightedPositionAcceptor acceptor) {
- int start = description.indexOf('<', current);
- int stop = description.indexOf('>', start);
- if (start > 0 && stop > 0 && description.charAt(start + 1) != ' ') {
- acceptor.addPosition(node.getTotalOffset() + start, stop - start + 1, HighlightingConfiguration.PLACEHOLDER);
- this.provideHighlightingForPlaceholders(description, node, stop + 1, acceptor);
- }
+ private void provideHighlightingFor(final Example example, final IHighlightedPositionAcceptor acceptor) {
+ provideHighlightingForTextLiterals(allLeafNodesFor(example, EXAMPLE__TITLE), acceptor);
}
+ private void provideHighlightingFor(final Step step, final IHighlightedPositionAcceptor acceptor) {
+ provideHighlightingForTextLiterals(allLeafNodesFor(step, STEP__DESCRIPTION), acceptor);
+ }
+
+ private void provideHighlightingForTextLiterals(final Stream leafNodes,
+ final IHighlightedPositionAcceptor acceptor) {
+ leafNodes.forEach(node -> {
+ // Temporary work around for LexicalHighlighter failing to flag certain numbers
+ // forms
+ if (NUMBER_PATTERN.matcher(node.getText()).matches()) {
+ acceptor.addPosition(node.getOffset(), node.getLength(),
+ HighlightingConfiguration.NUMBER_ID);
+ }
+ });
+ }
}
diff --git a/org.agileware.natural.cucumber.web/.settings/org.eclipse.wst.common.component b/org.agileware.natural.cucumber.web/.settings/org.eclipse.wst.common.component
index 24bc4761..4f85fa10 100644
--- a/org.agileware.natural.cucumber.web/.settings/org.eclipse.wst.common.component
+++ b/org.agileware.natural.cucumber.web/.settings/org.eclipse.wst.common.component
@@ -1,40 +1,46 @@
-
+
+
-
+
+
-
+
+
-
+
+
-
+
+
-
+
+
@@ -47,28 +53,32 @@
uses
-
+
+
-
+
+
-
+
+
-
+
+
diff --git a/org.agileware.natural.cucumber.web/WebRoot/xtext-resources/generated/mode-feature.js b/org.agileware.natural.cucumber.web/WebRoot/xtext-resources/generated/mode-feature.js
index 640527bf..ca984bfb 100644
--- a/org.agileware.natural.cucumber.web/WebRoot/xtext-resources/generated/mode-feature.js
+++ b/org.agileware.natural.cucumber.web/WebRoot/xtext-resources/generated/mode-feature.js
@@ -1,10 +1,6 @@
define(["ace/lib/oop", "ace/mode/text", "ace/mode/text_highlight_rules"], function(oop, mText, mTextHighlightRules) {
var HighlightRules = function() {
- var keywords = "Scenario";
this.$rules = {
- "start": [
- {token: "keyword", regex: "\\b(?:" + keywords + ")\\b"}
- ]
};
};
oop.inherits(HighlightRules, mTextHighlightRules.TextHighlightRules);
diff --git a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.java b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.java
new file mode 100644
index 00000000..d6de568c
--- /dev/null
+++ b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.java
@@ -0,0 +1,34 @@
+/*
+ * generated by Xtext 2.22.0
+ */
+package org.agileware.natural.cucumber.web;
+
+import com.google.inject.Injector;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import org.eclipse.xtext.util.DisposableRegistry;
+import org.eclipse.xtext.web.servlet.XtextServlet;
+
+/**
+ * Deploy this class into a servlet container to enable DSL-specific services.
+ */
+@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*")
+public class CucumberServlet extends XtextServlet {
+
+ DisposableRegistry disposableRegistry;
+
+ public void init() throws ServletException {
+ super.init();
+ Injector injector = new CucumberWebSetup().createInjectorAndDoEMFRegistration();
+ this.disposableRegistry = injector.getInstance(DisposableRegistry.class);
+ }
+
+ public void destroy() {
+ if (disposableRegistry != null) {
+ disposableRegistry.dispose();
+ disposableRegistry = null;
+ }
+ super.destroy();
+ }
+
+}
diff --git a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.xtend b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.xtend
deleted file mode 100644
index 24c50dd9..00000000
--- a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/CucumberServlet.xtend
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * generated by Xtext 2.21.0
- */
-package org.agileware.natural.cucumber.web
-
-import javax.servlet.annotation.WebServlet
-import org.eclipse.xtext.util.DisposableRegistry
-import org.eclipse.xtext.web.servlet.XtextServlet
-
-/**
- * Deploy this class into a servlet container to enable DSL-specific services.
- */
-@WebServlet(name = 'XtextServices', urlPatterns = '/xtext-service/*')
-class CucumberServlet extends XtextServlet {
-
- DisposableRegistry disposableRegistry
-
- override init() {
- super.init()
- val injector = new CucumberWebSetup().createInjectorAndDoEMFRegistration()
- disposableRegistry = injector.getInstance(DisposableRegistry)
- }
-
- override destroy() {
- if (disposableRegistry !== null) {
- disposableRegistry.dispose()
- disposableRegistry = null
- }
- super.destroy()
- }
-
-}
diff --git a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.java b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.java
new file mode 100644
index 00000000..b101be14
--- /dev/null
+++ b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.java
@@ -0,0 +1,65 @@
+/*
+ * generated by Xtext 2.22.0
+ */
+package org.agileware.natural.cucumber.web;
+
+import java.net.InetSocketAddress;
+import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.log.Slf4jLog;
+import org.eclipse.jetty.webapp.Configuration;
+import org.eclipse.jetty.webapp.MetaInfConfiguration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.WebInfConfiguration;
+import org.eclipse.jetty.webapp.WebXmlConfiguration;
+
+/**
+ * This program starts an HTTP server for testing the web integration of your DSL.
+ * Just execute it and point a web browser to http://localhost:8080/
+ */
+public class ServerLauncher {
+ public static void main(String[] args) {
+ Server server = new Server(new InetSocketAddress("localhost", 8080));
+ WebAppContext ctx = new WebAppContext();
+ ctx.setResourceBase("WebRoot");
+ ctx.setWelcomeFiles(new String[] {"index.html"});
+ ctx.setContextPath("/");
+ ctx.setConfigurations(new Configuration[] {
+ new AnnotationConfiguration(),
+ new WebXmlConfiguration(),
+ new WebInfConfiguration(),
+ new MetaInfConfiguration()
+ });
+ ctx.setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN,
+ ".*/org\\.agileware\\.natural\\.cucumber\\.web/.*,.*\\.jar");
+ ctx.setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+ server.setHandler(ctx);
+ Slf4jLog log = new Slf4jLog(ServerLauncher.class.getName());
+ try {
+ server.start();
+ log.info("Server started " + server.getURI() + "...");
+ new Thread() {
+
+ public void run() {
+ try {
+ log.info("Press enter to stop the server...");
+ int key = System.in.read();
+ if (key != -1) {
+ server.stop();
+ } else {
+ log.warn(
+ "Console input is not available. In order to stop the server, you need to cancel process manually.");
+ }
+ } catch (Exception e) {
+ log.warn(e);
+ }
+ }
+
+ }.start();
+ server.join();
+ } catch (Exception exception) {
+ log.warn(exception.getMessage());
+ System.exit(1);
+ }
+ }
+}
diff --git a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.xtend b/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.xtend
deleted file mode 100644
index 3ef81055..00000000
--- a/org.agileware.natural.cucumber.web/src/org/agileware/natural/cucumber/web/ServerLauncher.xtend
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * generated by Xtext 2.21.0
- */
-package org.agileware.natural.cucumber.web
-
-import java.net.InetSocketAddress
-import org.eclipse.jetty.annotations.AnnotationConfiguration
-import org.eclipse.jetty.server.Server
-import org.eclipse.jetty.util.log.Slf4jLog
-import org.eclipse.jetty.webapp.MetaInfConfiguration
-import org.eclipse.jetty.webapp.WebAppContext
-import org.eclipse.jetty.webapp.WebInfConfiguration
-import org.eclipse.jetty.webapp.WebXmlConfiguration
-
-/**
- * This program starts an HTTP server for testing the web integration of your DSL.
- * Just execute it and point a web browser to http://localhost:8080/
- */
-class ServerLauncher {
- def static void main(String[] args) {
- val server = new Server(new InetSocketAddress('localhost', 8080))
- server.handler = new WebAppContext => [
- resourceBase = 'WebRoot'
- welcomeFiles = #["index.html"]
- contextPath = "/"
- configurations = #[
- new AnnotationConfiguration,
- new WebXmlConfiguration,
- new WebInfConfiguration,
- new MetaInfConfiguration
- ]
- setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, '.*/org\\.agileware\\.natural\\.cucumber\\.web/.*,.*\\.jar')
- setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false")
- ]
- val log = new Slf4jLog(ServerLauncher.name)
- try {
- server.start
- log.info('Server started ' + server.getURI + '...')
- new Thread[
- log.info('Press enter to stop the server...')
- val key = System.in.read
- if (key != -1) {
- server.stop
- } else {
- log.warn('Console input is not available. In order to stop the server, you need to cancel process manually.')
- }
- ].start
- server.join
- } catch (Exception exception) {
- log.warn(exception.message)
- System.exit(1)
- }
- }
-}
diff --git a/org.agileware.natural.cucumber/META-INF/MANIFEST.MF b/org.agileware.natural.cucumber/META-INF/MANIFEST.MF
index a09a64d4..37a452f0 100644
--- a/org.agileware.natural.cucumber/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.cucumber/META-INF/MANIFEST.MF
@@ -6,7 +6,8 @@ Bundle-Vendor: Roberto Lo Giacco
Bundle-Version: 1.0.0.qualifier
Bundle-SymbolicName: org.agileware.natural.cucumber; singleton:=true
Bundle-ActivationPolicy: lazy
-Require-Bundle: org.agileware.natural.common;visibility:=reexport,
+Require-Bundle: org.agileware.natural.stepmatcher;visibility:=reexport,
+ org.agileware.natural.lang;visibility:=reexport,
org.eclipse.xtext,
org.eclipse.xtext.xbase,
org.eclipse.equinox.common;bundle-version="3.5.0",
@@ -18,11 +19,12 @@ Require-Bundle: org.agileware.natural.common;visibility:=reexport,
org.antlr.runtime;bundle-version="[3.2.0,3.2.1)"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: org.agileware.natural.cucumber;uses:="com.google.inject,org.eclipse.xtext.service,org.eclipse.xtext",
- org.agileware.natural.cucumber.cucumber;uses:="org.eclipse.emf.ecore,org.eclipse.emf.common.util",
+ org.agileware.natural.cucumber.cucumber;uses:="org.eclipse.emf.ecore,org.eclipse.emf.common.util,org.agileware.natural.lang.model",
org.agileware.natural.cucumber.cucumber.impl;
uses:="org.eclipse.emf.ecore,
org.eclipse.emf.ecore.impl,
org.eclipse.emf.common.util,
+ org.agileware.natural.lang.model,
org.eclipse.emf.common.notify,
org.agileware.natural.cucumber.cucumber",
org.agileware.natural.cucumber.cucumber.util;
@@ -31,7 +33,11 @@ Export-Package: org.agileware.natural.cucumber;uses:="com.google.inject,org.ecli
org.eclipse.emf.common.notify.impl,
org.eclipse.emf.ecore.util,
org.agileware.natural.cucumber.cucumber",
- org.agileware.natural.cucumber.formatting2;uses:="org.eclipse.xtext.formatting2,org.agileware.natural.cucumber.cucumber",
+ org.agileware.natural.cucumber.formatting2;
+ uses:="org.agileware.natural.lang.model,
+ org.eclipse.xtext.formatting2.regionaccess,
+ org.eclipse.xtext.formatting2,
+ org.agileware.natural.cucumber.cucumber",
org.agileware.natural.cucumber.generator;uses:="org.eclipse.xtext.generator,org.eclipse.emf.ecore.resource",
org.agileware.natural.cucumber.parser.antlr;uses:="org.eclipse.xtext.parser.antlr,org.agileware.natural.cucumber.parser.antlr.internal,org.agileware.natural.cucumber.services",
org.agileware.natural.cucumber.parser.antlr.internal;
@@ -39,8 +45,8 @@ Export-Package: org.agileware.natural.cucumber;uses:="com.google.inject,org.ecli
org.eclipse.xtext.parser.antlr,
org.antlr.runtime,
org.agileware.natural.cucumber.services",
- org.agileware.natural.cucumber.scoping;uses:="org.eclipse.xtext.scoping.impl",
+ org.agileware.natural.cucumber.scoping;uses:="org.agileware.natural.lang.scoping",
org.agileware.natural.cucumber.serializer;uses:="org.agileware.natural.cucumber.cucumber",
- org.agileware.natural.cucumber.services;uses:="org.eclipse.xtext.service,org.eclipse.xtext",
- org.agileware.natural.cucumber.validation;uses:="org.eclipse.xtext.util,org.eclipse.xtext.validation"
+ org.agileware.natural.cucumber.services;uses:="org.agileware.natural.lang.services,org.eclipse.xtext.service,org.eclipse.xtext",
+ org.agileware.natural.cucumber.validation;uses:="org.agileware.natural.lang.validation,org.eclipse.xtext.util,org.eclipse.xtext.validation"
Import-Package: org.apache.log4j
diff --git a/org.agileware.natural.cucumber/README.md b/org.agileware.natural.cucumber/README.md
index 21bbd4c2..4f34bef6 100644
--- a/org.agileware.natural.cucumber/README.md
+++ b/org.agileware.natural.cucumber/README.md
@@ -2,4 +2,4 @@
Xtext language model for Cucumber editor
-![Cucumber AST](model/Cucumber.jpg)
\ No newline at end of file
+![Cucumber AST](cucumber.model.jpg)
\ No newline at end of file
diff --git a/org.agileware.natural.cucumber/cucumber.model.jpg b/org.agileware.natural.cucumber/cucumber.model.jpg
new file mode 100644
index 00000000..64f8fd8e
Binary files /dev/null and b/org.agileware.natural.cucumber/cucumber.model.jpg differ
diff --git a/org.agileware.natural.cucumber/model/Cucumber.jpg b/org.agileware.natural.cucumber/model/Cucumber.jpg
deleted file mode 100644
index ca56bbc0..00000000
Binary files a/org.agileware.natural.cucumber/model/Cucumber.jpg and /dev/null differ
diff --git a/org.agileware.natural.cucumber/model/generated/Cucumber.ecore b/org.agileware.natural.cucumber/model/generated/Cucumber.ecore
index 8001475b..c74753f4 100644
--- a/org.agileware.natural.cucumber/model/generated/Cucumber.ecore
+++ b/org.agileware.natural.cucumber/model/generated/Cucumber.ecore
@@ -2,23 +2,29 @@
-
-
+
+
+
+
+
+
-
-
-
-
-
+
-
+
+
-
+
-
-
-
-
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/org.agileware.natural.cucumber/model/generated/Cucumber.genmodel b/org.agileware.natural.cucumber/model/generated/Cucumber.genmodel
index fe8495cd..3cd12b86 100644
--- a/org.agileware.natural.cucumber/model/generated/Cucumber.genmodel
+++ b/org.agileware.natural.cucumber/model/generated/Cucumber.genmodel
@@ -1,23 +1,26 @@
+ complianceLevel="8.0" copyrightFields="false" runtimeVersion="2.20" usedGenPackages="platform:/resource/org.agileware.natural.lang/model/generated/Natural.genmodel#//model">
+
+
+
-
+
+
+
+
+
+
-
-
-
-
-
@@ -27,31 +30,13 @@
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/org.agileware.natural.cucumber/model/representations.aird b/org.agileware.natural.cucumber/model/representations.aird
index 26b3a5ef..af85fc22 100644
--- a/org.agileware.natural.cucumber/model/representations.aird
+++ b/org.agileware.natural.cucumber/model/representations.aird
@@ -2,996 +2,558 @@
generated/Cucumber.ecore
+ platform:/resource/org.agileware.natural.lang/model/generated/Natural.ecore
-
+
-
-
-
-
+
+
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
+
+
+
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
-
-
-
-
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
-
-
-
-
-
-
-
-
-
+
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
+
+
+
-
+
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
-
-
-
-
-
+
KEEP_LOCATION
KEEP_SIZE
KEEP_RATIO
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- labelSize
- labelColor
-
-
- labelSize
- labelColor
-
-
-
-
-
-
-
-
-
+
+
+
+
+
labelSize
- labelColor
-
+
labelSize
- labelColor
-
+
-
-
+
+
labelSize
- labelColor
-
+
labelSize
- labelColor
-
+
-
-
+
+
labelSize
- labelColor
-
+
labelSize
- labelColor
-
+
-
-
- labelSize
- labelColor
-
-
- labelSize
- labelColor
-
-
-
-
-
-
-
-
-
- labelColor
+
+
labelSize
-
- labelColor
+
labelSize
-
-
-
-
-
- labelSize
- labelColor
-
-
- labelSize
- labelColor
-
-
-
-
-
-
-
-
-
- labelSize
- labelColor
-
-
- labelSize
- labelColor
-
-
-
-
-
-
-
-
-
-
- italic
-
-
-
-
-
-
-
-
-
-
-
- italic
-
-
-
-
-
-
+
-
+
-
+
italic
-
+
-
-
-
-
-
-
- italic
-
-
-
-
-
-
-
-
-
-
-
- italic
-
-
-
-
-
-
+
-
+
-
+
italic
-
+
-
-
-
-
+
+
+
+
-
+
italic
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
-
-
-
-
-
-
-
-
-
- labelColor
- labelSize
-
-
- labelColor
- labelSize
-
-
-
-
-
-
-
-
-
- labelColor
- labelSize
-
-
- labelColor
- labelSize
-
-
-
-
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
-
-
-
-
-
-
-
-
-
- labelColor
- labelSize
-
-
- labelColor
- labelSize
-
-
-
-
-
-
-
- KEEP_LOCATION
- KEEP_SIZE
- KEEP_RATIO
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- labelColor
- labelSize
-
-
- labelColor
- labelSize
-
-
-
-
-
+
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/Cucumber.xtext b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/Cucumber.xtext
index 02884ccb..eb0729ac 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/Cucumber.xtext
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/Cucumber.xtext
@@ -1,201 +1,117 @@
-grammar org.agileware.natural.cucumber.Cucumber hidden(WS, SL_COMMENT)
+grammar org.agileware.natural.cucumber.Cucumber with org.agileware.natural.lang.Natural
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate cucumber "http://www.agileware.org/natural/cucumber"
-Feature:
- tags+=Tag*
- 'Feature:'
- title=Title EOL+
- narrative=Narrative?
- background=Background?
- scenarios+=AbstractScenario+
+/**
+ *
+ */
+CucumberModel: {CucumberModel}
+ BLANK_SPACE?
+ document=Feature?
+;
+
+/**
+ *
+ */
+Feature: {Feature}
+ (meta=Meta BLANK_SPACE?)?
+ 'Feature:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+ (BLANK_SPACE? scenarios+=AbstractScenario)*
+ BLANK_SPACE?
;
/**
* Base class for Scenario implementations.
- * A Scenario is any type with the following structure:
+ * An AbstractScenario is any type with the following structure:
*
- * tags+=Tag*
- * 'Scenario:'
- * title=Title? EOL+
+ * meta=Meta?
+ * 'Keyword:' title=Title? NL
* narrative=Narrative?
- * steps+=Step+;
+ * steps+=Step*
*/
AbstractScenario: Scenario
| ScenarioOutline
| Background
;
-
/**
- * A Section is a generic element with the structure:
*
- * tags+=Tag*
- * 'Keyword:'
- * title=Title? EOL+
- * narrative=Narrative?
*/
-Section: Feature
- | Background
- | AbstractScenario
- | Example
-;
-
-Background:
- tags+=Tag*
- 'Background:'
- title=Title? EOL+
- narrative=Narrative?
- steps+=Step+
-;
-
-Scenario:
- tags+=Tag*
- 'Scenario:'
- title=Title? EOL+
- narrative=Narrative?
- steps+=Step+
-;
-
-ScenarioOutline:
- tags+=Tag*
- 'Scenario' 'Outline:'
- title=Title? EOL+
- narrative=Narrative?
- steps+=Step+
- examples+=Example+
-;
-
-Step:
- keyword=STEP_KEYWORD
- description=StepDescription EOL*
- (table=Table | code=DocString)?
-;
-
-Example:
- tags+=Tag*
- 'Examples:'
- title=Title? EOL+
- narrative=Narrative?
- table=Table
-;
-
-
-Table: {Table}
- rows+=TableRow+
- EOL*
+Background: {Background}
+ (meta=Meta BLANK_SPACE?)?
+ 'Background:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+ (BLANK_SPACE? steps+=Step)*
;
-TableRow: {TableRow}
- cols+=TableCol+ '|' EOL
-;
-
-TableCol: {TableCol}
- cell=TABLE_CELL
-;
-
-DocString: {DocString}
- ('"""' EOL -> text=Text '"""')
- // TODO alternate quote support in formatter
- // | ("'''" EOL -> text=Text? "'''")
- EOL*
+/**
+ *
+ */
+Scenario: {Scenario}
+ (meta=Meta BLANK_SPACE?)?
+ 'Scenario:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+ (BLANK_SPACE? steps+=Step)*
;
-Title:
- (WORD | INT | STRING | PLACEHOLDER)
- (WORD | INT | STRING | PLACEHOLDER | STEP_KEYWORD | TAGNAME)*
+/**
+ *
+ */
+ScenarioOutline: {ScenarioOutline}
+ (meta=Meta BLANK_SPACE?)?
+ // note: Do not fix keyword warning (replace with terminal ok)
+ 'Scenario Outline:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+ (BLANK_SPACE? steps+=Step)*
+ (BLANK_SPACE? examples+=Example)*
;
-Narrative:
- (
- (WORD | INT | STRING | PLACEHOLDER)
- (WORD | INT | STRING | PLACEHOLDER | STEP_KEYWORD | TAGNAME)*
- EOL+
- )+
+/**
+ *
+ */
+Step: {Step}
+ keyword=STEP_KEYWORD description=RawText NL
+ ((BLANK_SPACE? table=Table) | (BLANK_SPACE? text=DocString))?
;
-StepDescription:
- (WORD | INT | STRING | PLACEHOLDER | STEP_KEYWORD | TAGNAME)+
+terminal STEP_KEYWORD:
+ ('Given' | 'When' | 'Then' | 'And' | 'But' | '*')
;
-
-Tag: id=TAGNAME EOL?;
-
-Text: {Text}
- lines+=TextLine*
+terminal PLACEHOLDER:
+ ('<' !('>' | ' ' | '\t' | '\n' | '\r')+ '>')
+ | ('[' !(']' | ' ' | '\t' | '\n' | '\r')+ ']')
;
-TextLine: {TextLine}
- value=TEXT_VALUE EOL+
+/**
+ *
+ */
+Example: {Example}
+ (meta=Meta BLANK_SPACE?)?
+ 'Examples:' title=RawText? NL
+ (BLANK_SPACE? narrative=RawTextBlock NL)?
+ (BLANK_SPACE? table=Table)
;
-TEXT_VALUE returns ecore::EString:
- TEXT_LITERAL TEXT_LITERAL*
-;
-TEXT_LITERAL: WORD
- | INT
+@Override
+StartLiteral: ID
+ | NUMBER
| STRING
+ | PLACEHOLDER
+ | GLOB
| ANY_OTHER
;
-terminal INT:
- '-'?
- ('0'..'9')+
- ('.' ('0'..'9')+)?
-;
-
-terminal STEP_KEYWORD: ('Given' | 'When' | 'Then' | 'And' | 'But') (' ' | '\t')+;
-
-terminal PLACEHOLDER: '<' !('>' | ' ' | '\t' | '\n' | '\r')+ '>';
-
-terminal TABLE_CELL: '|' !('|' | '\n' | '\r')*;
-
-terminal STRING:
- '"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | '"' | '\r' | '\n'))* '"' |
- "'" ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | "'" | '\r' | '\n'))* "'";
-
-terminal SL_COMMENT: '#' !('\n' | '\r')* NL;
-
-terminal TAGNAME: '@' !(' ' | '\t' | '\n' | '\r')+ ;
-
-terminal WORD:
- !('@' | '|' | ' ' | '\t' | '\n' | '\r')
- !(' ' | '\t' | '\n' | '\r')*
-;
-
-terminal WS: (' ' | '\t');
-
-terminal EOL: NL;
-terminal fragment NL: ('\r'? '\n'?);
-
-terminal ANY_OTHER: .;
-
-// ----------------------------------------------------------
-//
-// Unicode Ranges
-//
-// ----------------------------------------------------------
-
-terminal fragment DIGIT: ASCII_DIGIT;
-
-terminal fragment LETTER: LATIN_ALPHABET;
-
-// Basic Latin
-////
-
-terminal fragment ASCII_SPACE: '\u0020';
-
-terminal fragment ASCII_DIGIT: ('\u0030'..'\u0039');
-
-// all ascii chars other than letters, digits, space, or control codes
-terminal fragment ASCII_SYMBOLS: ('\u0021'..'\u002F')
- | ('\u003A'..'\u0040')
- | ('\u005B'..'\u0060')
- | ('\u007B'..'\u007E')
+@Override
+Literal: ID
+ | NUMBER
+ | STRING
+ | PLACEHOLDER
+ | STEP_KEYWORD
+ | GLOB
+ | ANY_OTHER
;
-terminal fragment LATIN_ALPHABET: ('\u0041'..'\u005A')
- | ('\u0061'..'\u007A')
-;
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/CucumberRuntimeModule.java b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/CucumberRuntimeModule.java
index b443a9c9..d4b1c694 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/CucumberRuntimeModule.java
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/CucumberRuntimeModule.java
@@ -3,30 +3,16 @@
*/
package org.agileware.natural.cucumber;
-import org.agileware.natural.common.AbstractAnnotationDescriptor;
+import org.agileware.natural.stepmatcher.DefaultStepMatcher;
+import org.agileware.natural.stepmatcher.IStepMatcher;
/**
- * Use this class to register components to be used at runtime / without the Equinox extension registry.
+ * Use this class to register components to be used at runtime / without the
+ * Equinox extension registry.
*/
public class CucumberRuntimeModule extends org.agileware.natural.cucumber.AbstractCucumberRuntimeModule {
- public final static String[] STEPS = { "Given", "When", "Then", "And", "But" };
- private static final String CUCUMBER_PACKAGE = "io.cucumber.java.en";
-
-
- public Class extends AbstractAnnotationDescriptor> bindAnnotationDescriptor() {
- return CucumberAnnotationDescriptor.class;
- }
-
- public static class CucumberAnnotationDescriptor extends AbstractAnnotationDescriptor {
-
- @Override
- public String[] getNames() {
- return STEPS;
- }
- @Override
- public String getPackage() {
- return CUCUMBER_PACKAGE;
- }
+ public Class extends IStepMatcher> bindIStepMatcher() {
+ return DefaultStepMatcher.class;
}
}
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/GenerateCucumber.mwe2 b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/GenerateCucumber.mwe2
index 5309b2a6..e9f3e0d0 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/GenerateCucumber.mwe2
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/GenerateCucumber.mwe2
@@ -7,7 +7,7 @@ import org.eclipse.xtext.xtext.generator.ui.codemining.CodeMiningFragment
var rootPath = ".."
Workflow {
-
+
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
@@ -37,13 +37,13 @@ Workflow {
language = StandardLanguage {
name = "org.agileware.natural.cucumber.Cucumber"
fileExtensions = "feature"
-
+ referencedResource = "platform:/resource/org.agileware.natural.lang/model/generated/Natural.genmodel"
serializer = {
generateStub = true
}
validator = {
- // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
- // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
+ // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
+ // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
generateDeprecationValidation = true
}
formatter = {
@@ -56,6 +56,9 @@ Workflow {
}
parserGenerator = {
debugGrammar = true
+ options = auto-inject {
+ classSplitting = true
+ }
}
projectWizard = {
generate = false
@@ -66,7 +69,7 @@ Workflow {
generate = false
generateToolbarButton = false
}
- fragment = CodeMiningFragment {
+ fragment = CodeMiningFragment {
generateStub = true
generateXtendStub = false
}
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/formatting2/CucumberFormatter.xtend b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/formatting2/CucumberFormatter.xtend
index 39a74070..7f742205 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/formatting2/CucumberFormatter.xtend
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/formatting2/CucumberFormatter.xtend
@@ -6,167 +6,173 @@ package org.agileware.natural.cucumber.formatting2
import com.google.inject.Inject
import org.agileware.natural.cucumber.cucumber.AbstractScenario
import org.agileware.natural.cucumber.cucumber.Background
-import org.agileware.natural.cucumber.cucumber.DocString
+import org.agileware.natural.cucumber.cucumber.CucumberModel
import org.agileware.natural.cucumber.cucumber.Example
import org.agileware.natural.cucumber.cucumber.Feature
import org.agileware.natural.cucumber.cucumber.Scenario
import org.agileware.natural.cucumber.cucumber.ScenarioOutline
import org.agileware.natural.cucumber.cucumber.Step
-import org.agileware.natural.cucumber.cucumber.Table
-import org.agileware.natural.cucumber.cucumber.Tag
import org.agileware.natural.cucumber.services.CucumberGrammarAccess
+import org.agileware.natural.lang.formatting2.NaturalFormatHelper
+import org.agileware.natural.lang.model.Block
+import org.agileware.natural.lang.model.DocString
+import org.agileware.natural.lang.model.Meta
+import org.agileware.natural.lang.model.MetaElement
+import org.agileware.natural.lang.model.Narrative
+import org.agileware.natural.lang.model.Paragraph
+import org.agileware.natural.lang.model.Table
+import org.eclipse.xtext.Assignment
+import org.eclipse.xtext.Keyword
import org.eclipse.xtext.formatting2.AbstractFormatter2
+import org.eclipse.xtext.formatting2.FormatterRequest
import org.eclipse.xtext.formatting2.IFormattableDocument
import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion
+import org.eclipse.xtext.util.Strings
class CucumberFormatter extends AbstractFormatter2 {
@Inject extension CucumberGrammarAccess cucumberGrammarAccess
+ @Inject NaturalFormatHelper.Factory formatHelperFactory
+
+ var extension NaturalFormatHelper _formatHelper = null
+
+ override protected initialize(FormatterRequest request) {
+ _formatHelper = formatHelperFactory.create(request.textRegionAccess, naturalGrammarAccess)
+ _formatHelper.initialize(request)
+
+ super.initialize(request)
+ }
+
+ def dispatch void format(CucumberModel model, extension IFormattableDocument doc) {
+ // println(textRegionAccess)
+ model.document.format()
+ // println(doc)
+ }
+
def dispatch void format(Feature model, extension IFormattableDocument doc) {
- println(textRegionAccess)
- // format tags
- for (t : model.tags) {
- t.format()
+ resetIndentation()
+
+ // Condense all BLANK_SPACE regions into single line break
+ model.allRegionsFor.ruleCallsTo(BLANK_SPACERule).forEach [ region |
+ // println('''Trimming BLANK_SPACE: «region.offset» «region.length»''')
+ trimBlankSpace(region, 1, doc)
+ ]
+
+ // Format Tags
+ model.meta.format()
+
+ // Cleanup whitespace around keyword/title
+ if (model.title === null) {
+ model.regionFor.keyword(documentAccess.documentKeyword_3).append[noSpace]
+ } else {
+ model.regionFor.assignment(documentAccess.titleAssignment_4).prepend[oneSpace].append[noSpace]
}
- // format background
- model.background.format()
+ increaseIndent()
+ indentBlock(model.startIndent, model.endIndent, doc)
- // format scenarios
- for (s : model.scenarios) {
- s.format()
+ // Format narrative
+ if (model.narrative !== null) {
+ model.narrative.format().prepend[indent]
+ if (!model.narrative.hasLeadingBlankSpace) {
+ model.narrative.prepend[setNewLines(2)]
+ }
}
- println(doc)
+ // Format scenarios
+ model.scenarios.forEach[format().prepend[indent]]
+
+ decreaseIndent()
}
def dispatch void format(Background model, extension IFormattableDocument doc) {
- // format tags
- for (t : model.tags) {
- t.format()
- }
-
- // align keyword to column 0
- model.regionFor
- .keyword(backgroundAccess.backgroundKeyword_1)
- .prepend[noIndentation]
-
- // Indent interior
- val begin = model.regionFor.ruleCallTo(EOLRule)
- val end = endRegionFor(model, doc)
- interior(begin, end)[indent]
-
- // format steps
- for (s : model.steps) {
- s.prepend[indent]
- s.format()
- }
+ // Apply default scenario formatting
+ val keyword = backgroundAccess.backgroundKeyword_2
+ val titleAssignment = backgroundAccess.titleAssignment_3
+ formatScenarioBlock(model, keyword, titleAssignment, doc)
}
def dispatch void format(Scenario model, extension IFormattableDocument doc) {
- // format tags
- for (t : model.tags) {
- t.format()
- }
-
- // align keyword to column 0
- model.regionFor
- .keyword(scenarioAccess.scenarioKeyword_1)
- .prepend[noIndentation]
-
- // Indent interior
- val begin = model.regionFor.ruleCallTo(EOLRule)
- val end = endRegionFor(model, doc)
- interior(begin, end)[indent]
-
- // format steps
- for (s : model.steps) {
- s.prepend[indent]
- s.format()
- }
+ // Apply default scenario formatting
+ val keyword = scenarioAccess.scenarioKeyword_2
+ val titleAssignment = scenarioAccess.titleAssignment_3
+ formatScenarioBlock(model, keyword, titleAssignment, doc)
}
def dispatch void format(ScenarioOutline model, extension IFormattableDocument doc) {
- // format tags
- for (t : model.tags) {
- t.format()
+
+ // Apply default scenario formatting
+ val keyword = scenarioOutlineAccess.scenarioOutlineKeyword_2
+ val titleAssignment = scenarioOutlineAccess.titleAssignment_3
+ formatScenarioBlock(model, keyword, titleAssignment, doc)
+
+ increaseIndent()
+ model.examples.forEach[format().prepend[indent]]
+ decreaseIndent()
+ }
+
+ def dispatch void format(Meta model, extension IFormattableDocument doc) {
+ model.tags.forEach[format]
+ }
+
+ def dispatch void format(MetaElement model, extension IFormattableDocument doc) {
+ // Trim leading/trailing whitespace
+ model.surround[noSpace]
+
+// if (model.value !== null) {
+// // Cleanup whitespace around value assignment
+// model.regionFor.keyword(':').prepend[noSpace].append[oneSpace]
+// model.regionFor.assignment(metaElementAccess.valueAssignment_2_1).prepend[oneSpace].append[noSpace]
+// }
+
+ // Insert newline if not present from BLANK_SPACE
+ if (model.isLast()) {
+ model.append[setNewLines(0)]
+ } else if (!model.hasTrailingBlankSpace) {
+ model.append[newLine]
}
-
- // align keyword to column 0
- model.regionFor
- .keyword(scenarioOutlineAccess.scenarioKeyword_1)
- .prepend[noIndentation]
-
- // Indent interior
- val begin = model.regionFor.ruleCallTo(EOLRule)
- val end = endRegionFor(model, doc)
- interior(begin, end)[indent]
-
- // format steps
- for (s : model.steps) {
- s.prepend[indent]
- s.format()
+ }
+
+ def dispatch void format(Step model, extension IFormattableDocument doc) {
+ // TODO cleanup whitespace
+ if (model.text !== null) {
+ model.text.format().prepend[indent]
}
- // format examples
- for (e : model.examples) {
- e.prepend[indent]
- e.format()
+ if (model.table !== null) {
+ model.table.format().prepend[indent]
}
}
def dispatch void format(Example model, extension IFormattableDocument doc) {
- // format tags
- for (t : model.tags) {
- t.format()
- }
- // TODO this is just a hacky work-around until we can figure
- // why having tags changes the indentation behavior of the
- // keyword
- if (!model.tags.isEmpty()) {
- val region = model.regionFor.keyword(exampleAccess.examplesKeyword_1)
- region.prepend[indent]
+ if (model.meta !== null) {
+ model.meta.format()
+
+ // Work-around for strange keyword placement when tags are present
+ model.regionFor.keyword(exampleAccess.examplesKeyword_2).prepend[indent]
}
- // format table
- model.table.rows.forEach[prepend[indent]]
- model.table.format()
+ // indent Table
+ model.table.format().prepend[indent]
}
- def dispatch void format(Step model, extension IFormattableDocument doc) {
- // TODO cleanup keyword/description
- // format table
- if (model.table !== null) {
- model.table.rows.forEach[prepend[indent]]
- model.table.format()
- }
+ def dispatch void format(Narrative model, extension IFormattableDocument doc) {
+ model.sections.forEach[format().prepend[indent]]
+ }
- // format code
- // TODO proper Text model support (see branch scratch/textmodel)
- if (model.code !== null) {
- val open = docStringAccess.quotationMarkQuotationMarkQuotationMarkKeyword_1_0
- val close = docStringAccess.quotationMarkQuotationMarkQuotationMarkKeyword_1_3
-
- model.code.regionFor.keyword(open).prepend[indent]
- model.code.text.lines.forEach[prepend[indent]]
- model.code.regionFor.keyword(close).prepend[indent]
- model.code.format()
- }
+ def dispatch void format(Paragraph model, extension IFormattableDocument doc) {
+ formatMultilineText(model, paragraphAccess.valueAssignment_1, indentationLevel, doc)
}
def dispatch void format(Table model, extension IFormattableDocument doc) {
- // TODO...
+ model.rows.forEach[prepend[indent]]
}
def dispatch void format(DocString model, extension IFormattableDocument doc) {
- // TODO...
- }
-
- def dispatch void format(Tag model, extension IFormattableDocument doc) {
- // TODO...
+ formatMultilineText(model, docStringAccess.valueAssignment_1, indentationLevel, doc)
}
// ----------------------------------------------------------
@@ -174,107 +180,114 @@ class CucumberFormatter extends AbstractFormatter2 {
// Helper Methods
//
// ----------------------------------------------------------
-
- /**
- * Returns the semantic element that closes the Feature
- *
- * Delegates to:
- * 1. The last element in scenarios
- * 2. The last element in background
- * 3. The EOL rule after title
- */
- protected def ISemanticRegion endRegionFor(Feature model, extension IFormattableDocument doc) {
+ def void formatScenarioBlock(AbstractScenario model, Keyword keyword, Assignment titleAssignment,
+ extension IFormattableDocument doc) {
+
+ // Set block spacing
+ if (!model.hasLeadingBlankSpace) {
+ model.prepend[setNewLines(2)]
+ }
+
+ // Format meta tags
+ if (model.meta !== null) {
+ model.meta.format()
+
+ // Work-around for strange keyword placement when tags are present
+ model.regionFor.keyword(keyword).prepend[indent]
+ }
+
+ // Cleanup whitespace around keyword/title
+ if (model.title === null) {
+ model.regionFor.keyword(keyword).append[noSpace]
+ } else {
+ model.regionFor.assignment(titleAssignment).prepend[oneSpace].append[noSpace]
+ }
+
+ increaseIndent()
+ indentBlock(model.startIndent, model.endIndent, doc)
+
+ // Format narrative
+ if (model.narrative !== null) {
+ model.narrative.format().prepend[indent]
+ }
+
+ // Format steps
+ model.steps.forEach[format().prepend[indent]]
+
+ decreaseIndent()
+ }
+
+ def ISemanticRegion startIndent(Feature model) {
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def ISemanticRegion endIndent(Feature model) {
if (!model.scenarios.isEmpty()) {
- return endRegionFor(model.scenarios.last, doc)
- } else if (model.background !== null) {
- return endRegionFor(model.background, doc)
+ return model.scenarios.last.endIndent()
+ } else if (model.narrative !== null) {
+ return model.narrative.endIndent()
}
- return model.regionFor.ruleCallTo(EOLRule)
+ return model.regionFor.ruleCallTo(NLRule)
}
- /**
- * Returns the semantic element that closes an AbstractScenario
- *
- * Delegates to:
- * 1. The last element in `steps`
- * 3. The EOL rule after title
- */
- protected def ISemanticRegion endRegionFor(AbstractScenario model, extension IFormattableDocument doc) {
- if (!model.steps.isEmpty()) {
- return endRegionFor(model.steps.last, doc)
+ def ISemanticRegion startIndent(AbstractScenario model) {
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def ISemanticRegion endIndent(Narrative model) {
+ return model.sections.last.endIndent()
+ }
+
+ def ISemanticRegion endIndent(Block model) {
+ if (model instanceof Table) {
+ return model.rows.last.regionFor.ruleCallTo(NLRule)
}
- return model.regionFor.ruleCallTo(EOLRule)
+ return model.regionFor.ruleCallTo(NLRule)
}
- /**
- * Returns the semantic element that closes a ScenarioOutline
- *
- * Delegates to:
- * 1. The last element in examples
- * 2. The last element in steps
- * 3. The EOL rule after title
- */
- protected def ISemanticRegion endRegionFor(ScenarioOutline model, extension IFormattableDocument doc) {
- if (!model.examples.isEmpty()) {
- return endRegionFor(model.examples.last, doc)
- } else if (!model.steps.isEmpty()) {
- return endRegionFor(model.steps.last, doc)
+ def ISemanticRegion endIndent(AbstractScenario model) {
+ if (model instanceof ScenarioOutline) {
+ if (!model.examples.isEmpty()) {
+ return model.examples.last.endIndent()
+ }
+ }
+
+ if (!model.steps.isEmpty()) {
+ return model.steps.last.endIndent()
+ } else if (model.narrative !== null) {
+ return model.narrative.endIndent()
}
- return model.regionFor.ruleCallTo(EOLRule)
+ return model.regionFor.ruleCallTo(NLRule)
}
- /**
- * Returns the semantic element that closes an Example
- *
- * Delegates to:
- * 1. The EOL rule after the Table
- * 1. The EOL rule after the title
- */
- protected def ISemanticRegion endRegionFor(Example model, extension IFormattableDocument doc) {
+ def ISemanticRegion endIndent(Example model) {
if (model.table !== null) {
- return endRegionFor(model.table, doc)
+ return model.table.endIndent()
+ } else if (Strings.isEmpty(model.narrative)) {
+ return model.regionFor.ruleCall(exampleAccess.NLTerminalRuleCall_5_2)
}
- return model.regionFor.ruleCallTo(EOLRule)
+ return model.regionFor.ruleCall(exampleAccess.NLTerminalRuleCall_4)
}
- /**
- * Returns the semantic element that closes a Step
- *
- * Delegates to:
- * 1. Either to code or table if present
- * 2. The EOL rule after `description`
- */
- protected def ISemanticRegion endRegionFor(Step model, extension IFormattableDocument doc) {
- if (model.code !== null) {
- return endRegionFor(model.code, doc)
+ def ISemanticRegion endIndent(Step model) {
+ if (model.text !== null) {
+ return model.text.endIndent()
} else if (model.table !== null) {
- return endRegionFor(model.table, doc)
+ return model.table.endIndent()
}
- return model.regionFor.ruleCallTo(EOLRule)
+ return model.regionFor.ruleCallTo(NLRule)
}
- /**
- * Returns the semantic element that closes a DocString
- *
- * Delegates to:
- * 1. The EOLRule at the end of the element
- */
- protected def ISemanticRegion endRegionFor(DocString model, extension IFormattableDocument doc) {
- return model.regionFor.ruleCall(docStringAccess.EOLTerminalRuleCall_2)
+ def ISemanticRegion endIndent(DocString model) {
+ return model.regionFor.ruleCall(docStringAccess.NLTerminalRuleCall_2)
}
- /**
- * Returns the semantic element that closes a Table
- *
- * Delegates to:
- * 1. The EOLRule at the end of the table
- */
- protected def ISemanticRegion endRegionFor(Table model, extension IFormattableDocument doc) {
- return model.rows.last.regionFor.ruleCallTo(EOLRule)
+ def ISemanticRegion endIndent(Table model) {
+ return model.rows.last.regionFor.ruleCallTo(NLRule)
}
}
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/serializer/CucumberSerializer.xtend b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/serializer/CucumberSerializer.xtend
index 44f79376..38772bc5 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/serializer/CucumberSerializer.xtend
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/serializer/CucumberSerializer.xtend
@@ -1,42 +1,52 @@
package org.agileware.natural.cucumber.serializer
+import com.google.inject.Inject
+import org.agileware.natural.cucumber.cucumber.AbstractScenario
import org.agileware.natural.cucumber.cucumber.Background
-import org.agileware.natural.cucumber.cucumber.DocString
+import org.agileware.natural.cucumber.cucumber.CucumberModel
import org.agileware.natural.cucumber.cucumber.Example
import org.agileware.natural.cucumber.cucumber.Feature
import org.agileware.natural.cucumber.cucumber.Scenario
import org.agileware.natural.cucumber.cucumber.ScenarioOutline
import org.agileware.natural.cucumber.cucumber.Step
-import org.agileware.natural.cucumber.cucumber.Table
-import org.agileware.natural.cucumber.cucumber.TableCol
-import org.agileware.natural.cucumber.cucumber.TableRow
-import org.agileware.natural.cucumber.cucumber.Tag
+import org.agileware.natural.lang.serializer.NaturalSerializer
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
-import org.agileware.natural.cucumber.cucumber.Text
class CucumberSerializer {
+ @Inject extension NaturalSerializer
+
+ def String serialize(CucumberModel model) '''
+ # language: en
+ «IF model.document !== null»
+ «serialize(model.document)»
+ «ENDIF»
+ '''
+
def String serialize(Feature model) '''
- «FOR t : model.tags»
- «serialize(t)»
- «ENDFOR»
+ «serialize(model.meta)»
Feature: «model.title»
«model.narrative»
-
- «IF model.background !== null»
- «serialize(model.background)»
- «ENDIF»
«FOR s : model.scenarios»
-
- «IF s instanceof Scenario»
- «serialize(s)»
- «ELSEIF s instanceof ScenarioOutline»
- «serialize(s)»
- «ENDIF»
+
+ «serialize(s)»
«ENDFOR»
'''
+ def String serialize(AbstractScenario model) {
+ if (model instanceof Background) {
+ return serialize(model as Background)
+ } else if (model instanceof Scenario) {
+ return serialize(model as Scenario)
+ } else if (model instanceof ScenarioOutline) {
+ return serialize(model as ScenarioOutline)
+ }
+
+ return "\n"
+ }
+
def String serialize(Background model) '''
+ «serialize(model.meta)»
Background: «model.title»
«model.narrative»
«FOR s : model.steps»
@@ -45,9 +55,7 @@ class CucumberSerializer {
'''
def String serialize(Scenario model) '''
- «FOR t : model.tags»
- «serialize(t)»
- «ENDFOR»
+ «serialize(model.meta)»
Scenario: «model.title»
«model.narrative»
«FOR s : model.steps»
@@ -56,17 +64,12 @@ class CucumberSerializer {
'''
def String serialize(ScenarioOutline model) '''
- «FOR t : model.tags»
- «serialize(t)»
- «ENDFOR»
- Scenario Outline: «model.title»
+ «serialize(model.meta)»
+ Scenario Outline:«model.title»
«model.narrative»
- «FOR s : model.steps»
- «serialize(s)»
- «ENDFOR»
«FOR e : model.examples»
-
- «serialize(e)»
+
+ «serialize(e)»
«ENDFOR»
'''
@@ -80,43 +83,8 @@ class CucumberSerializer {
«NodeModelUtils.getNode(model).getText()»
«IF model.table !== null»
«serialize(model.table)»
- «ELSEIF model.code !== null»
- «serialize(model.code)»
+ «ELSEIF model.text !== null»
+ «serialize(model.text)»
«ENDIF»
'''
-
- def String serialize(Tag model) '''
- @«model.id»
- '''
-
- def String serialize(Table model) '''
- «FOR r : model.rows»
- «serialize(r)»
- «ENDFOR»
- '''
-
-
- def String serialize(TableRow model) '''
- «model.cols.map[serialize].join()» |
- '''
-
- def String serialize(TableCol model) {
- return model.cell
- }
-
- def String serialize(DocString model) '''
- """
- «serialize(model.text)»
- """
- '''
-
- /**
- * TODO this will most certainly break two-way serialization,
- * as trailing line breaks are not assigned within the TEXT_VALUE.
- */
- def String serialize(Text model) '''
- «FOR l : model.lines»
- «l.value»
- «ENDFOR»
- '''
}
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberIssueCodes.java b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberIssueCodes.java
new file mode 100644
index 00000000..c45ca54d
--- /dev/null
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberIssueCodes.java
@@ -0,0 +1,16 @@
+package org.agileware.natural.cucumber.validation;
+
+public interface CucumberIssueCodes {
+
+ String PREFIX = "org.agileware.natural.cucumber.";
+
+ String MISSING_FEATURE_TITLE = PREFIX + "MISSING_FEATURE_TITLE";
+
+ String MISSING_SCENARIOS = PREFIX + "MISSING_SCENARIOS";
+
+ String MISSING_SCENARIO_STEPS = PREFIX + "MISSING_SCENARIO_STEPS";
+
+ String MISSING_STEPDEFS = PREFIX + "MISSING_STEPDEFS";
+
+ String MULTIPLE_STEPDEFS = PREFIX + "MULTIPLE_STEPDEFS";
+}
diff --git a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberValidator.java b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberValidator.java
index 25a06b54..72a9c5cb 100644
--- a/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberValidator.java
+++ b/org.agileware.natural.cucumber/src/org/agileware/natural/cucumber/validation/CucumberValidator.java
@@ -1,40 +1,89 @@
package org.agileware.natural.cucumber.validation;
-import org.agileware.natural.common.JavaAnnotationMatcher;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.ABSTRACT_SCENARIO__STEPS;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.FEATURE__SCENARIOS;
+import static org.agileware.natural.cucumber.cucumber.CucumberPackage.Literals.FEATURE__TITLE;
+import static org.agileware.natural.cucumber.validation.CucumberIssueCodes.MISSING_FEATURE_TITLE;
+import static org.agileware.natural.cucumber.validation.CucumberIssueCodes.MISSING_SCENARIOS;
+import static org.agileware.natural.cucumber.validation.CucumberIssueCodes.MISSING_SCENARIO_STEPS;
+
+import java.util.Collection;
+
+import org.agileware.natural.cucumber.cucumber.AbstractScenario;
import org.agileware.natural.cucumber.cucumber.CucumberPackage;
+import org.agileware.natural.cucumber.cucumber.Feature;
import org.agileware.natural.cucumber.cucumber.Step;
-import org.eclipse.jdt.core.IMethod;
+import org.agileware.natural.stepmatcher.IStepMatcher;
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.validation.CheckType;
+import org.eclipse.xtext.validation.ValidationMessageAcceptor;
import com.google.inject.Inject;
public class CucumberValidator extends AbstractCucumberValidator {
-
+
@Inject
- private JavaAnnotationMatcher matcher;
-
- @Check(CheckType.EXPENSIVE)
- public void checkStepMatching(Step step) {
- final Counter counter = new Counter();
- String description = step.getDescription().trim();
- matcher.findMatches(description, counter);
- if (counter.get() == 0) {
- warning("No definition found for `" + description + "`", CucumberPackage.Literals.STEP__DESCRIPTION);
- } else if (counter.get() > 1) {
- warning("Multiple definitions found for `" + description + "`", CucumberPackage.Literals.STEP__DESCRIPTION);
+ private IStepMatcher matcher;
+
+ /**
+ * Issue a warning if the Feature has no title
+ *
+ * @param model
+ */
+ @Check(CheckType.FAST)
+ public void featureTitle(final Feature model) {
+ if (model.getTitle() == null) {
+ warning("Feature title is missing", FEATURE__TITLE, ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
+ MISSING_FEATURE_TITLE);
+ }
+ }
+
+ /**
+ * Issue a warning if Feature has no scenarios defined. **note:** Do not depend
+ * on grammar rule validation
+ *
+ * @param model
+ */
+ @Check(CheckType.FAST)
+ public void missingScenarios(final Feature model) {
+ if (model.getScenarios().isEmpty()) {
+ warning("Feature has no scenarios", model, FEATURE__SCENARIOS, MISSING_SCENARIOS);
}
}
- private final static class Counter implements JavaAnnotationMatcher.Command {
- private int count = 0;
-
- public int get() {
- return count;
+ /**
+ * Issue a warning if AbstractScenario has no defined steps. **note:** Do not
+ * depend on grammar rule validation
+ *
+ * @param model
+ */
+ @Check(CheckType.FAST)
+ public void missingScenarioSteps(final AbstractScenario model) {
+ if (model.getSteps().isEmpty()) {
+ warning("Scenario has no steps", model, ABSTRACT_SCENARIO__STEPS, MISSING_SCENARIO_STEPS);
}
-
- public void match(String annotationValue, IMethod method) {
- count++;
+ }
+
+ /**
+ * Scan for matching java annotation if activated
+ *
+ * @param model
+ */
+ @Check(CheckType.NORMAL)
+ public void checkStepMatching(final Step step) {
+ if (!matcher.isActivated())
+ return;
+
+ final String keyword = step.getKeyword();
+ final String description = step.getDescription();
+ if (keyword != null && description != null) {
+ final Collection> matches = matcher.findMatches(keyword, description);
+ if (matches.size() == 0) {
+ warning("No definition found for `" + description + "`", CucumberPackage.Literals.STEP__DESCRIPTION);
+ } else if (matches.size() > 1) {
+ warning("Multiple definitions found for `" + description + "`",
+ CucumberPackage.Literals.STEP__DESCRIPTION);
+ }
}
}
}
diff --git a/org.agileware.natural.jbehave.feature/feature.xml b/org.agileware.natural.jbehave.feature/feature.xml
index c5dbfa59..cd17db3e 100644
--- a/org.agileware.natural.jbehave.feature/feature.xml
+++ b/org.agileware.natural.jbehave.feature/feature.xml
@@ -66,7 +66,14 @@ to corresponding Java annotated classes.
unpack="false"/>
+
+
4.0.0
@@ -19,11 +20,14 @@
org.eclipse.tycho
tycho-surefire-plugin
+ false
true
+ true
+ org.agileware.natural.jbehave.ui.tests
+ org.agileware.natural.jbehave.ui.tests.JbehaveUiTestSuite
- 1.0.0-SNAPSHOT
diff --git a/org.agileware.natural.jbehave.ui/META-INF/MANIFEST.MF b/org.agileware.natural.jbehave.ui/META-INF/MANIFEST.MF
index 949b5077..4ebb6a0b 100644
--- a/org.agileware.natural.jbehave.ui/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.jbehave.ui/META-INF/MANIFEST.MF
@@ -8,6 +8,8 @@ Bundle-SymbolicName: org.agileware.natural.jbehave.ui; singleton:=true
Bundle-ActivationPolicy: lazy
Require-Bundle: org.agileware.natural.jbehave,
org.agileware.natural.jbehave.ide,
+ org.agileware.natural.lang.ui,
+ org.agileware.natural.stepmatcher.ui,
org.eclipse.xtext.ui,
org.eclipse.xtext.ui.shared,
org.eclipse.xtext.ui.codetemplates.ui,
@@ -18,9 +20,14 @@ Require-Bundle: org.agileware.natural.jbehave,
org.eclipse.xtext.builder
Import-Package: org.apache.log4j
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Export-Package: org.agileware.natural.jbehave.ui.contentassist;uses:="org.eclipse.emf.ecore,org.eclipse.xtext.ui.editor.contentassist,org.eclipse.xtext",
+Export-Package: org.agileware.natural.jbehave.ui.contentassist;
+ uses:="org.eclipse.emf.ecore,
+ org.agileware.natural.lang.ui.contentassist,
+ org.eclipse.xtext.ui.editor.contentassist,
+ org.eclipse.xtext",
org.agileware.natural.jbehave.ui.internal;uses:="org.osgi.framework,com.google.inject,org.eclipse.ui.plugin",
org.agileware.natural.jbehave.ui.labeling;uses:="org.eclipse.xtext.ui.label,org.eclipse.emf.edit.ui.provider",
org.agileware.natural.jbehave.ui.outline;uses:="org.eclipse.xtext.ui.editor.outline.impl",
- org.agileware.natural.jbehave.ui.quickfix;uses:="org.eclipse.xtext.ui.editor.quickfix"
+ org.agileware.natural.jbehave.ui.quickfix;uses:="org.eclipse.xtext.ui.editor.quickfix",
+ org.agileware.natural.jbehave.validation;uses:="org.eclipse.swt.widgets,org.eclipse.jface.dialogs,org.eclipse.xtext.ui.validation"
Bundle-Activator: org.agileware.natural.jbehave.ui.internal.JbehaveActivator
diff --git a/org.agileware.natural.jbehave.ui/build.properties b/org.agileware.natural.jbehave.ui/build.properties
index 282ec075..0a12cca8 100644
--- a/org.agileware.natural.jbehave.ui/build.properties
+++ b/org.agileware.natural.jbehave.ui/build.properties
@@ -1,7 +1,9 @@
source.. = src/,\
- src-gen/
+ src-gen/,\
+ xtend-gen/
bin.includes = META-INF/,\
.,\
plugin.xml
-additional.bundles = org.agileware.natural.common,\
+additional.bundles = org.agileware.natural.stepmatcher,\
+ org.agileware.natural.stepmatcher.ui,\
org.agileware.natural.jbehave
diff --git a/org.agileware.natural.jbehave.web/WebRoot/xtext-resources/generated/mode-story.js b/org.agileware.natural.jbehave.web/WebRoot/xtext-resources/generated/mode-story.js
index d9d0c44c..f70d74cb 100644
--- a/org.agileware.natural.jbehave.web/WebRoot/xtext-resources/generated/mode-story.js
+++ b/org.agileware.natural.jbehave.web/WebRoot/xtext-resources/generated/mode-story.js
@@ -1,6 +1,10 @@
define(["ace/lib/oop", "ace/mode/text", "ace/mode/text_highlight_rules"], function(oop, mText, mTextHighlightRules) {
var HighlightRules = function() {
+ var keywords = "ANY|FAILURE|SCENARIO|STEP|STORY|SUCCESS";
this.$rules = {
+ "start": [
+ {token: "keyword", regex: "\\b(?:" + keywords + ")\\b"}
+ ]
};
};
oop.inherits(HighlightRules, mTextHighlightRules.TextHighlightRules);
diff --git a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.java b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.java
new file mode 100644
index 00000000..0dcea3e0
--- /dev/null
+++ b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.java
@@ -0,0 +1,34 @@
+/*
+ * generated by Xtext 2.22.0
+ */
+package org.agileware.natural.jbehave.web;
+
+import com.google.inject.Injector;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import org.eclipse.xtext.util.DisposableRegistry;
+import org.eclipse.xtext.web.servlet.XtextServlet;
+
+/**
+ * Deploy this class into a servlet container to enable DSL-specific services.
+ */
+@WebServlet(name = "XtextServices", urlPatterns = "/xtext-service/*")
+public class JbehaveServlet extends XtextServlet {
+
+ DisposableRegistry disposableRegistry;
+
+ public void init() throws ServletException {
+ super.init();
+ Injector injector = new JbehaveWebSetup().createInjectorAndDoEMFRegistration();
+ this.disposableRegistry = injector.getInstance(DisposableRegistry.class);
+ }
+
+ public void destroy() {
+ if (disposableRegistry != null) {
+ disposableRegistry.dispose();
+ disposableRegistry = null;
+ }
+ super.destroy();
+ }
+
+}
diff --git a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.xtend b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.xtend
deleted file mode 100644
index d2637de2..00000000
--- a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/JbehaveServlet.xtend
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * generated by Xtext 2.21.0
- */
-package org.agileware.natural.jbehave.web
-
-import javax.servlet.annotation.WebServlet
-import org.eclipse.xtext.util.DisposableRegistry
-import org.eclipse.xtext.web.servlet.XtextServlet
-
-/**
- * Deploy this class into a servlet container to enable DSL-specific services.
- */
-@WebServlet(name = 'XtextServices', urlPatterns = '/xtext-service/*')
-class JbehaveServlet extends XtextServlet {
-
- DisposableRegistry disposableRegistry
-
- override init() {
- super.init()
- val injector = new JbehaveWebSetup().createInjectorAndDoEMFRegistration()
- disposableRegistry = injector.getInstance(DisposableRegistry)
- }
-
- override destroy() {
- if (disposableRegistry !== null) {
- disposableRegistry.dispose()
- disposableRegistry = null
- }
- super.destroy()
- }
-
-}
diff --git a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.java b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.java
new file mode 100644
index 00000000..a1f46e0e
--- /dev/null
+++ b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.java
@@ -0,0 +1,65 @@
+/*
+ * generated by Xtext 2.22.0
+ */
+package org.agileware.natural.jbehave.web;
+
+import java.net.InetSocketAddress;
+import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.log.Slf4jLog;
+import org.eclipse.jetty.webapp.Configuration;
+import org.eclipse.jetty.webapp.MetaInfConfiguration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.webapp.WebInfConfiguration;
+import org.eclipse.jetty.webapp.WebXmlConfiguration;
+
+/**
+ * This program starts an HTTP server for testing the web integration of your DSL.
+ * Just execute it and point a web browser to http://localhost:8080/
+ */
+public class ServerLauncher {
+ public static void main(String[] args) {
+ Server server = new Server(new InetSocketAddress("localhost", 8080));
+ WebAppContext ctx = new WebAppContext();
+ ctx.setResourceBase("WebRoot");
+ ctx.setWelcomeFiles(new String[] {"index.html"});
+ ctx.setContextPath("/");
+ ctx.setConfigurations(new Configuration[] {
+ new AnnotationConfiguration(),
+ new WebXmlConfiguration(),
+ new WebInfConfiguration(),
+ new MetaInfConfiguration()
+ });
+ ctx.setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN,
+ ".*/org\\.agileware\\.natural\\.jbehave\\.web/.*,.*\\.jar");
+ ctx.setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false");
+ server.setHandler(ctx);
+ Slf4jLog log = new Slf4jLog(ServerLauncher.class.getName());
+ try {
+ server.start();
+ log.info("Server started " + server.getURI() + "...");
+ new Thread() {
+
+ public void run() {
+ try {
+ log.info("Press enter to stop the server...");
+ int key = System.in.read();
+ if (key != -1) {
+ server.stop();
+ } else {
+ log.warn(
+ "Console input is not available. In order to stop the server, you need to cancel process manually.");
+ }
+ } catch (Exception e) {
+ log.warn(e);
+ }
+ }
+
+ }.start();
+ server.join();
+ } catch (Exception exception) {
+ log.warn(exception.getMessage());
+ System.exit(1);
+ }
+ }
+}
diff --git a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.xtend b/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.xtend
deleted file mode 100644
index 5f478ebf..00000000
--- a/org.agileware.natural.jbehave.web/src/org/agileware/natural/jbehave/web/ServerLauncher.xtend
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * generated by Xtext 2.21.0
- */
-package org.agileware.natural.jbehave.web
-
-import java.net.InetSocketAddress
-import org.eclipse.jetty.annotations.AnnotationConfiguration
-import org.eclipse.jetty.server.Server
-import org.eclipse.jetty.util.log.Slf4jLog
-import org.eclipse.jetty.webapp.MetaInfConfiguration
-import org.eclipse.jetty.webapp.WebAppContext
-import org.eclipse.jetty.webapp.WebInfConfiguration
-import org.eclipse.jetty.webapp.WebXmlConfiguration
-
-/**
- * This program starts an HTTP server for testing the web integration of your DSL.
- * Just execute it and point a web browser to http://localhost:8080/
- */
-class ServerLauncher {
- def static void main(String[] args) {
- val server = new Server(new InetSocketAddress('localhost', 8080))
- server.handler = new WebAppContext => [
- resourceBase = 'WebRoot'
- welcomeFiles = #["index.html"]
- contextPath = "/"
- configurations = #[
- new AnnotationConfiguration,
- new WebXmlConfiguration,
- new WebInfConfiguration,
- new MetaInfConfiguration
- ]
- setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, '.*/org\\.agileware\\.natural\\.jbehave\\.web/.*,.*\\.jar')
- setInitParameter("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false")
- ]
- val log = new Slf4jLog(ServerLauncher.name)
- try {
- server.start
- log.info('Server started ' + server.getURI + '...')
- new Thread[
- log.info('Press enter to stop the server...')
- val key = System.in.read
- if (key != -1) {
- server.stop
- } else {
- log.warn('Console input is not available. In order to stop the server, you need to cancel process manually.')
- }
- ].start
- server.join
- } catch (Exception exception) {
- log.warn(exception.message)
- System.exit(1)
- }
- }
-}
diff --git a/org.agileware.natural.jbehave/META-INF/MANIFEST.MF b/org.agileware.natural.jbehave/META-INF/MANIFEST.MF
index 7b0b2a37..a704fa64 100644
--- a/org.agileware.natural.jbehave/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.jbehave/META-INF/MANIFEST.MF
@@ -6,7 +6,8 @@ Bundle-Vendor: Roberto Lo Giacco
Bundle-Version: 1.0.0.qualifier
Bundle-SymbolicName: org.agileware.natural.jbehave; singleton:=true
Bundle-ActivationPolicy: lazy
-Require-Bundle: org.agileware.natural.common,
+Require-Bundle: org.agileware.natural.lang;visibility:=reexport,
+ org.agileware.natural.stepmatcher;visibility:=reexport,
org.eclipse.xtext,
org.eclipse.xtext.xbase,
org.eclipse.equinox.common;bundle-version="3.5.0",
@@ -14,6 +15,7 @@ Require-Bundle: org.agileware.natural.common,
org.eclipse.xtext.xbase.lib;bundle-version="2.14.0",
org.eclipse.xtext.util,
org.eclipse.emf.common,
+ org.eclipse.jdt.core,
org.antlr.runtime;bundle-version="[3.2.0,3.2.1)"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: org.agileware.natural.jbehave;uses:="com.google.inject,org.eclipse.xtext,org.eclipse.xtext.service",
diff --git a/org.agileware.natural.jbehave/model/generated/Jbehave.ecore b/org.agileware.natural.jbehave/model/generated/Jbehave.ecore
index 6363e3a7..e67d7320 100644
--- a/org.agileware.natural.jbehave/model/generated/Jbehave.ecore
+++ b/org.agileware.natural.jbehave/model/generated/Jbehave.ecore
@@ -1,67 +1,104 @@
+
+
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
+
+
+
-
+
+ eType="#//LifecycleAfterElement" containment="true"/>
-
-
-
+
+
+
-
-
+
+
-
-
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
+
-
-
+
+
diff --git a/org.agileware.natural.jbehave/model/generated/Jbehave.genmodel b/org.agileware.natural.jbehave/model/generated/Jbehave.genmodel
index 28f85712..8885c96a 100644
--- a/org.agileware.natural.jbehave/model/generated/Jbehave.genmodel
+++ b/org.agileware.natural.jbehave/model/generated/Jbehave.genmodel
@@ -1,59 +1,90 @@
+ complianceLevel="8.0" copyrightFields="false" runtimeVersion="2.20" usedGenPackages="platform:/resource/org.agileware.natural.lang/model/generated/Natural.genmodel#//model">
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/GenerateJbehave.mwe2 b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/GenerateJbehave.mwe2
index a503dad0..2d3a1e41 100644
--- a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/GenerateJbehave.mwe2
+++ b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/GenerateJbehave.mwe2
@@ -6,7 +6,7 @@ import org.eclipse.xtext.xtext.generator.model.project.*
var rootPath = ".."
Workflow {
-
+
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
@@ -36,13 +36,13 @@ Workflow {
language = StandardLanguage {
name = "org.agileware.natural.jbehave.Jbehave"
fileExtensions = "story"
-
+ referencedResource = "platform:/resource/org.agileware.natural.lang/model/generated/Natural.genmodel"
serializer = {
generateStub = true
}
validator = {
- // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
- // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
+ // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
+ // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
generateDeprecationValidation = true
}
formatter = {
@@ -55,6 +55,9 @@ Workflow {
}
parserGenerator = {
debugGrammar = true
+ options = auto-inject {
+ classSplitting = true
+ }
}
projectWizard = {
generate = false
diff --git a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/Jbehave.xtext b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/Jbehave.xtext
index 4a6223c8..ed0cdd25 100644
--- a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/Jbehave.xtext
+++ b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/Jbehave.xtext
@@ -1,102 +1,251 @@
-grammar org.agileware.natural.jbehave.Jbehave hidden(SPACE, SL_COMMENT)
+grammar org.agileware.natural.jbehave.Jbehave with org.agileware.natural.lang.Natural
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate jbehave "http://www.agileware.org/natural/jbehave"
+/**
+ *
+ */
+JbehaveModel:
+ {JbehaveModel}
+ BLANK_SPACE?
+ document=Story?;
+
+ /**
+ * The story describes a feature via description, narrative and a set of scenarios
+ * Story := Description? Meta? Narrative? GivenStories? Lifecycle? Scenario+ ;
+ */
Story:
- description+=Description*
- meta=Meta?
- narrative=Narrative?
- scenarios+=Scenario+;
-
-Narrative:
- 'Narrative:'
- inOrderTo=InOrderTo
- asA=AsA
- iWantTo=IWantTo;
-
-Scenario:
- 'Scenario:'
- description+=Description+
- meta=Meta?
- given=GivenStories?
- conditions+=Step+
- examples=Examples?;
-
-GivenStories:
- 'GivenStories:'
- resources+=StoryPath+;
-
-StoryPath:
- path=PATH ','?;
-
-Meta: {Meta}
- 'Meta:'
- elements+=Tag*;
-
-Step:
- description=StepDescription EOL*
- table=Table?;
-
-InOrderTo:
- IN_ORDER_TO content=NarrativeElementContent;
-
-AsA:
- AS_A content=NarrativeElementContent;
-
-IWantTo:
- I_WANT_TO content=NarrativeElementContent;
-
-Examples:
- 'Examples:'
- table=Table;
-
-Table:
- rows+=TABLE_ROW+ EOL*;
-
+ {Story}
+ (description=Description BLANK_SPACE?)?
+ (meta=Meta BLANK_SPACE?)?
+ (narrative=StoryNarrative BLANK_SPACE?)
+ (lifecycle=Lifecycle BLANK_SPACE?)?
+ scenarios+=Scenario
+ (BLANK_SPACE? scenarios+=Scenario)*
+;
+
+/**
+ * The Description is expressed by any sequence of words that must not contain any keywords at start of lines.
+ * Description := (Word Space?)* ;
+ */
Description:
- Content EOL+;
-
-StepDescription:
- STEP_KEYWORD (STRING | WORD | INT | ANY | PLACEHOLDER)+;
-
-NarrativeElementContent:
- (STRING | WORD | INT | ANY | PLACEHOLDER) (AT | STRING | WORD | INT | ANY | PLACEHOLDER | STEP_KEYWORD)*;
-
-Content:
- (STRING | WORD | INT | ANY | PLACEHOLDER) (AT | STRING | WORD | INT | ANY | PLACEHOLDER | STEP_KEYWORD)*;
-
-Tag: AT name=WORD EOL?;
-
-
-terminal STEP_KEYWORD: ('Given' | 'When' | 'Then' | 'And' | '!--');
+ {Description}
+ value=RawTextBlock
+ NL
+;
+
+/**
+ * The meta is identified by keyword "Meta:" (or equivalent in I18n-ed locale),
+ * It is followed by any number of meta elements
+ * Meta:= "Meta:" (MetaElement)* ;
+ */
+@Override
+Meta: {Meta}
+ 'Meta:' NL
+ (BLANK_SPACE? tags+=MetaElement)+
+ NL
+;
+
+/**
+ * The narrative is identified by keyword "Narrative:" (or equivalent in I18n-ed locale),
+ * It is followed by the narrative elements
+ * Narrative:= "Narrative:" ( InOrderTo AsA IWantTo | AsA IWantTo SoThat ) ;
+ */
+StoryNarrative: StoryNarrativeA
+ | StoryNarrativeB
+;
+
+StoryNarrativeA: {StoryNarrativeA}
+ 'Narrative:' NL
+ (BLANK_SPACE? inOrderTo=InOrderTo)
+ (BLANK_SPACE? asA=AsA)
+ (BLANK_SPACE? wantTo=IWantTo);
+
+StoryNarrativeB: {StoryNarrativeB}
+ 'Narrative:' NL
+ (BLANK_SPACE? asA=AsA)
+ (BLANK_SPACE? wantTo=IWantTo)
+ (BLANK_SPACE? soThat=SoThat);
+
+StoryNarrativeElement: InOrderTo
+ | AsA
+ | IWantTo
+ | SoThat
+;
+
+InOrderTo: {InOrderTo}
+ keyword=IN_ORDER_TO value=RawText NL
+;
+
+AsA: {AsA}
+ keyword=AS_A value=RawText NL
+;
+
+IWantTo: {IWantTo}
+ keyword=I_WANT_TO value=RawText NL
+;
+
+SoThat: {SoThat}
+ keyword=SO_THAT value=RawText NL
+;
terminal IN_ORDER_TO: 'In order to';
-
terminal AS_A: 'As a';
-
terminal I_WANT_TO: 'I want to';
-
-terminal PLACEHOLDER: '<' ('a'..'z' | 'A'..'Z') !('>' | '\n' | '\r')* '>';
-
-terminal TABLE_ROW: '|' (!('|' | '\n' | '\r')* '|')+ SPACE* EOL;
-
-terminal WORD: ('a'..'z' | 'A'..'Z') !(SPACE | '\n' | '\r')*;
-
-terminal PATH: '/' ('/' | '.' | '_' | 'a'..'z' | 'A'..'Z' | '0'..'9')+;
-
-terminal INT returns ecore::EDouble: '-'? ('0'..'9')+ ('.' ('0'..'9')+)?;
-
-terminal STRING:
- '"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | '"'))* '"' |
- "'" ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | "'"))* "'";
-
-terminal SL_COMMENT: '#' !('\n' | '\r')* EOL;
-
-terminal SPACE: (' ' | '\t');
-
-terminal EOL: '\r'? '\n'?;
-
-terminal AT: '@';
-
-terminal ANY: .;
\ No newline at end of file
+terminal SO_THAT: 'So that';
+
+/**
+ * The lifecycle is identified by keyword "Lifecycle:" (or equivalent in I18n-ed locale),
+ * It is followed by the lifecycle elements
+ * Lifecycle:= "Lifecycle:" LifecycleBefore? LifecycleAfter?
+ */
+Lifecycle: {Lifecycle}
+ 'Lifecycle:' NL
+ before=LifecycleBefore?
+ after=LifecycleAfter?
+;
+
+/**
+ * The before lifecyle element identified by keyword "Before:" (or equivalent in I18n-ed locale),
+ * followed by one or more steps
+ * LifecycleBefore:= "Before:" (Scope? Step+)+
+ */
+LifecycleBefore: {LifecycleBefore}
+ "Before:" NL
+ elements+=LifecycleBeforeElement+
+;
+
+LifecycleBeforeElement: {LifecycleBeforeElement}
+ scope=Scope NL
+ steps+=Step+
+;
+
+/**
+ * The after lifecyle element identified by keyword "After:" (or equivalent in I18n-ed locale),
+ * followed by one or more sets of scope, outcome, meta filter and steps
+ * LifecycleAfter:= "After:" (Scope? Outcome? MetaFilter? Step+)+
+ */
+LifecycleAfter: {LifecycleAfter}
+ "After:" NL
+ elements+=LifecycleAfterElement+
+;
+
+LifecycleAfterElement: {LifecycleAfterElement}
+ scope=Scope NL
+ (outcome=Outcome NL)?
+ steps+=Step+
+;
+
+/**
+ * The scope element identified by keyword "Scope:" (or equivalent in I18n-ed locale),
+ * Scope:= "Scope:" "STEP" | "SCENARIO" | "STORY"
+ */
+Scope: {Scope}
+ "Scope:"
+ type=ScopeType
+;
+
+enum ScopeType: STEP
+ | SCENARIO
+ | STORY
+;
+
+/**
+ * The outcome element identified by keyword "Outcome:" (or equivalent in I18n-ed locale),
+ * Outcome:= "Outcome:" "ANY" | "SUCCESS" | "FAILURE" ;
+ */
+Outcome: {Outcome}
+ "Outcome:"
+ type=OutcomeType
+;
+
+enum OutcomeType: ANY
+ | SUCCESS
+ | FAILURE
+;
+
+/**
+ * The scenario is identified by keyword "Scenario:" (or equivalent in I18n-ed locale),
+ * which is optional in the case of a single scenario.
+ * It can optionally be followed by a title, which is expressed by any sequence of words
+ * that must not contain any keywords at start of lines.
+ * It is followed by one or more Steps.
+ * Scenarios can optionally contain comments (which are not part of the scenarios) after examples using "!--" keyword
+ * Scenario := "Scenario:"? Title? Meta? GivenStories? Step+ Examples? (Examples Comment+)? ;
+ */
+Scenario: {Scenario}
+ 'Scenario:' title=RawText? NL
+ (meta=Meta BLANK_SPACE?)?
+// (given=GivenStories BLANK_SPACE?)?
+ steps+=Step
+ (BLANK_SPACE? steps+=Step)*
+ (BLANK_SPACE? examples=Examples)?
+;
+
+/**
+ * The comma-separated list of story resources that specify the stories to be run before a story or a scenario
+ * GivenStories:= "GivenStories:" (StoryPath ','?)+ ;
+ */
+//GivenStories: {GivenStories}
+// 'GivenStories:'
+// resources+=StoryPath
+// (-> ',' BLANK_SPACE? resources+=StoryPath)*
+// NL
+//;
+
+//StoryPath: {StoryPath}
+// value=PATH
+//;
+
+/**
+ * The scenario step is a step starting work followed by any number of characters
+ * Step := StepStartingWord StepContent ;
+ */
+Step: {Step}
+ keyword=STEP_KEYWORD description=RawText NL
+ // ((BLANK_SPACE? table=Table) | (BLANK_SPACE? text=DocString))?
+;
+
+terminal STEP_KEYWORD:
+ ('Given' | 'When' | 'Then' | 'And' | 'But' | '*')
+;
+
+terminal PLACEHOLDER:
+ ('<' !('>' | ' ' | '\t' | '\n' | '\r')+ '>')
+ | ('[' !(']' | ' ' | '\t' | '\n' | '\r')+ ']')
+;
+
+/**
+ * The examples table
+ * Examples := "Examples:" ExamplesTable ;
+ */
+Examples: {Examples}
+ 'Examples:' NL
+ (BLANK_SPACE? table=Table)
+;
+
+
+@Override
+StartLiteral: ID
+ | NUMBER
+ | STRING
+ | PLACEHOLDER
+ | GLOB
+ | ANY_OTHER
+;
+
+@Override
+Literal: ID
+ | NUMBER
+ | STRING
+ | PLACEHOLDER
+ | STEP_KEYWORD
+ | GLOB
+ | ANY_OTHER
+;
+
+//PATH returns ecore::EString:
+// ('./' | '../' | '/')
+// (GLOB ('/' GLOB)* ('.' GLOB)?)?
+//;
diff --git a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/formatting2/JbehaveFormatter.xtend b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/formatting2/JbehaveFormatter.xtend
index be356e00..ac0642fc 100644
--- a/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/formatting2/JbehaveFormatter.xtend
+++ b/org.agileware.natural.jbehave/src/org/agileware/natural/jbehave/formatting2/JbehaveFormatter.xtend
@@ -4,31 +4,156 @@
package org.agileware.natural.jbehave.formatting2
import com.google.inject.Inject
-import org.agileware.natural.jbehave.jbehave.Narrative
+import org.agileware.natural.jbehave.jbehave.Examples
+import org.agileware.natural.jbehave.jbehave.JbehaveModel
+import org.agileware.natural.jbehave.jbehave.Lifecycle
+import org.agileware.natural.jbehave.jbehave.LifecycleAfter
+import org.agileware.natural.jbehave.jbehave.LifecycleAfterElement
+import org.agileware.natural.jbehave.jbehave.LifecycleBefore
+import org.agileware.natural.jbehave.jbehave.LifecycleBeforeElement
+import org.agileware.natural.jbehave.jbehave.Meta
+import org.agileware.natural.jbehave.jbehave.Scenario
+import org.agileware.natural.jbehave.jbehave.Step
import org.agileware.natural.jbehave.jbehave.Story
+import org.agileware.natural.jbehave.jbehave.StoryNarrativeA
+import org.agileware.natural.jbehave.jbehave.StoryNarrativeB
+import org.agileware.natural.jbehave.jbehave.StoryNarrativeElement
import org.agileware.natural.jbehave.services.JbehaveGrammarAccess
+import org.agileware.natural.lang.formatting2.NaturalFormatHelper
+import org.agileware.natural.lang.model.DocString
+import org.agileware.natural.lang.model.MetaElement
+import org.agileware.natural.lang.model.Table
import org.eclipse.xtext.formatting2.AbstractFormatter2
+import org.eclipse.xtext.formatting2.FormatterRequest
import org.eclipse.xtext.formatting2.IFormattableDocument
class JbehaveFormatter extends AbstractFormatter2 {
+
+ @Inject extension JbehaveGrammarAccess jbehaveGrammerAccess
+
+ @Inject NaturalFormatHelper.Factory formatHelperFactory
+
+ // TODO there must be a better way to get the current indentation level!
+ var int indentationLevel = -1
+
+ var extension NaturalFormatHelper _formatHelper = null
+
+ override protected initialize(FormatterRequest request) {
+ _formatHelper = formatHelperFactory.create(request.textRegionAccess, naturalGrammarAccess)
+ _formatHelper.initialize(request)
+
+ super.initialize(request)
+ }
+
+ def dispatch void format(JbehaveModel model, extension IFormattableDocument doc) {
+ // println(textRegionAccess)
+ model.document.format()
+ // println(doc)
+ }
+
+ def dispatch void format(Story model, extension IFormattableDocument document) {
+ model.description.format()
+ model.meta.format()
+ model.narrative.format()
+ model.lifecycle.format()
+ model.scenarios.forEach[format]
+ }
+
+ def dispatch void format(StoryNarrativeA model, extension IFormattableDocument doc) {
+ model.inOrderTo.format()
+ model.asA.format()
+ model.wantTo.format()
+ }
+
+ def dispatch void format(StoryNarrativeB model, extension IFormattableDocument doc) {
+ model.asA.format()
+ model.wantTo.format()
+ model.soThat.format()
+ }
+
+ def dispatch void format(StoryNarrativeElement model, extension IFormattableDocument doc) {
+ // TODO...
+ }
+
+ def dispatch void format(Lifecycle model, extension IFormattableDocument doc) {
+ model.before.format()
+ model.after.format()
+ }
+
+ def dispatch void format(LifecycleBefore model, extension IFormattableDocument doc) {
+ model.elements.forEach[format]
+ }
+
+ def dispatch void format(LifecycleBeforeElement model, extension IFormattableDocument doc) {
+ model.steps.forEach[format]
+ }
+
+ def dispatch void format(LifecycleAfter model, extension IFormattableDocument doc) {
+ model.elements.forEach[format]
+ }
+
+ def dispatch void format(LifecycleAfterElement model, extension IFormattableDocument doc) {
+ model.steps.forEach[format]
+ }
+
+ def dispatch void format(Scenario model, extension IFormattableDocument doc) {
+ model.meta.format()
+ // model.given.format()
+ model.steps.forEach[format]
+ model.examples.format()
+ }
+
+// def dispatch void format(GivenStories model, extension IFormattableDocument doc) {
+// model.resources.forEach[format]
+// }
+
+// def dispatch void format(StoryPath model, extension IFormattableDocument doc) {
+// // TODO...
+// }
- @Inject extension JbehaveGrammarAccess
-
- def dispatch void format(Story story, extension IFormattableDocument document) {
- // TODO: format HiddenRegions around keywords, attributes, cross references, etc.
- story.meta.format
- story.narrative.format
- for (scenario : story.scenarios) {
- scenario.format
+ def dispatch void format(Step model, extension IFormattableDocument doc) {
+ // TODO...
+ }
+
+ def dispatch void format(Examples model, extension IFormattableDocument doc) {
+ model.table.format()
+ }
+
+
+
+
+ def dispatch void format(Meta model, extension IFormattableDocument doc) {
+ model.tags.forEach[format]
+ }
+
+ def dispatch void format(MetaElement model, extension IFormattableDocument doc) {
+ // Trim leading/trailing whitespace
+ model.surround[noSpace]
+
+// if (model.value !== null) {
+// // Cleanup whitespace around value assignment
+// model.regionFor.keyword(':').prepend[noSpace].append[oneSpace]
+// model.regionFor.assignment(metaElementAccess.valueAssignment_2_1).prepend[oneSpace].append[noSpace]
+// }
+
+ // Insert newline if not present from BLANK_SPACE
+ if (model.isLast()) {
+ model.append[setNewLines(0)]
+ } else if (!model.hasTrailingBlankSpace) {
+ model.append[newLine]
}
}
- def dispatch void format(Narrative narrative, extension IFormattableDocument document) {
- // TODO: format HiddenRegions around keywords, attributes, cross references, etc.
- narrative.inOrderTo.format
- narrative.asA.format
- narrative.IWantTo.format
+ def dispatch void format(Table model, extension IFormattableDocument doc) {
+ model.rows.forEach[prepend[indent]]
+ }
+
+ def dispatch void format(DocString model, extension IFormattableDocument doc) {
+ formatMultilineText(model, docStringAccess.valueAssignment_1, indentationLevel, doc)
+ }
+
+ def dispatch boolean isLast(MetaElement model) {
+ val meta = model.eContainer as Meta
+ model == meta.tags.last
}
-
- // TODO: implement for Scenario, GivenStories, Meta, Step, Examples
}
diff --git a/org.agileware.natural.common/.classpath b/org.agileware.natural.lang.ide/.classpath
similarity index 69%
rename from org.agileware.natural.common/.classpath
rename to org.agileware.natural.lang.ide/.classpath
index e7847821..8d26fa59 100644
--- a/org.agileware.natural.common/.classpath
+++ b/org.agileware.natural.lang.ide/.classpath
@@ -1,12 +1,9 @@
-
-
-
-
-
-
+
-
+
+
+
diff --git a/org.agileware.natural.lang.ide/.project b/org.agileware.natural.lang.ide/.project
new file mode 100644
index 00000000..b95bdf0d
--- /dev/null
+++ b/org.agileware.natural.lang.ide/.project
@@ -0,0 +1,40 @@
+
+
+ org.agileware.natural.lang.ide
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/org.agileware.natural.common/.settings/org.eclipse.core.resources.prefs b/org.agileware.natural.lang.ide/.settings/org.eclipse.core.resources.prefs
similarity index 100%
rename from org.agileware.natural.common/.settings/org.eclipse.core.resources.prefs
rename to org.agileware.natural.lang.ide/.settings/org.eclipse.core.resources.prefs
diff --git a/org.agileware.natural.common/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.lang.ide/.settings/org.eclipse.jdt.core.prefs
similarity index 74%
rename from org.agileware.natural.common/.settings/org.eclipse.jdt.core.prefs
rename to org.agileware.natural.lang.ide/.settings/org.eclipse.jdt.core.prefs
index c872bd03..9f6ece88 100644
--- a/org.agileware.natural.common/.settings/org.eclipse.jdt.core.prefs
+++ b/org.agileware.natural.lang.ide/.settings/org.eclipse.jdt.core.prefs
@@ -3,8 +3,6 @@ org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.common/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.agileware.natural.lang.ide/.settings/org.eclipse.xtend.core.Xtend.prefs
similarity index 100%
rename from org.agileware.natural.common/.settings/org.eclipse.xtend.core.Xtend.prefs
rename to org.agileware.natural.lang.ide/.settings/org.eclipse.xtend.core.Xtend.prefs
diff --git a/org.agileware.natural.lang.ide/META-INF/MANIFEST.MF b/org.agileware.natural.lang.ide/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..bd51a4b2
--- /dev/null
+++ b/org.agileware.natural.lang.ide/META-INF/MANIFEST.MF
@@ -0,0 +1,26 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.agileware.natural.lang.ide
+Bundle-ManifestVersion: 2
+Bundle-Name: org.agileware.natural.lang.ide
+Bundle-Vendor: Roberto Lo Giacco
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: org.agileware.natural.lang.ide; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.agileware.natural.lang,
+ org.eclipse.xtext.ide,
+ org.eclipse.xtext.xbase.ide,
+ org.antlr.runtime;bundle-version="[3.2.0,3.2.1)"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.agileware.natural.lang.ide;uses:="com.google.inject,org.eclipse.xtext.ide",
+ org.agileware.natural.lang.ide.contentassist.antlr;
+ uses:="org.eclipse.xtext.ide.editor.contentassist.antlr,
+ org.eclipse.xtext.ide.editor.contentassist.antlr.internal,
+ org.eclipse.xtext.ide.editor.partialEditing,
+ org.agileware.natural.lang.ide.contentassist.antlr.internal,
+ org.agileware.natural.lang.services,
+ org.eclipse.xtext",
+ org.agileware.natural.lang.ide.contentassist.antlr.internal;
+ uses:="org.eclipse.xtext.ide.editor.contentassist.antlr.internal,
+ org.agileware.natural.lang.services,
+ org.antlr.runtime,
+ org.eclipse.xtext"
diff --git a/org.agileware.natural.lang.ide/build.properties b/org.agileware.natural.lang.ide/build.properties
new file mode 100644
index 00000000..5c6bbf99
--- /dev/null
+++ b/org.agileware.natural.lang.ide/build.properties
@@ -0,0 +1,6 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = .,\
+ META-INF/
+bin.excludes = **/*.xtend
diff --git a/org.agileware.natural.lang.ide/pom.xml b/org.agileware.natural.lang.ide/pom.xml
new file mode 100644
index 00000000..4ccc54fd
--- /dev/null
+++ b/org.agileware.natural.lang.ide/pom.xml
@@ -0,0 +1,155 @@
+
+ 4.0.0
+
+ org.agileware
+ natural
+ 1.0.0-SNAPSHOT
+
+ org.agileware.natural.lang.ide
+ eclipse-plugin
+
+
+
+ log4j
+ log4j
+
+
+ org.eclipse.lsp4j
+ org.eclipse.lsp4j
+
+
+ org.ow2.asm
+ asm
+
+
+ org.ow2.asm
+ asm-commons
+
+
+ org.ow2.asm
+ asm-tree
+
+
+
+
+
+ org.eclipse.xtend
+ xtend-maven-plugin
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+
+ consider
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.1
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ p2.eclipse-feature
+ ${project.build.directory}/libs
+ false
+ false
+ true
+ true
+
+ com.ibm.icu,
+ org.apache.ant,
+ org.apache.commons.lang,
+ org.apache.commons.logging,
+ org.eclipse.core.commands,
+ org.eclipse.core.contenttype,
+ org.eclipse.core.expressions,
+ org.eclipse.core.filesystem,
+ org.eclipse.core.jobs,
+ org.eclipse.core.resources,
+ org.eclipse.core.runtime,
+ org.eclipse.core.variables,
+ org.eclipse.debug.core,
+ org.eclipse.emf.codegen.ecore,
+ org.eclipse.emf.codegen,
+ org.eclipse.emf.mwe.core,
+ org.eclipse.emf.mwe.utils,
+ org.eclipse.emf.mwe2.lib,
+ org.eclipse.emf.mwe2.runtime,
+ org.eclipse.equinox.app,
+ org.eclipse.equinox.preferences,
+ org.eclipse.equinox.registry,
+ org.eclipse.jdt.core,
+ org.eclipse.jdt.debug,
+ org.eclipse.jdt.launching,
+ org.eclipse.text,
+
+
+
+
+
+
+ com.googlecode.addjars-maven-plugin
+ addjars-maven-plugin
+ 1.0.5
+
+
+ package
+
+ add-jars
+
+
+
+
+ ${project.build.directory}/libs
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ appassembler-maven-plugin
+ 2.1.0
+
+
+ package
+
+ assemble
+
+
+ ${project.build.directory}/languageserver
+ flat
+ true
+
+
+
+ mydsl-ls
+ org.eclipse.xtext.ide.server.ServerLauncher
+
+
+
+
+
+
+
+
+
+
+ 1.0.0-SNAPSHOT
+
diff --git a/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeModule.java b/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeModule.java
new file mode 100644
index 00000000..9e144eda
--- /dev/null
+++ b/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeModule.java
@@ -0,0 +1,11 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ide;
+
+
+/**
+ * Use this class to register ide components.
+ */
+public class NaturalIdeModule extends AbstractNaturalIdeModule {
+}
diff --git a/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeSetup.java b/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeSetup.java
new file mode 100644
index 00000000..ec68a58f
--- /dev/null
+++ b/org.agileware.natural.lang.ide/src/org/agileware/natural/lang/ide/NaturalIdeSetup.java
@@ -0,0 +1,22 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ide;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.agileware.natural.lang.NaturalRuntimeModule;
+import org.agileware.natural.lang.NaturalStandaloneSetup;
+import org.eclipse.xtext.util.Modules2;
+
+/**
+ * Initialization support for running Xtext languages as language servers.
+ */
+public class NaturalIdeSetup extends NaturalStandaloneSetup {
+
+ @Override
+ public Injector createInjector() {
+ return Guice.createInjector(Modules2.mixin(new NaturalRuntimeModule(), new NaturalIdeModule()));
+ }
+
+}
diff --git a/org.agileware.natural.lang.tests/.classpath b/org.agileware.natural.lang.tests/.classpath
new file mode 100644
index 00000000..3c559cfb
--- /dev/null
+++ b/org.agileware.natural.lang.tests/.classpath
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang.tests/.gitignore b/org.agileware.natural.lang.tests/.gitignore
new file mode 100644
index 00000000..e75a396d
--- /dev/null
+++ b/org.agileware.natural.lang.tests/.gitignore
@@ -0,0 +1 @@
+/test-bin/
diff --git a/org.agileware.natural.lang.tests/.project b/org.agileware.natural.lang.tests/.project
new file mode 100644
index 00000000..960c8127
--- /dev/null
+++ b/org.agileware.natural.lang.tests/.project
@@ -0,0 +1,40 @@
+
+
+ org.agileware.natural.lang.tests
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/org.agileware.natural.stepmatcher.feature/.settings/org.eclipse.core.resources.prefs b/org.agileware.natural.lang.tests/.settings/org.eclipse.core.resources.prefs
similarity index 100%
rename from org.agileware.natural.stepmatcher.feature/.settings/org.eclipse.core.resources.prefs
rename to org.agileware.natural.lang.tests/.settings/org.eclipse.core.resources.prefs
diff --git a/org.agileware.natural.lang.tests/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.lang.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..9f6ece88
--- /dev/null
+++ b/org.agileware.natural.lang.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.lang.tests/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.agileware.natural.lang.tests/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 00000000..fdf3191a
--- /dev/null
+++ b/org.agileware.natural.lang.tests/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,7 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=xtend-gen
+BuilderConfiguration.is_project_specific=true
+eclipse.preferences.version=1
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.agileware.natural.lang.tests/META-INF/MANIFEST.MF b/org.agileware.natural.lang.tests/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..f9e80353
--- /dev/null
+++ b/org.agileware.natural.lang.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.agileware.natural.lang.tests
+Bundle-ManifestVersion: 2
+Bundle-Name: org.agileware.natural.lang.tests
+Bundle-Vendor: Roberto Lo Giacco
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: org.agileware.natural.lang.tests; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.agileware.natural.lang,
+ org.agileware.natural.testing,
+ org.eclipse.xtext.testing,
+ org.eclipse.xtext.xbase.testing,
+ org.eclipse.xtext.xbase.lib;bundle-version="2.14.0"
+Import-Package: org.apache.commons.logging,
+ org.apache.log4j,
+ org.junit,
+ org.junit.runner,
+ org.junit.runner.manipulation,
+ org.junit.runner.notification,
+ org.junit.runners,
+ org.junit.runners.model
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.agileware.natural.lang.tests;x-internal=true
diff --git a/org.agileware.natural.lang.tests/build.properties b/org.agileware.natural.lang.tests/build.properties
new file mode 100644
index 00000000..5c6bbf99
--- /dev/null
+++ b/org.agileware.natural.lang.tests/build.properties
@@ -0,0 +1,6 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = .,\
+ META-INF/
+bin.excludes = **/*.xtend
diff --git a/org.agileware.natural.lang.tests/org.agileware.natural.lang.tests.launch b/org.agileware.natural.lang.tests/org.agileware.natural.lang.tests.launch
new file mode 100644
index 00000000..0bdf6da2
--- /dev/null
+++ b/org.agileware.natural.lang.tests/org.agileware.natural.lang.tests.launch
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang.tests/pom.xml b/org.agileware.natural.lang.tests/pom.xml
new file mode 100644
index 00000000..51914d85
--- /dev/null
+++ b/org.agileware.natural.lang.tests/pom.xml
@@ -0,0 +1,30 @@
+
+ 4.0.0
+
+ org.agileware
+ natural
+ 1.0.0-SNAPSHOT
+
+ org.agileware.natural.lang.tests
+ eclipse-test-plugin
+
+
+
+
+ org.eclipse.xtend
+ xtend-maven-plugin
+
+
+ org.eclipse.tycho
+ tycho-surefire-plugin
+
+ org.agileware.natural.lang.tests
+ org.agileware.natural.lang.tests.NaturalTestSuite
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalExamplesTest.xtend b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalExamplesTest.xtend
new file mode 100644
index 00000000..082027cf
--- /dev/null
+++ b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalExamplesTest.xtend
@@ -0,0 +1,134 @@
+package org.agileware.natural.lang.tests
+
+import org.agileware.natural.lang.model.NaturalModel
+import org.agileware.natural.testing.AbstractExamplesTest
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(XtextRunner)
+@InjectWith(NaturalInjectorProvider)
+class NaturalExamplesTest extends AbstractExamplesTest {
+
+ @Test
+ def void example_01() {
+ assertExampleParses('''
+ Document: Hello, Natural!
+ ''')
+ }
+
+ @Test
+ def void example_02() {
+ assertExampleParses('''
+ # language: en
+ Document: Hello, Natural!
+ ''')
+ }
+
+ @Test
+ def void example_03() {
+ assertExampleParses('''
+ Document:
+ Section: B
+
+ Section:
+ ''')
+ }
+
+ @Test
+ def void example_04() {
+ assertExampleParses('''
+ Document: Hello, Natural!
+
+ The quick brown fox
+ Jumps over the lazy dog
+ ''')
+ }
+
+ @Test
+ def void example_05() {
+ assertExampleParses('''
+ Document: Hello, Natural!
+
+ The quick brown fox
+ Jumps over the lazy dog
+ ''')
+ }
+
+ @Test
+ def void example_06() {
+ assertExampleParses('''
+ Document:
+ The quick brown fox
+
+ Jumps over the lazy dog
+ ''')
+ }
+
+ @Test
+ def void example_07() {
+ assertExampleParses('''
+ Document: Hello, Natural!
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ ''')
+ }
+
+ @Test
+ def void example_08() {
+ assertExampleParses('''
+ # language: en
+
+ Document: Hello, Natural!
+
+ Section: A
+
+ The quick brown fox
+
+ Jumps over the lazy dog
+
+
+ Section: B
+
+ The quick brown fox
+
+ Jumps over the lazy dog
+
+ Section: A B
+ The quick brown fox
+
+ Jumps over the lazy dog
+
+ ''')
+ }
+
+ @Test
+ def void example_09() {
+ assertExampleParses('''
+ # language: en
+ @version:1
+ Document: Hello, Natural!
+
+ @foo
+ @bar
+ Section: A
+
+ @foo @bar
+
+ Section: B
+ ''')
+ }
+
+ @Test
+ def void example_10() {
+ assertExampleParses('''
+ Document: Hello, ASCII Punctuation!
+ ,./;'[]\-=
+ <>?:"{}|_+
+ !@$%^&*()`~
+ ''')
+ }
+}
diff --git a/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalFormatterTest.xtend b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalFormatterTest.xtend
new file mode 100644
index 00000000..1c5ceebb
--- /dev/null
+++ b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalFormatterTest.xtend
@@ -0,0 +1,402 @@
+package org.agileware.natural.lang.tests
+
+import org.agileware.natural.lang.model.NaturalModel
+import org.agileware.natural.testing.AbstractFormatterTest
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.eclipse.xtext.formatting2.FormatterPreferenceKeys
+
+@RunWith(XtextRunner)
+@InjectWith(NaturalInjectorProvider)
+class NaturalFormatterTest extends AbstractFormatterTest {
+
+ @Test
+ def void cleanupTitleText() {
+ val toBeFormatted = '''
+ # language: en
+ Document: Hello, Natural Formatter !
+
+ Section: A
+
+ Section:
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document: Hello, Natural Formatter !
+
+ Section: A
+
+ Section:
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentNarrative_01() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted)
+ }
+
+ @Test
+ def void indentNarrative_02() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentNarrative_03() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ * 1
+ * 1.1
+ * 1.2
+ * 2
+ * 2.1
+ '''
+ assertFormatted(toBeFormatted)
+ }
+
+ @Test
+ def void indentNarrative_04() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ * 1
+ * 1.1
+ * 1.2
+ * 2
+ * 2.1
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ * 1
+ * 1.1
+ * 1.2
+ * 2
+ * 2.1
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentNarrative_05() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ 1)
+ * 1.1
+ * 1.2
+
+ 2)
+ * 2.1
+ * 2.2
+
+ 3)
+ * 3.1
+ * 3.2
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ 1)
+ * 1.1
+ * 1.2
+
+ 2)
+ * 2.1
+ * 2.2
+
+ 3)
+ * 3.1
+ * 3.2
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentNarrative_06() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ | a | 0 |
+ | b | 1 |
+
+ """
+ ,./;'[]\-=
+ <>?:"{}|_+
+ !@#$%^&*()`~
+ """
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ | a | 0 |
+ | b | 1 |
+
+ """
+ ,./;'[]\-=
+ <>?:"{}|_+
+ !@#$%^&*()`~
+ """
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentSections_01() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Section:
+ The quick brown fox
+
+ Section:
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted)
+ }
+
+ @Test
+ def void indentSections_02() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Section:
+ The quick brown fox
+
+ Section:
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Section:
+ The quick brown fox
+
+ Section:
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void indentSections_03() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ @foo
+ Section: A
+
+ @foo
+ @bar
+ Section: B
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ @foo
+ Section: A
+
+ @foo
+ @bar
+ Section: B
+ The quick brown fox
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void adjustBlockSpacing_01() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+ The quick brown fox
+ Jumps over the lazy dog
+ Section:
+ The quick brown fox
+
+ Section:
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Section:
+ The quick brown fox
+
+ Section:
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void adjustBlockSpacing_02() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+
+
+
+ Section:
+
+
+ The quick brown fox
+
+ Section:
+
+
+
+ Jumps over the lazy dog
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ The quick brown fox
+ Jumps over the lazy dog
+
+ Section:
+
+ The quick brown fox
+
+ Section:
+
+ Jumps over the lazy dog
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void cleanupMetaTags_01() {
+ val toBeFormatted = '''
+ # language: en
+ @foo @bar
+
+ @foobar
+ Document:
+ '''
+ val expectation = '''
+ # language: en
+ @foo
+ @bar
+ @foobar
+ Document:
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+ @Test
+ def void cleanupMetaTags_02() {
+ val toBeFormatted = '''
+ # language: en
+ Document:
+
+ @foo @bar
+
+ @foobar
+ Section:
+ The quick brown fox
+ '''
+ val expectation = '''
+ # language: en
+ Document:
+
+ @foo
+ @bar
+ @foobar
+ Section:
+ The quick brown fox
+ '''
+ assertFormatted(toBeFormatted, expectation)
+ }
+
+// TODO add support for user indentation preferences
+// @Test
+// def void indentWithSpaces_01() {
+// formatterTestHelper.assertFormatted[
+// preferences[ put(FormatterPreferenceKeys.indentation, " ") ]
+// toBeFormatted = '''
+// # language: en
+// Document:
+//
+// The quick brown fox
+// Jumps over the lazy dog
+// '''
+// expectation = '''
+// # language: en
+// Document:
+//
+// The quick brown fox
+// Jumps over the lazy dog
+// '''
+// ]
+// }
+}
diff --git a/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalParsingTest.xtend b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalParsingTest.xtend
new file mode 100644
index 00000000..20c4890f
--- /dev/null
+++ b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalParsingTest.xtend
@@ -0,0 +1,174 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.tests
+
+import com.google.inject.Inject
+import org.agileware.natural.lang.model.DocString
+import org.agileware.natural.lang.model.NaturalModel
+import org.agileware.natural.lang.model.Table
+import org.agileware.natural.lang.model.Paragraph
+import org.agileware.natural.lang.serializer.NaturalSerializer
+import org.agileware.natural.testing.AbstractExamplesTest
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.XtextRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import static org.hamcrest.MatcherAssert.*
+import static org.hamcrest.Matchers.*
+
+@RunWith(XtextRunner)
+@InjectWith(NaturalInjectorProvider)
+class NaturalParsingTest extends AbstractExamplesTest {
+
+ @Inject extension NaturalSerializer
+
+ @Test
+ def void documentWithTitle() {
+
+ val model = parse('''
+ # language: en
+ Document: Hello, Natural!
+ ''')
+
+ assertThat(model, notNullValue())
+ assertThat(validate(model), empty())
+
+ val doc = model.document
+ assertThat(doc.sections, hasSize(0))
+ assertThat(doc, notNullValue())
+ assertThat(doc.title, equalTo("Hello, Natural!"))
+ }
+
+ @Test
+ def void simpleDocumentNarrative() {
+
+ val model = parse('''
+ # language: en
+ Document:
+ The quick brown fox
+ Jumps over the lazy dog
+ ''')
+
+ assertThat(model, notNullValue())
+ assertThat(validate(model), empty())
+
+ val doc = model.document
+ assertThat(doc, notNullValue())
+ assertThat(doc.narrative, notNullValue())
+ assertThat(doc.narrative.sections, hasSize(1))
+
+ val p1 = doc.narrative.sections.get(0) as Paragraph
+ assertThat(serialize(p1), equalToIgnoringWhiteSpace('''
+ The quick brown fox
+ Jumps over the lazy dog
+ '''))
+ }
+
+ @Test
+ def void complexDocumentNarrative() {
+ val model = parse('''
+ # language: en
+ Document:
+ """
+ At -9.8 m/s^2
+ """
+
+ | x | y |
+ | a | 0 |
+ | b | 1 |
+
+ 田中さんにあげて下さい
+ パーティーへ行かないか
+ ''')
+
+ assertThat(model, notNullValue())
+ assertThat(validate(model), empty())
+
+ val doc = model.document
+ assertThat(doc, notNullValue())
+
+ assertThat(doc.narrative, notNullValue())
+ assertThat(doc.narrative.sections, hasSize(3))
+
+ val b1 = doc.narrative.sections.get(0) as DocString
+ assertThat(b1.value, equalToIgnoringWhiteSpace('''
+ """
+ At -9.8 m/s^2
+ """
+ '''))
+
+ val b2 = doc.narrative.sections.get(1) as Table
+ assertThat(serialize(b2), equalToIgnoringWhiteSpace('''
+ | x | y |
+ | a | 0 |
+ | b | 1 |
+ '''))
+
+ val b3 = doc.narrative.sections.get(2) as Paragraph
+ assertThat(serialize(b3), equalToIgnoringWhiteSpace('''
+ 田中さんにあげて下さい
+ パーティーへ行かないか
+ '''))
+ }
+
+ @Test
+ def void parseMetaData() {
+ val model = parse('''
+ # language: en
+ @foo @bar
+ @version:v1
+ @release:2.0
+ Document:
+ ''')
+
+ assertThat(model, notNullValue())
+ assertThat(validate(model), empty())
+
+ val doc = model.document
+ assertThat(doc, notNullValue())
+ assertThat(doc.meta, notNullValue())
+ assertThat(doc.meta.tags, hasSize(4))
+ }
+
+ @Test
+ def void multipleSectionsWithMetaTags() {
+ val model = parse('''
+ # language: en
+ # @title: Hello, World!
+ Document:
+ The quick brown fox
+ Jumps over the lazy dog
+
+ @foo
+ @bar
+ Section: A
+
+ @foo @bar
+
+ Section: B
+ ''')
+
+ assertThat(model, notNullValue())
+ assertThat(validate(model), empty())
+
+ val doc = model.document
+ assertThat(doc, notNullValue())
+ assertThat(doc.title, nullValue())
+ assertThat(doc.sections, hasSize(2))
+ // TODO
+ // assertThat(doc.meta.tags, hasSize(1))
+ // assertThat(doc.meta.tags.get(0).value, equalTo("@title: Hello, Meta Tags!"))
+ assertThat(doc.narrative, notNullValue())
+ assertThat(doc.narrative.sections, hasSize(1))
+
+ val p1 = doc.narrative.sections.get(0) as Paragraph
+ assertThat(serialize(p1), equalToIgnoringWhiteSpace('''
+ The quick brown fox
+ Jumps over the lazy dog
+ '''))
+ assertThat(doc.sections.get(0).meta.tags, hasSize(2))
+ assertThat(doc.sections.get(1).meta.tags, hasSize(2))
+ }
+}
diff --git a/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalTestSuite.java b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalTestSuite.java
new file mode 100644
index 00000000..52b63398
--- /dev/null
+++ b/org.agileware.natural.lang.tests/src/org/agileware/natural/lang/tests/NaturalTestSuite.java
@@ -0,0 +1,8 @@
+package org.agileware.natural.lang.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({ NaturalExamplesTest.class, NaturalParsingTest.class, NaturalFormatterTest.class })
+public class NaturalTestSuite {}
diff --git a/org.agileware.natural.lang.ui.tests/.classpath b/org.agileware.natural.lang.ui.tests/.classpath
new file mode 100644
index 00000000..5cc10f4e
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/.classpath
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang.ui.tests/.project b/org.agileware.natural.lang.ui.tests/.project
new file mode 100644
index 00000000..5d05dc79
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/.project
@@ -0,0 +1,40 @@
+
+
+ org.agileware.natural.lang.ui.tests
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.core.resources.prefs b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..99f26c02
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..9f6ece88
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 00000000..fdf3191a
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,7 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=xtend-gen
+BuilderConfiguration.is_project_specific=true
+eclipse.preferences.version=1
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.agileware.natural.lang.ui.tests/META-INF/MANIFEST.MF b/org.agileware.natural.lang.ui.tests/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..40d4784c
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.agileware.natural.lang.ui.tests
+Bundle-ManifestVersion: 2
+Bundle-Name: org.agileware.natural.lang.ui.tests
+Bundle-Vendor: Roberto Lo Giacco
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: org.agileware.natural.lang.ui.tests; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.agileware.natural.lang.ui,
+ org.junit;bundle-version="4.12.0",
+ org.eclipse.xtext.testing,
+ org.eclipse.xtext.xbase.testing,
+ org.eclipse.xtext.junit4,
+ org.eclipse.xtext.xbase.junit,
+ org.eclipse.core.runtime,
+ org.eclipse.xtext.ui.testing,
+ org.eclipse.ui.workbench;resolution:=optional
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.agileware.natural.lang.ui.tests;x-internal=true
diff --git a/org.agileware.natural.lang.ui.tests/build.properties b/org.agileware.natural.lang.ui.tests/build.properties
new file mode 100644
index 00000000..5c6bbf99
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/build.properties
@@ -0,0 +1,6 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = .,\
+ META-INF/
+bin.excludes = **/*.xtend
diff --git a/org.agileware.natural.lang.ui.tests/pom.xml b/org.agileware.natural.lang.ui.tests/pom.xml
new file mode 100644
index 00000000..5f1b881a
--- /dev/null
+++ b/org.agileware.natural.lang.ui.tests/pom.xml
@@ -0,0 +1,29 @@
+
+ 4.0.0
+
+ org.agileware
+ natural
+ 1.0.0-SNAPSHOT
+
+ org.agileware.natural.lang.ui.tests
+ eclipse-test-plugin
+
+
+
+
+ org.eclipse.xtend
+ xtend-maven-plugin
+
+
+ org.eclipse.tycho
+ tycho-surefire-plugin
+
+ true
+
+
+
+
+
+ 1.0.0-SNAPSHOT
+
diff --git a/org.agileware.natural.lang.ui/.classpath b/org.agileware.natural.lang.ui/.classpath
new file mode 100644
index 00000000..8d26fa59
--- /dev/null
+++ b/org.agileware.natural.lang.ui/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang.ui/.project b/org.agileware.natural.lang.ui/.project
new file mode 100644
index 00000000..2da58228
--- /dev/null
+++ b/org.agileware.natural.lang.ui/.project
@@ -0,0 +1,40 @@
+
+
+ org.agileware.natural.lang.ui
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/org.agileware.natural.lang.ui/.settings/org.eclipse.core.resources.prefs b/org.agileware.natural.lang.ui/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..99f26c02
--- /dev/null
+++ b/org.agileware.natural.lang.ui/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.agileware.natural.lang.ui/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.lang.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..9f6ece88
--- /dev/null
+++ b/org.agileware.natural.lang.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.lang.ui/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.agileware.natural.lang.ui/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 00000000..fdf3191a
--- /dev/null
+++ b/org.agileware.natural.lang.ui/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,7 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=xtend-gen
+BuilderConfiguration.is_project_specific=true
+eclipse.preferences.version=1
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.agileware.natural.lang.ui/META-INF/MANIFEST.MF b/org.agileware.natural.lang.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..78ef215e
--- /dev/null
+++ b/org.agileware.natural.lang.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.agileware.natural.lang.ui
+Bundle-ManifestVersion: 2
+Bundle-Name: org.agileware.natural.lang.ui
+Bundle-Vendor: Roberto Lo Giacco
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: org.agileware.natural.lang.ui; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.agileware.natural.lang,
+ org.agileware.natural.lang.ide,
+ org.eclipse.xtext.ui,
+ org.eclipse.xtext.ui.shared,
+ org.eclipse.xtext.ui.codetemplates.ui,
+ org.eclipse.ui.editors;bundle-version="3.5.0",
+ org.eclipse.ui.ide;bundle-version="3.5.0",
+ org.eclipse.ui,
+ org.eclipse.compare,
+ org.eclipse.xtext.builder
+Import-Package: org.apache.log4j
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.agileware.natural.lang.ui.quickfix,
+ org.agileware.natural.lang.ui.contentassist,
+ org.agileware.natural.lang.ui.internal
+Bundle-Activator: org.agileware.natural.lang.ui.internal.LangActivator
diff --git a/org.agileware.natural.lang.ui/build.properties b/org.agileware.natural.lang.ui/build.properties
new file mode 100644
index 00000000..323f56c5
--- /dev/null
+++ b/org.agileware.natural.lang.ui/build.properties
@@ -0,0 +1,7 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = .,\
+ META-INF/,\
+ plugin.xml
+bin.excludes = **/*.xtend
diff --git a/org.agileware.natural.lang.ui/plugin.xml b/org.agileware.natural.lang.ui/plugin.xml
new file mode 100644
index 00000000..20dc2e02
--- /dev/null
+++ b/org.agileware.natural.lang.ui/plugin.xml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.stepmatcher.feature/pom.xml b/org.agileware.natural.lang.ui/pom.xml
similarity index 56%
rename from org.agileware.natural.stepmatcher.feature/pom.xml
rename to org.agileware.natural.lang.ui/pom.xml
index 5f317f56..5a31cca6 100644
--- a/org.agileware.natural.stepmatcher.feature/pom.xml
+++ b/org.agileware.natural.lang.ui/pom.xml
@@ -6,10 +6,18 @@
natural
1.0.0-SNAPSHOT
- org.agileware.natural.stepmatcher.feature
- eclipse-feature
+ org.agileware.natural.lang.ui
+ eclipse-plugin
+ 1.0.0-SNAPSHOT
+
+
+
+ org.eclipse.xtend
+ xtend-maven-plugin
+
+
+
-
-
+
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/NaturalUiModule.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/NaturalUiModule.java
new file mode 100644
index 00000000..99d95ffc
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/NaturalUiModule.java
@@ -0,0 +1,16 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * Use this class to register components to be used within the Eclipse IDE.
+ */
+public class NaturalUiModule extends AbstractNaturalUiModule {
+
+ public NaturalUiModule(AbstractUIPlugin plugin) {
+ super(plugin);
+ }
+}
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/contentassist/NaturalProposalProvider.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/contentassist/NaturalProposalProvider.java
new file mode 100644
index 00000000..f6d8fa55
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/contentassist/NaturalProposalProvider.java
@@ -0,0 +1,12 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui.contentassist;
+
+
+/**
+ * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#content-assist
+ * on how to customize the content assistant.
+ */
+public class NaturalProposalProvider extends AbstractNaturalProposalProvider {
+}
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalDescriptionLabelProvider.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalDescriptionLabelProvider.java
new file mode 100644
index 00000000..0f84e3f6
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalDescriptionLabelProvider.java
@@ -0,0 +1,25 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui.labeling;
+
+import org.eclipse.xtext.ui.label.DefaultDescriptionLabelProvider;
+
+/**
+ * Provides labels for IEObjectDescriptions and IResourceDescriptions.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#label-provider
+ */
+public class NaturalDescriptionLabelProvider extends DefaultDescriptionLabelProvider {
+
+ // Labels and icons can be computed like this:
+// @Override
+// public String text(IEObjectDescription ele) {
+// return ele.getName().toString();
+// }
+//
+// @Override
+// public String image(IEObjectDescription ele) {
+// return ele.getEClass().getName() + ".gif";
+// }
+}
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalLabelProvider.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalLabelProvider.java
new file mode 100644
index 00000000..320ff093
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/labeling/NaturalLabelProvider.java
@@ -0,0 +1,31 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui.labeling;
+
+import com.google.inject.Inject;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider;
+
+/**
+ * Provides labels for EObjects.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#label-provider
+ */
+public class NaturalLabelProvider extends DefaultEObjectLabelProvider {
+
+ @Inject
+ public NaturalLabelProvider(AdapterFactoryLabelProvider delegate) {
+ super(delegate);
+ }
+
+ // Labels and icons can be computed like this:
+
+// String text(Greeting ele) {
+// return "A greeting to " + ele.getName();
+// }
+//
+// String image(Greeting ele) {
+// return "Greeting.gif";
+// }
+}
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/outline/NaturalOutlineTreeProvider.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/outline/NaturalOutlineTreeProvider.java
new file mode 100644
index 00000000..9688fdd6
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/outline/NaturalOutlineTreeProvider.java
@@ -0,0 +1,15 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui.outline;
+
+import org.eclipse.xtext.ui.editor.outline.impl.DefaultOutlineTreeProvider;
+
+/**
+ * Customization of the default outline structure.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#outline
+ */
+public class NaturalOutlineTreeProvider extends DefaultOutlineTreeProvider {
+
+}
diff --git a/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/quickfix/NaturalQuickfixProvider.java b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/quickfix/NaturalQuickfixProvider.java
new file mode 100644
index 00000000..1e189ab9
--- /dev/null
+++ b/org.agileware.natural.lang.ui/src/org/agileware/natural/lang/ui/quickfix/NaturalQuickfixProvider.java
@@ -0,0 +1,26 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.ui.quickfix;
+
+import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider;
+
+/**
+ * Custom quickfixes.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes
+ */
+public class NaturalQuickfixProvider extends DefaultQuickfixProvider {
+
+// @Fix(NaturalValidator.INVALID_NAME)
+// public void capitalizeName(final Issue issue, IssueResolutionAcceptor acceptor) {
+// acceptor.accept(issue, "Capitalize name", "Capitalize the name.", "upcase.png", new IModification() {
+// public void apply(IModificationContext context) throws BadLocationException {
+// IXtextDocument xtextDocument = context.getXtextDocument();
+// String firstLetter = xtextDocument.get(issue.getOffset(), 1);
+// xtextDocument.replace(issue.getOffset(), 1, firstLetter.toUpperCase());
+// }
+// });
+// }
+
+}
diff --git a/org.agileware.natural.lang/.classpath b/org.agileware.natural.lang/.classpath
new file mode 100644
index 00000000..8d26fa59
--- /dev/null
+++ b/org.agileware.natural.lang/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.common/.project b/org.agileware.natural.lang/.project
similarity index 95%
rename from org.agileware.natural.common/.project
rename to org.agileware.natural.lang/.project
index 4cad5653..dfb2951c 100644
--- a/org.agileware.natural.common/.project
+++ b/org.agileware.natural.lang/.project
@@ -1,6 +1,6 @@
- org.agileware.natural.common
+ org.agileware.natural.lang
@@ -32,9 +32,9 @@
- org.eclipse.pde.PluginNature
- org.eclipse.jdt.core.javanature
org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
org.eclipse.m2e.core.maven2Nature
diff --git a/org.agileware.natural.lang/.settings/org.eclipse.core.resources.prefs b/org.agileware.natural.lang/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..99f26c02
--- /dev/null
+++ b/org.agileware.natural.lang/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/org.agileware.natural.lang/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.lang/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..9f6ece88
--- /dev/null
+++ b/org.agileware.natural.lang/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.lang/.settings/org.eclipse.pde.core.prefs b/org.agileware.natural.lang/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 00000000..923c37fb
--- /dev/null
+++ b/org.agileware.natural.lang/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+resolve.requirebundle=false
diff --git a/org.agileware.natural.lang/.settings/org.eclipse.xtend.core.Xtend.prefs b/org.agileware.natural.lang/.settings/org.eclipse.xtend.core.Xtend.prefs
new file mode 100644
index 00000000..fdf3191a
--- /dev/null
+++ b/org.agileware.natural.lang/.settings/org.eclipse.xtend.core.Xtend.prefs
@@ -0,0 +1,7 @@
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/main/java.directory=xtend-gen
+//outlet.DEFAULT_OUTPUT.sourceFolder.src/test/java.directory=xtend-gen
+BuilderConfiguration.is_project_specific=true
+eclipse.preferences.version=1
+outlet.DEFAULT_OUTPUT.hideLocalSyntheticVariables=true
+outlet.DEFAULT_OUTPUT.installDslAsPrimarySource=false
+outlet.DEFAULT_OUTPUT.userOutputPerSourceFolder=true
diff --git a/org.agileware.natural.lang/Generate Natural Language Infrastructure.launch b/org.agileware.natural.lang/Generate Natural Language Infrastructure.launch
new file mode 100644
index 00000000..b16ec578
--- /dev/null
+++ b/org.agileware.natural.lang/Generate Natural Language Infrastructure.launch
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/META-INF/MANIFEST.MF b/org.agileware.natural.lang/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..7985be1d
--- /dev/null
+++ b/org.agileware.natural.lang/META-INF/MANIFEST.MF
@@ -0,0 +1,54 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: org.agileware.natural.lang
+Bundle-ManifestVersion: 2
+Bundle-Name: org.agileware.natural.lang
+Bundle-Vendor: Roberto Lo Giacco
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: org.agileware.natural.lang; singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.eclipse.xtext,
+ org.eclipse.xtext.xbase,
+ org.eclipse.equinox.common;bundle-version="3.5.0",
+ org.eclipse.emf.ecore,
+ org.eclipse.xtext.xbase.lib;bundle-version="2.14.0",
+ org.eclipse.xtext.util,
+ org.eclipse.emf.common,
+ org.antlr.runtime;bundle-version="[3.2.0,3.2.1)"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.agileware.natural.lang;uses:="com.google.inject,org.eclipse.xtext.service,org.eclipse.xtext",
+ org.agileware.natural.lang.formatting2;
+ uses:="org.eclipse.emf.ecore,
+ org.agileware.natural.lang.model,
+ org.eclipse.xtext.formatting2.regionaccess,
+ org.eclipse.xtext.formatting2.regionaccess.internal,
+ org.agileware.natural.lang.services,
+ org.eclipse.xtext.xbase.lib,
+ org.eclipse.xtext.formatting2,
+ org.eclipse.xtext",
+ org.agileware.natural.lang.generator;uses:="org.eclipse.xtext.generator,org.eclipse.emf.ecore.resource",
+ org.agileware.natural.lang.model;uses:="org.eclipse.emf.ecore,org.eclipse.emf.common.util",
+ org.agileware.natural.lang.model.impl;
+ uses:="org.eclipse.emf.ecore,
+ org.eclipse.emf.ecore.impl,
+ org.eclipse.emf.common.util,
+ org.agileware.natural.lang.model,
+ org.eclipse.emf.common.notify",
+ org.agileware.natural.lang.model.util;
+ uses:="org.eclipse.emf.ecore,
+ org.agileware.natural.lang.model,
+ org.eclipse.emf.common.notify,
+ org.eclipse.emf.common.notify.impl,
+ org.eclipse.emf.ecore.util",
+ org.agileware.natural.lang.parser.antlr;uses:="org.eclipse.xtext.parser.antlr,org.agileware.natural.lang.services,org.agileware.natural.lang.parser.antlr.internal",
+ org.agileware.natural.lang.parser.antlr.internal;
+ uses:="org.eclipse.emf.ecore,
+ org.eclipse.xtext.parser.antlr,
+ org.agileware.natural.lang.services,
+ org.antlr.runtime",
+ org.agileware.natural.lang.scoping;uses:="org.eclipse.xtext.scoping.impl",
+ org.agileware.natural.lang.serializer;uses:="org.agileware.natural.lang.model",
+ org.agileware.natural.lang.services;uses:="org.eclipse.xtext.service,org.eclipse.xtext",
+ org.agileware.natural.lang.text;uses:="org.eclipse.xtext.conversion,org.eclipse.xtext.nodemodel,org.eclipse.xtext.conversion.impl",
+ org.agileware.natural.lang.validation;uses:="org.eclipse.xtext.util,org.eclipse.xtext.validation"
+Import-Package: org.apache.commons.lang;version="2.6.0",
+ org.apache.log4j
diff --git a/org.agileware.natural.lang/README.md b/org.agileware.natural.lang/README.md
new file mode 100644
index 00000000..65b887de
--- /dev/null
+++ b/org.agileware.natural.lang/README.md
@@ -0,0 +1,5 @@
+# org.agileware.natural.lang
+
+Core language support for Cucumber and Jbehave modules
+
+![Natural AST](natural.model.jpg)
diff --git a/org.agileware.natural.lang/build.properties b/org.agileware.natural.lang/build.properties
new file mode 100644
index 00000000..18d540bf
--- /dev/null
+++ b/org.agileware.natural.lang/build.properties
@@ -0,0 +1,20 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = model/generated/,\
+ .,\
+ META-INF/,\
+ plugin.xml
+bin.excludes = **/*.mwe2,\
+ **/*.xtend
+additional.bundles = org.eclipse.xtext.xbase,\
+ org.eclipse.xtext.common.types,\
+ org.eclipse.xtext.xtext.generator,\
+ org.eclipse.emf.codegen.ecore,\
+ org.eclipse.emf.mwe.utils,\
+ org.eclipse.emf.mwe2.launch,\
+ org.eclipse.emf.mwe2.lib,\
+ org.objectweb.asm,\
+ org.apache.commons.logging,\
+ org.apache.log4j,\
+ com.ibm.icu
diff --git a/org.agileware.natural.lang/model/generated/Natural.ecore b/org.agileware.natural.lang/model/generated/Natural.ecore
new file mode 100644
index 00000000..5501b9f1
--- /dev/null
+++ b/org.agileware.natural.lang/model/generated/Natural.ecore
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/model/generated/Natural.genmodel b/org.agileware.natural.lang/model/generated/Natural.genmodel
new file mode 100644
index 00000000..7db260e0
--- /dev/null
+++ b/org.agileware.natural.lang/model/generated/Natural.genmodel
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/model/representations.aird b/org.agileware.natural.lang/model/representations.aird
new file mode 100644
index 00000000..e07bebbd
--- /dev/null
+++ b/org.agileware.natural.lang/model/representations.aird
@@ -0,0 +1,722 @@
+
+
+
+ generated/Natural.ecore
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KEEP_LOCATION
+ KEEP_SIZE
+ KEEP_RATIO
+
+
+
+
+
+
+
+
+ KEEP_LOCATION
+ KEEP_SIZE
+ KEEP_RATIO
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ labelSize
+
+
+ labelSize
+
+
+
+
+
+
+
+
+
+
+ italic
+
+
+
+
+
+
+
+
+
+
+
+ italic
+
+
+
+
+
+
+
+
+
+
+
+ italic
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/natural.model.jpg b/org.agileware.natural.lang/natural.model.jpg
new file mode 100644
index 00000000..9bb1fe04
Binary files /dev/null and b/org.agileware.natural.lang/natural.model.jpg differ
diff --git a/org.agileware.natural.lang/plugin.xml b/org.agileware.natural.lang/plugin.xml
new file mode 100644
index 00000000..96a07481
--- /dev/null
+++ b/org.agileware.natural.lang/plugin.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/pom.xml b/org.agileware.natural.lang/pom.xml
new file mode 100644
index 00000000..dba27879
--- /dev/null
+++ b/org.agileware.natural.lang/pom.xml
@@ -0,0 +1,136 @@
+
+ 4.0.0
+
+ org.agileware
+ natural
+ 1.0.0-SNAPSHOT
+
+ org.agileware.natural.lang
+ eclipse-plugin
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+ mwe2Launcher
+ generate-sources
+
+ java
+
+
+
+
+ org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher
+
+ /${project.basedir}/src/org/agileware/natural/lang/GenerateNatural.mwe2
+ -p
+ rootPath=/${project.basedir}/..
+
+ compile
+ true
+ false
+
+
+
+ org.eclipse.emf
+ org.eclipse.emf.mwe2.launch
+ ${mwe2.version}
+
+
+ org.eclipse.xtext
+ org.eclipse.xtext.common.types
+ ${xtext.version}
+
+
+ org.eclipse.xtext
+ org.eclipse.xtext.xtext.generator
+ ${xtext.version}
+
+
+ org.eclipse.xtext
+ org.eclipse.xtext.xbase
+ ${xtext.version}
+
+
+ org.eclipse.xtext
+ xtext-antlr-generator
+ 2.1.1
+
+
+
+
+ org.eclipse.xtend
+ xtend-maven-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+
+
+
+ ${basedir}/../org.agileware.natural.lang/src-gen/
+
+ **/*
+
+
+
+ ${basedir}/../org.agileware.natural.lang.tests/src-gen/
+
+ **/*
+
+
+
+ ${basedir}/../org.agileware.natural.lang.ide/src-gen/
+
+ **/*
+
+
+
+ ${basedir}/model/generated/
+
+
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+
+ org.codehaus.mojo
+
+
+ exec-maven-plugin
+
+
+ [1.2.1,)
+
+
+ java
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/GenerateNatural.mwe2 b/org.agileware.natural.lang/src/org/agileware/natural/lang/GenerateNatural.mwe2
new file mode 100644
index 00000000..0f9e05b8
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/GenerateNatural.mwe2
@@ -0,0 +1,62 @@
+module org.agileware.natural.lang.GenerateNatural
+
+import org.eclipse.xtext.xtext.generator.*
+import org.eclipse.xtext.xtext.generator.model.project.*
+import org.eclipse.emf.mwe.utils.*
+
+var rootPath = ".."
+
+Workflow {
+
+ component = XtextGenerator {
+ configuration = {
+ project = StandardProjectConfig {
+ baseName = "org.agileware.natural.lang"
+ rootPath = rootPath
+ runtimeTest = {
+ enabled = true
+ }
+ eclipsePlugin = {
+ enabled = true
+ }
+ eclipsePluginTest = {
+ enabled = true
+ }
+ createEclipseMetaData = true
+ }
+ code = {
+ encoding = "UTF-8"
+ lineDelimiter = "\n"
+ fileHeader = "/*\n * generated by Xtext \${version}\n */"
+ preferXtendStubs = false
+ }
+ }
+ language = StandardLanguage {
+ name = "org.agileware.natural.lang.Natural"
+ fileExtensions = "natural"
+ serializer = {
+ generateStub = true
+ }
+ validator = {
+ // composedCheck = "org.eclipse.xtext.validation.NamesAreUniqueValidator"
+ // Generates checks for @Deprecated grammar annotations, an IssueProvider and a corresponding PropertyPage
+ generateDeprecationValidation = true
+ }
+ formatter = {
+ generateStub = true
+ generateXtendStub = true
+ }
+ generator = {
+ generateStub = true
+ generateXtendStub = true
+ }
+ parserGenerator = {
+ debugGrammar = true
+ options = auto-inject {
+ classSplitting = true
+ }
+ }
+ }
+
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/Natural.xtext b/org.agileware.natural.lang/src/org/agileware/natural/lang/Natural.xtext
new file mode 100644
index 00000000..8ec5cefa
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/Natural.xtext
@@ -0,0 +1,246 @@
+grammar org.agileware.natural.lang.Natural hidden(WS, SL_COMMENT)
+
+import "http://www.eclipse.org/emf/2002/Ecore" as ecore
+generate model "http://www.agileware.org/natural/lang"
+
+/**
+ *
+ */
+NaturalModel: {NaturalModel}
+ document=Document?
+;
+
+/**
+ *
+ */
+Document: {Document}
+ BLANK_SPACE?
+ (meta=Meta BLANK_SPACE?)?
+ 'Document:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+ (BLANK_SPACE? sections+=Section)*
+ BLANK_SPACE?
+;
+
+/**
+ *
+ */
+Section: {Section}
+ (meta=Meta BLANK_SPACE?)?
+ 'Section:' title=RawText? NL
+ (BLANK_SPACE? narrative=Narrative)?
+;
+
+// --------------------------------------
+// Meta Tags
+// --------------------------------------
+
+/**
+ *
+ */
+Meta: {Meta}
+ tags+=MetaElement
+ (BLANK_SPACE? tags+=MetaElement)*
+ NL
+;
+
+/**
+ *
+ */
+MetaElement: {MetaElement}
+ id=TAG
+// '@' => id=ID => (':' value=RawText)?
+;
+
+terminal TAG:
+ '@' !(' ' | '\t' | '\n' | '\r')+
+;
+
+
+/**
+ *
+ */
+Narrative: {Narrative}
+ sections+=Block
+ (NL BLANK_SPACE? sections+=Block)*
+;
+
+// --------------------------------------
+// Text Blocks
+// --------------------------------------
+
+/**
+ *
+ */
+Block: Paragraph
+ | DocString
+ | Table
+;
+
+/**
+ *
+ */
+Paragraph: {Paragraph}
+ value=RawTextBlock
+ NL
+;
+
+/**
+ *
+ */
+DocString: {DocString}
+ value=DOC_STRING_LITERAL
+ NL
+;
+
+terminal DOC_STRING_LITERAL:
+ ('"""'->'"""')
+ | ("'''"->"'''")
+;
+
+/**
+ *
+ */
+Table: {Table}
+ rows+=TableRow+
+;
+
+/**
+ *
+ */
+TableRow: {TableRow}
+ cols+=TableCol+ '|' NL
+;
+
+/**
+ *
+ */
+TableCol: {TableCol}
+ value=TABLE_CELL
+;
+
+terminal TABLE_CELL:
+ '|' !('|' | '\n' | '\r')*
+;
+
+// --------------------------------------
+// Text Literals
+// --------------------------------------
+
+/**
+ * Consumes all text literals. This SHOULD be assigned after a start literal or keyword
+ * In the production rules.
+ */
+RawText returns ecore::EString:
+ Literal+
+;
+
+/**
+ * Consumes all text literals, including a single newline prior to another line
+ * of text. Each line MUST not start with any special keywords. All text literals
+ * are consumed until multiple newlines, or a keyword starting a new Block is
+ * encoutered in the model rules.
+ */
+RawTextBlock returns ecore::EString:
+ StartLiteral Literal*
+ (NL StartLiteral Literal*)*
+;
+
+StartLiteral: ID
+ | NUMBER
+ | STRING
+ | GLOB
+ | ANY_OTHER
+;
+
+Literal: ID
+ | NUMBER
+ | STRING
+ | GLOB
+ | ANY_OTHER
+;
+
+terminal ID:
+ (LETTER | DIGIT)
+ (LETTER | DIGIT | '_' | '-')*
+;
+
+terminal fragment LETTER: ARABIC_ALPHABET
+ | ARMENIAN_ALPHABET
+ | GREEK_ALPHABET
+ | CYRILLIC_ALPHABET
+ | HEBREW_ALPHABET
+ | LATIN_ALPHABET
+ | THAI_ALPHABET
+ | TAGALOG_ALPHABET
+ | DIACRITICAL_MARKS
+;
+
+
+// Reference: https://jrgraphix.net/r/Unicode/
+////
+
+terminal fragment ARABIC_ALPHABET: ('\u0600'..'\u06FF');
+terminal fragment ARMENIAN_ALPHABET: ('\u0530'..'\u058F');
+terminal fragment GREEK_ALPHABET: ('\u0370'..'\u03FF');
+terminal fragment CYRILLIC_ALPHABET: ('\u0400'..'\u04FF');
+terminal fragment HEBREW_ALPHABET: ('\u0590'..'\u05FF');
+terminal fragment LATIN_ALPHABET: ('\u0041'..'\u005A')
+ | ('\u0061'..'\u007A')
+;
+terminal fragment THAI_ALPHABET: ('\u0E00'..'\u0E7F');
+terminal fragment TAGALOG_ALPHABET: ('\u0400'..'\u04FF');
+terminal fragment DIACRITICAL_MARKS: ('\u0300'..'\u036F');
+
+terminal STRING returns ecore::EString:
+ '"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | '\\') | !('\\' | '"' | '\r' | '\n'))* '"' |
+ "'" ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | "'" | '\\') | !('\\' | "'" | '\r' | '\n'))* "'"
+;
+
+terminal NUMBER returns ecore::EBigInteger:
+ '-'? DIGIT+ '.' DIGIT* EXPONENT_PART?
+ | '-'? '.' DIGIT+ EXPONENT_PART?
+ | '-'? DIGIT+ EXPONENT_PART
+ | '-'? DECIMAL_NUMBER
+ | '-'? HEX_NUMBER
+ | '-'? OCTAL_NUMBER
+;
+
+terminal fragment DECIMAL_NUMBER:
+ NON_ZERO_DIGIT DIGIT*
+;
+
+terminal fragment DIGIT:
+ '0' | NON_ZERO_DIGIT
+;
+
+terminal fragment NON_ZERO_DIGIT:
+ '1'..'9'
+;
+
+terminal fragment HEX_NUMBER:
+ '0' ('x' | 'X') ('0'..'9' | 'a'..'f' | 'A'..'F')+
+;
+
+terminal fragment OCTAL_NUMBER:
+ '0' '0'..'7'*
+;
+
+terminal fragment EXPONENT_PART:
+ ('e' | 'E') ('+' | '-')? DIGIT+
+;
+
+terminal SL_COMMENT:
+ '#' !('\n' | '\r')* NL
+;
+
+terminal GLOB:
+ !('@' | '|' | ' ' | '\t' | '\n' | '\r')
+ !(' ' | '\t' | '\n' | '\r')*
+;
+
+BLANK_SPACE: NL+;
+terminal NL: ('\r'? '\n') | EOF;
+terminal WS: (' ' | '\t');
+
+terminal ANY_OTHER: .;
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalRuntimeModule.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalRuntimeModule.java
new file mode 100644
index 00000000..89f2ac59
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalRuntimeModule.java
@@ -0,0 +1,17 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang;
+
+import org.agileware.natural.lang.text.TextValueConverterService;
+import org.eclipse.xtext.conversion.IValueConverterService;
+
+/**
+ * Use this class to register components to be used at runtime / without the Equinox extension registry.
+ */
+public class NaturalRuntimeModule extends AbstractNaturalRuntimeModule {
+ @Override
+ public Class extends IValueConverterService> bindIValueConverterService() {
+ return TextValueConverterService.class;
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalStandaloneSetup.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalStandaloneSetup.java
new file mode 100644
index 00000000..806fd1ae
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/NaturalStandaloneSetup.java
@@ -0,0 +1,15 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang;
+
+
+/**
+ * Initialization support for running Xtext languages without Equinox extension registry.
+ */
+public class NaturalStandaloneSetup extends NaturalStandaloneSetupGenerated {
+
+ public static void doSetup() {
+ new NaturalStandaloneSetup().createInjectorAndDoEMFRegistration();
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatHelper.xtend b/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatHelper.xtend
new file mode 100644
index 00000000..9c24e8d5
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatHelper.xtend
@@ -0,0 +1,216 @@
+package org.agileware.natural.lang.formatting2
+
+import com.google.inject.Inject
+import java.util.List
+import org.agileware.natural.lang.model.Meta
+import org.agileware.natural.lang.model.MetaElement
+import org.agileware.natural.lang.services.NaturalGrammarAccess
+import org.agileware.natural.lang.text.TextLine
+import org.agileware.natural.lang.text.TextModel
+import org.apache.commons.lang.StringUtils
+import org.eclipse.emf.ecore.EObject
+import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
+import org.eclipse.xtext.Assignment
+import org.eclipse.xtext.RuleCall
+import org.eclipse.xtext.formatting.IIndentationInformation
+import org.eclipse.xtext.formatting2.FormatterPreferenceKeys
+import org.eclipse.xtext.formatting2.FormatterRequest
+import org.eclipse.xtext.formatting2.IFormattableDocument
+import org.eclipse.xtext.formatting2.ITextReplacer
+import org.eclipse.xtext.formatting2.ITextReplacerContext
+import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion
+import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess
+import org.eclipse.xtext.formatting2.regionaccess.ITextRegionExtensions
+import org.eclipse.xtext.formatting2.regionaccess.ITextSegment
+import org.eclipse.xtext.formatting2.regionaccess.internal.NodeSemanticRegion
+import org.eclipse.xtext.nodemodel.util.NodeModelUtils
+import org.eclipse.xtext.preferences.MapBasedPreferenceValues
+
+@FinalFieldsConstructor
+class NaturalFormatHelper {
+
+ static class Factory {
+ @Inject IIndentationInformation indentationInformation
+
+ def NaturalFormatHelper create(ITextRegionAccess regionAccess, NaturalGrammarAccess grammerAccess) {
+ new NaturalFormatHelper(this, regionAccess.extensions, grammerAccess)
+ }
+ }
+
+ val Factory factory
+
+ val extension ITextRegionExtensions
+
+ val extension NaturalGrammarAccess
+
+ var int _indentationLevel = 0
+
+ def int getIndentationLevel() {
+ return _indentationLevel
+ }
+
+ def void resetIndentation() {
+ _indentationLevel = 0
+ }
+
+ def void increaseIndent() {
+ _indentationLevel += 1
+ }
+
+ def void decreaseIndent() {
+ _indentationLevel -= 1
+ }
+
+ def void initialize(FormatterRequest request) {
+ val preferences = request.preferences
+ if (preferences instanceof MapBasedPreferenceValues) {
+ preferences.put(FormatterPreferenceKeys.indentation, factory.indentationInformation.indentString)
+ }
+
+ _indentationLevel = 0
+ }
+
+ def void formatMultilineText(EObject owner, Assignment assignment, int indentationLevel,
+ extension IFormattableDocument doc) {
+ val region = owner.regionFor.assignment(assignment)
+ if (region instanceof NodeSemanticRegion) {
+ addReplacer(new MultilineTextReplacer(region, indentationLevel))
+ }
+ }
+
+ def void trimBlankSpace(EObject owner, RuleCall rule, extension IFormattableDocument doc) {
+ trimBlankSpace(owner, rule, 0, doc)
+ }
+
+ def void trimBlankSpace(EObject owner, RuleCall rule, int newLines, extension IFormattableDocument doc) {
+ val region = owner.regionFor.ruleCall(rule)
+ if (region instanceof NodeSemanticRegion) {
+ addReplacer(new BlankSpaceReplacer(region, newLines))
+ }
+ }
+
+ def void indentBlock(ISemanticRegion start, ISemanticRegion end, extension IFormattableDocument doc) {
+ // println('''
+ // ========= Indent Block («indentationLevel») =========
+ // start=[«start.offset», «start.length»] «start.grammarElement»
+ // end=[«end.offset», «end.length»] «end.grammarElement»
+ // ''')
+ interior(start, end)[indent]
+ }
+
+ def boolean hasLeadingBlankSpace(EObject model) {
+ immediatelyPreceding(model).ruleCallTo(BLANK_SPACERule) !== null
+ }
+
+ def boolean hasTrailingBlankSpace(EObject model) {
+ immediatelyFollowing(model).ruleCallTo(BLANK_SPACERule) !== null
+ }
+
+ def trimBlankSpace(ISemanticRegion region, int newLines, extension IFormattableDocument doc) {
+ if (region instanceof NodeSemanticRegion) {
+ addReplacer(new BlankSpaceReplacer(region, newLines))
+ }
+ }
+
+ def dispatch boolean isLast(MetaElement model) {
+ val meta = model.eContainer as Meta
+ model == meta.tags.last
+ }
+}
+
+@FinalFieldsConstructor
+public class BlankSpaceReplacer implements ITextReplacer {
+ val NodeSemanticRegion region
+
+ val int newLines
+
+ override ITextSegment getRegion() {
+ region
+ }
+
+ override createReplacements(ITextReplacerContext context) {
+ val newText = (newLines === 0) ? "" : StringUtils.repeat(System.lineSeparator, newLines)
+
+ context.addReplacement(region.replaceWith(newText))
+
+ return context
+ }
+}
+
+@FinalFieldsConstructor
+class MultilineTextReplacer implements ITextReplacer {
+
+ static def indentToRemove(List lines, int originalStartColumn) {
+ var count = lines.length - 1
+ if (count < 1) {
+ return 0
+ }
+
+ val (TextLine)=>Integer countLeadingWS = [leadingWhiteSpace.length()]
+ val minCountLeadingWS = lines.tail.take(count).map[countLeadingWS.apply(it)].min
+
+ return Math.min(minCountLeadingWS, originalStartColumn)
+ }
+
+ val NodeSemanticRegion region
+
+ val int indentationLevel
+
+ override ITextSegment getRegion() {
+ region
+ }
+
+ override createReplacements(ITextReplacerContext context) {
+ val indentationString = context.getIndentationString(1)
+ val originalStartColumn = NodeModelUtils.getLineAndColumn(region.node, region.offset).column
+
+ val model = TextModel.build(region.text)
+ if (model.lines.size > 1) {
+ val indentToRemove = indentToRemove(model.lines, originalStartColumn)
+ // println('''======= Processng Text Indentation (indentationLevel: «indentationLevel», originalStartColumn: «originalStartColumn», indentToRemove: «indentToRemove») =======''')
+ context.addReplacement(
+ region.replaceWith(
+ toIndentedString(model.lines, indentationString, indentationLevel, originalStartColumn,
+ indentToRemove)))
+ }
+
+ return context
+ }
+
+ def String toIndentedString(List lines, String indentationString, int indentationLevel,
+ int originalStartColumn, int indentToRemove) {
+ val result = new StringBuilder()
+ val length = lines.size()
+
+ for (var i = 0; i < length; i++) {
+ val line = lines.get(i)
+ // println('''[offset: «line.relativeOffset», length: «line.length», leadingWhiteSpace: «line.leadingWhiteSpace.length»] «line»''')
+ val toColumn = indentationLevel + 1
+ if (i == 0) {
+ // append first line as is (will be indented by formatter rules)
+ result.append(line)
+ } else {
+ if (originalStartColumn < toColumn) {
+ // increase indent
+ val indentIncrease = StringUtils.repeat(indentationString, toColumn - originalStartColumn)
+ result.append(indentIncrease).append(line)
+ } else if (originalStartColumn > toColumn) {
+ // decrease indent
+ val leadingWs = line.leadingWhiteSpace.toString()
+ val newIndent = StringUtils.replace(leadingWs, indentationString, "",
+ originalStartColumn - toColumn)
+ result.append(newIndent).append(line.semanticText)
+ } else {
+ // no adjustment needed
+ result.append(line)
+ }
+ }
+
+ if (i < length - 1) {
+ result.append(System.lineSeparator());
+ }
+ }
+
+ return result.toString();
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatter.xtend b/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatter.xtend
new file mode 100644
index 00000000..de4f433b
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/formatting2/NaturalFormatter.xtend
@@ -0,0 +1,198 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.formatting2
+
+import com.google.inject.Inject
+import org.agileware.natural.lang.model.Block
+import org.agileware.natural.lang.model.DocString
+import org.agileware.natural.lang.model.Document
+import org.agileware.natural.lang.model.Meta
+import org.agileware.natural.lang.model.MetaElement
+import org.agileware.natural.lang.model.Narrative
+import org.agileware.natural.lang.model.NaturalModel
+import org.agileware.natural.lang.model.Paragraph
+import org.agileware.natural.lang.model.Section
+import org.agileware.natural.lang.model.Table
+import org.agileware.natural.lang.services.NaturalGrammarAccess
+import org.eclipse.xtext.formatting2.AbstractFormatter2
+import org.eclipse.xtext.formatting2.FormatterRequest
+import org.eclipse.xtext.formatting2.IFormattableDocument
+import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion
+
+class NaturalFormatter extends AbstractFormatter2 {
+
+ @Inject extension NaturalGrammarAccess naturalGrammarAccess
+
+ @Inject NaturalFormatHelper.Factory formatHelperFactory
+
+ var extension NaturalFormatHelper _formatHelper = null
+
+ override protected initialize(FormatterRequest request) {
+ _formatHelper = formatHelperFactory.create(request.textRegionAccess, naturalGrammarAccess)
+ _formatHelper.initialize(request)
+
+ super.initialize(request)
+ }
+
+ def dispatch void format(NaturalModel model, extension IFormattableDocument doc) {
+ // println(textRegionAccess)
+ model.document.format()
+ // println(doc)
+ }
+
+ def dispatch void format(Document model, extension IFormattableDocument doc) {
+ resetIndentation()
+
+ // Condense all BLANK_SPACE regions into single line break
+ model.allRegionsFor.ruleCallsTo(BLANK_SPACERule).forEach [ region |
+ // println('''Trimming BLANK_SPACE: «region.offset» «region.length»''')
+ trimBlankSpace(region, 1, doc)
+ ]
+
+ // Format meta tags
+ model.meta.format()
+
+ // Cleanup whitespace around keyword/title
+ if (model.title === null) {
+ model.regionFor.keyword(documentAccess.documentKeyword_3).append[noSpace]
+ } else {
+ model.regionFor.assignment(documentAccess.titleAssignment_4).prepend[oneSpace].append[noSpace]
+ }
+
+ increaseIndent()
+ indentBlock(model.startIndent, model.endIndent, doc)
+
+ // Format narrative
+ if (model.narrative !== null) {
+ model.narrative.format().prepend[indent]
+ if (!model.narrative.hasLeadingBlankSpace) {
+ model.narrative.prepend[setNewLines(2)]
+ }
+ }
+
+ // Format sections
+ model.sections.forEach[format().prepend[indent]]
+
+ decreaseIndent()
+ }
+
+ def dispatch void format(Section model, extension IFormattableDocument doc) {
+
+ // Set block spacing
+ if (!model.hasLeadingBlankSpace) {
+ model.prepend[setNewLines(2)]
+ }
+
+ // Format meta tags
+ if (model.meta !== null) {
+ model.meta.format()
+
+ // Work-around for strange keyword placement when tags are present
+ model.regionFor.keyword(sectionAccess.sectionKeyword_2).prepend[indent]
+ }
+
+ // Cleanup whitespace around keyword/title
+ if (model.title === null) {
+ model.regionFor.keyword(sectionAccess.sectionKeyword_2).append[noSpace]
+ } else {
+ model.regionFor.assignment(sectionAccess.titleAssignment_3).prepend[oneSpace].append[noSpace]
+ }
+
+ increaseIndent()
+ indentBlock(model.startIndent, model.endIndent, doc)
+
+ // Format narrative
+ if (model.narrative !== null) {
+ model.narrative.format().prepend[indent]
+ // TODO (opinionated) should we increase spacing here?
+ // if(!model.narrative.hasLeadingBlankSpace) {
+ // model.narrative.prepend[setNewLines(2)]
+ // }
+ }
+
+ decreaseIndent()
+ }
+
+ def dispatch void format(Meta model, extension IFormattableDocument doc) {
+ model.tags.forEach[format]
+ }
+
+ def dispatch void format(MetaElement model, extension IFormattableDocument doc) {
+
+ // Trim leading/trailing whitespace
+ model.surround[noSpace]
+
+// if (model.value !== null) {
+// // Cleanup whitespace around value assignment
+// model.regionFor.keyword(':').prepend[noSpace].append[oneSpace]
+// model.regionFor.assignment(metaElementAccess.valueAssignment_2_1).prepend[oneSpace].append[noSpace]
+// }
+
+ // Insert newline if not present from BLANK_SPACE
+ if (model.isLast()) {
+ model.append[setNewLines(0)]
+ } else if (!model.hasTrailingBlankSpace) {
+ model.append[newLine]
+ }
+ }
+
+ def dispatch void format(Narrative model, extension IFormattableDocument doc) {
+ model.sections.forEach[format().prepend[indent]]
+ }
+
+ def dispatch void format(Paragraph model, extension IFormattableDocument doc) {
+ formatMultilineText(model, paragraphAccess.valueAssignment_1, indentationLevel, doc)
+ }
+
+ def dispatch void format(Table model, extension IFormattableDocument doc) {
+ model.rows.forEach[prepend[indent]]
+ }
+
+ def dispatch void format(DocString model, extension IFormattableDocument doc) {
+ formatMultilineText(model, docStringAccess.valueAssignment_1, indentationLevel, doc)
+ }
+
+ def ISemanticRegion startIndent(Document model) {
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def ISemanticRegion endIndent(Document model) {
+ if (!model.sections.isEmpty()) {
+ return model.sections.last.endIndent()
+ } else if (model.narrative !== null) {
+ return model.narrative.endIndent()
+ }
+
+ return model.regionFor.ruleCall(documentAccess.BLANK_SPACEParserRuleCall_8)
+ }
+
+ def ISemanticRegion startIndent(Section model) {
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def ISemanticRegion endIndent(Section model) {
+ if (model.narrative !== null) {
+ return model.narrative.endIndent()
+ }
+
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def ISemanticRegion endIndent(Narrative model) {
+ return model.sections.last.endIndent()
+ }
+
+ def ISemanticRegion endIndent(Block model) {
+ if(model instanceof Table) {
+ return model.rows.last.regionFor.ruleCallTo(NLRule)
+ }
+
+ return model.regionFor.ruleCallTo(NLRule)
+ }
+
+ def boolean isLast(Section model) {
+ val document = model.eContainer as Document
+ model == document.sections.last
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/generator/NaturalGenerator.xtend b/org.agileware.natural.lang/src/org/agileware/natural/lang/generator/NaturalGenerator.xtend
new file mode 100644
index 00000000..a0d3a30f
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/generator/NaturalGenerator.xtend
@@ -0,0 +1,25 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.generator
+
+import org.eclipse.emf.ecore.resource.Resource
+import org.eclipse.xtext.generator.AbstractGenerator
+import org.eclipse.xtext.generator.IFileSystemAccess2
+import org.eclipse.xtext.generator.IGeneratorContext
+
+/**
+ * Generates code from your model files on save.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation
+ */
+class NaturalGenerator extends AbstractGenerator {
+
+ override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
+// fsa.generateFile('greetings.txt', 'People to greet: ' +
+// resource.allContents
+// .filter(Greeting)
+// .map[name]
+// .join(', '))
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/scoping/NaturalScopeProvider.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/scoping/NaturalScopeProvider.java
new file mode 100644
index 00000000..cb9c3e84
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/scoping/NaturalScopeProvider.java
@@ -0,0 +1,15 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.scoping;
+
+
+/**
+ * This class contains custom scoping description.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping
+ * on how and when to use it.
+ */
+public class NaturalScopeProvider extends AbstractNaturalScopeProvider {
+
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSemanticSequencer.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSemanticSequencer.java
new file mode 100644
index 00000000..fc117309
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSemanticSequencer.java
@@ -0,0 +1,8 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.serializer;
+
+
+public class NaturalSemanticSequencer extends AbstractNaturalSemanticSequencer {
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSerializer.xtend b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSerializer.xtend
new file mode 100644
index 00000000..ce26c4fa
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSerializer.xtend
@@ -0,0 +1,98 @@
+package org.agileware.natural.lang.serializer
+
+import org.agileware.natural.lang.model.Block
+import org.agileware.natural.lang.model.DocString
+import org.agileware.natural.lang.model.Document
+import org.agileware.natural.lang.model.Meta
+import org.agileware.natural.lang.model.Narrative
+import org.agileware.natural.lang.model.NaturalModel
+import org.agileware.natural.lang.model.Paragraph
+import org.agileware.natural.lang.model.Section
+import org.agileware.natural.lang.model.Table
+import org.agileware.natural.lang.model.TableCol
+import org.agileware.natural.lang.model.TableRow
+
+class NaturalSerializer {
+
+ def String serialize(NaturalModel model) {
+ return (model.document === null) ? "\n" : serialize(model.document)
+ }
+
+ def String serialize(Document model) '''
+ # language: en
+ «serialize(model.meta)»
+ Document: «model.title»
+ «serialize(model.narrative)»
+ «FOR s : model.sections»
+ «serialize(s)»
+ «ENDFOR»
+ '''
+
+ def String serialize(Section model) '''
+ Section: «model.title»
+ «serialize(model.narrative)»
+ '''
+
+ def String serialize(Meta model) {
+ if(model === null) return ""
+
+ return '''
+ «FOR t : model.tags»
+ «t.id»
+ «ENDFOR»
+ '''
+ }
+
+ def String serialize(Narrative model) {
+ if(model === null) return ""
+ return '''
+ «FOR s : model.sections»
+ «serialize(s)»
+ «ENDFOR»
+ '''
+ }
+
+ def String serialize(Block model) {
+ if(model instanceof Paragraph) {
+ return serialize(model as Paragraph)
+ } else if(model instanceof Table) {
+ return serialize(model as Table)
+ } else if(model instanceof DocString) {
+ return serialize(model as DocString)
+ }
+
+ return ""
+ }
+
+ def String serialize(Paragraph model) {
+ if(model === null) return ""
+
+ return model.value
+ }
+
+ def String serialize(Table model) {
+ if(model === null) return ""
+
+ return '''
+ «FOR r : model.rows»
+ «serialize(r)»
+ «ENDFOR»
+ '''
+ }
+
+ def String serialize(TableRow model) '''
+ «model.cols.map[serialize].join()» |
+ '''
+
+ def String serialize(TableCol model) {
+ return model.value
+ }
+
+ def String serialize(DocString model) {
+ if(model === null) return ""
+
+ return '''
+ «model.value»
+ '''
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSyntacticSequencer.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSyntacticSequencer.java
new file mode 100644
index 00000000..b892f1d6
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/serializer/NaturalSyntacticSequencer.java
@@ -0,0 +1,8 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.serializer;
+
+
+public class NaturalSyntacticSequencer extends AbstractNaturalSyntacticSequencer {
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/text/NUMBERValueConverter.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/NUMBERValueConverter.java
new file mode 100644
index 00000000..de58bf43
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/NUMBERValueConverter.java
@@ -0,0 +1,32 @@
+package org.agileware.natural.lang.text;
+
+import java.math.BigInteger;
+
+import org.eclipse.xtext.conversion.ValueConverterException;
+import org.eclipse.xtext.conversion.impl.AbstractLexerBasedConverter;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.util.Strings;
+
+public class NUMBERValueConverter extends AbstractLexerBasedConverter {
+
+ public NUMBERValueConverter() {
+ super();
+ }
+
+ @Override
+ protected String toEscapedString(final BigInteger value) {
+ return value.toString();
+ }
+
+ @Override
+ public BigInteger toValue(final String string, final INode node) throws ValueConverterException {
+ if (Strings.isEmpty(string))
+ throw new ValueConverterException("Couldn't convert empty string to an int value.", node, null);
+ try {
+ return new BigInteger(string);
+ } catch (final NumberFormatException e) {
+ throw new ValueConverterException("Couldn't convert '" + string + "' to an int value.", node, e);
+ }
+ }
+
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLine.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLine.java
new file mode 100644
index 00000000..94a89281
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLine.java
@@ -0,0 +1,158 @@
+package org.agileware.natural.lang.text;
+
+/**
+ * Implementation {@link CharSequence} that is tailored to line-per-line
+ * processing of text and supports special handling of whitespace.
+ *
+ * @author Sebastian Zarnekow - Initial contribution and API
+ */
+public class TextLine implements CharSequence {
+
+ protected static class LeadingWSTextLinePart extends TextLine {
+
+ public LeadingWSTextLinePart(final String completeText, final int offset, final int length) {
+ super(completeText, offset, length, 0);
+ }
+
+ @Override
+ public CharSequence getLeadingWhiteSpace() {
+ return this;
+ }
+
+ @Override
+ public boolean hasLeadingWhiteSpace() {
+ return length() > 0;
+ }
+
+ @Override
+ public boolean containsOnlyWhitespace() {
+ return true;
+ }
+ }
+
+ private final String completeText;
+ private final int offset;
+ private final int length;
+ private final int delimiterLength;
+
+ public TextLine(final String completeText, final int offset, final int length, final int delimiterLength) {
+ this.completeText = completeText;
+ this.offset = offset;
+ this.length = length;
+ this.delimiterLength = delimiterLength;
+ }
+
+ public String getCompleteText() {
+ return completeText;
+ }
+
+ public boolean hasLeadingWhiteSpace() {
+ if (length == 0)
+ return false;
+ final boolean result = Character.isWhitespace(charAt(0));
+ return result;
+ }
+
+ public boolean containsOnlyWhitespace() {
+ for (int i = 0; i < length(); i++) {
+ if (!Character.isWhitespace(charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public CharSequence getLeadingWhiteSpace() {
+ for (int i = 0; i < length(); i++) {
+ if (!Character.isWhitespace(charAt(i))) {
+ if (i == 0)
+ return "";
+ return new LeadingWSTextLinePart(completeText, offset, i);
+ }
+ }
+ return new LeadingWSTextLinePart(completeText, offset, length);
+ }
+
+ public boolean hasTrailingLineBreak() {
+ return delimiterLength > 0;
+ }
+
+ public int getRelativeOffset() {
+ return offset;
+ }
+
+ @Override
+ public int length() {
+ return length;
+ }
+
+ @Override
+ public char charAt(final int index) {
+ return completeText.charAt(index + offset);
+ }
+
+ public int getDelimiterLength() {
+ return delimiterLength;
+ }
+
+ public CharSequence getSemanticText() {
+ return subSequence(getLeadingWhiteSpace().length(), length);
+ }
+
+ @Override
+ public String toString() {
+ return completeText.substring(offset, offset + length);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + toString().hashCode();
+ result = prime * result + delimiterLength;
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final TextLine other = (TextLine) obj;
+ if (length != other.length)
+ return false;
+ if (delimiterLength != other.delimiterLength)
+ return false;
+ if (!completeText.regionMatches(offset, other.completeText, other.offset, length))
+ return false;
+ return true;
+ }
+
+ /**
+ * @throws IndexOutOfBoundsException if start or end are
+ * negative, if end is greater than
+ * length(), or if start is
+ * greater than end
+ */
+ @Override
+ public CharSequence subSequence(final int start, final int end) {
+ if (start < 0 || start > end) {
+ throwIndexOutOfBounds(start);
+ }
+ if (end < 0 || end > length) {
+ throwIndexOutOfBounds(end);
+ }
+ if (start > end) {
+ throwIndexOutOfBounds(end - start);
+ }
+ return completeText.subSequence(start + offset, end + offset);
+ }
+
+ protected void throwIndexOutOfBounds(final int offset) {
+ throw new IndexOutOfBoundsException(("Index out of range: " + offset));
+ }
+
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLiterals.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLiterals.java
new file mode 100644
index 00000000..46638f75
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextLiterals.java
@@ -0,0 +1,13 @@
+package org.agileware.natural.lang.text;
+
+public interface TextLiterals {
+ String DOC_STRING_LITERAL = "DOC_STRING_LITERAL";
+ String TABLE_CELL = "TABLE_CELL";
+ String STRING = "STRING";
+ String NUMBER = "NUMBER";
+ String WORD = "WORD";
+ String NL = "NL";
+ String WS = "WS";
+ String SL_COMMENT = "SL_COMMENT";
+ String ANY_OTHER = "ANY_OTHER";
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextModel.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextModel.java
new file mode 100644
index 00000000..fc5c01ec
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextModel.java
@@ -0,0 +1,74 @@
+package org.agileware.natural.lang.text;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * TODO This was originally designed for individual replacers per Literal, And
+ * is probably a bit overkill for the simple whole-region-replacer that is
+ * currently implemented in MultilineTextFormatter
+ *
+ */
+public class TextModel {
+
+ /**
+ * adapted from
+ * org.eclipse.jface.text.DefaultLineTracker.nextDelimiterInfo(String, int)
+ */
+ public static TextModel build(final String text) {
+ final List lines = new ArrayList();
+ if (text == null)
+ return new TextModel(lines);
+
+ final int length = text.length();
+ int nextLineOffset = 0;
+ int idx = 0;
+ while (idx < length) {
+ final char currentChar = text.charAt(idx);
+ // check for \r or \r\n
+ if (currentChar == '\r') {
+ int delimiterLength = 1;
+ if (idx + 1 < length && text.charAt(idx + 1) == '\n') {
+ delimiterLength++;
+ idx++;
+ }
+ final int lineLength = idx - delimiterLength - nextLineOffset + 1;
+ final TextLine line = new TextLine(text, nextLineOffset, lineLength, delimiterLength);
+ lines.add(line);
+ nextLineOffset = idx + 1;
+ } else if (currentChar == '\n') {
+ final int lineLength = idx - nextLineOffset;
+ final TextLine line = new TextLine(text, nextLineOffset, lineLength, 1);
+ lines.add(line);
+ nextLineOffset = idx + 1;
+ }
+ idx++;
+ }
+ if (nextLineOffset != length) {
+ final int lineLength = length - nextLineOffset;
+ final TextLine line = new TextLine(text, nextLineOffset, lineLength, 0);
+ lines.add(line);
+ }
+
+ return new TextModel(lines);
+ }
+
+ private final List lines;
+
+ public List getLines() {
+ return lines;
+ }
+
+ public TextModel(final List lines) {
+ super();
+
+ this.lines = lines;
+ }
+
+ @Override
+ public String toString() {
+ return lines.stream().collect(Collectors.joining(System.lineSeparator())).toString();
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextValueConverterService.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextValueConverterService.java
new file mode 100644
index 00000000..3441069c
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/text/TextValueConverterService.java
@@ -0,0 +1,29 @@
+package org.agileware.natural.lang.text;
+
+import java.math.BigInteger;
+
+import org.eclipse.xtext.conversion.IValueConverter;
+import org.eclipse.xtext.conversion.ValueConverter;
+import org.eclipse.xtext.conversion.impl.AbstractDeclarativeValueConverterService;
+import org.eclipse.xtext.conversion.impl.STRINGValueConverter;
+
+import com.google.inject.Inject;
+
+public class TextValueConverterService extends AbstractDeclarativeValueConverterService {
+
+ @Inject
+ private STRINGValueConverter stringValueConverter;
+
+ @ValueConverter(rule = TextLiterals.STRING)
+ public IValueConverter STRING_LITERAL() {
+ return stringValueConverter;
+ }
+
+ @Inject
+ private NUMBERValueConverter numberValueConverter;
+
+ @ValueConverter(rule = TextLiterals.NUMBER)
+ public IValueConverter NUMBER_LITERAL() {
+ return numberValueConverter;
+ }
+}
diff --git a/org.agileware.natural.lang/src/org/agileware/natural/lang/validation/NaturalValidator.java b/org.agileware.natural.lang/src/org/agileware/natural/lang/validation/NaturalValidator.java
new file mode 100644
index 00000000..0d00851d
--- /dev/null
+++ b/org.agileware.natural.lang/src/org/agileware/natural/lang/validation/NaturalValidator.java
@@ -0,0 +1,25 @@
+/*
+ * generated by Xtext 2.23.0-SNAPSHOT
+ */
+package org.agileware.natural.lang.validation;
+
+
+/**
+ * This class contains custom validation rules.
+ *
+ * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#validation
+ */
+public class NaturalValidator extends AbstractNaturalValidator {
+
+// public static final String INVALID_NAME = "invalidName";
+//
+// @Check
+// public void checkGreetingStartsWithCapital(Greeting greeting) {
+// if (!Character.isUpperCase(greeting.getName().charAt(0))) {
+// warning("Name should start with a capital",
+// NaturalPackage.Literals.GREETING__NAME,
+// INVALID_NAME);
+// }
+// }
+
+}
diff --git a/org.agileware.natural.stepmatcher.feature/.project b/org.agileware.natural.stepmatcher.feature/.project
deleted file mode 100644
index 49ca92e2..00000000
--- a/org.agileware.natural.stepmatcher.feature/.project
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
- org.agileware.natural.stepmatcher.feature
-
-
-
-
-
- org.eclipse.pde.FeatureBuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.pde.FeatureNature
- org.eclipse.m2e.core.maven2Nature
-
-
diff --git a/org.agileware.natural.stepmatcher.feature/build.properties b/org.agileware.natural.stepmatcher.feature/build.properties
deleted file mode 100644
index 64f93a9f..00000000
--- a/org.agileware.natural.stepmatcher.feature/build.properties
+++ /dev/null
@@ -1 +0,0 @@
-bin.includes = feature.xml
diff --git a/org.agileware.natural.stepmatcher.feature/feature.xml b/org.agileware.natural.stepmatcher.feature/feature.xml
deleted file mode 100644
index 177b9d65..00000000
--- a/org.agileware.natural.stepmatcher.feature/feature.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
- [Enter Feature Description here.]
-
-
-
- [Enter Copyright Description here.]
-
-
-
- [Enter License Description here.]
-
-
-
-
-
diff --git a/org.agileware.natural.stepmatcher.ui/.classpath b/org.agileware.natural.stepmatcher.ui/.classpath
new file mode 100644
index 00000000..eca7bdba
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.stepmatcher.ui/.project b/org.agileware.natural.stepmatcher.ui/.project
new file mode 100644
index 00000000..32974d7a
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/.project
@@ -0,0 +1,28 @@
+
+
+ org.agileware.natural.stepmatcher.ui
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.pde.PluginNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/org.agileware.natural.stepmatcher.ui/.settings/org.eclipse.jdt.core.prefs b/org.agileware.natural.stepmatcher.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..9f6ece88
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/org.agileware.natural.stepmatcher.ui/META-INF/MANIFEST.MF b/org.agileware.natural.stepmatcher.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000..b91167e4
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,28 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Eclipse JDT StepMatcher
+Bundle-SymbolicName: org.agileware.natural.stepmatcher.ui
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.agileware.natural.stepmatcher.ui.Activator
+Bundle-Vendor: Roberto Lo Giacco
+Require-Bundle: org.agileware.natural.stepmatcher,
+ org.eclipse.ui,
+ org.eclipse.ui.ide,
+ org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.jdt.core,
+ org.eclipse.jdt.ui,
+ org.eclipse.jface.text,
+ com.google.guava;bundle-version="27.1.0",
+ com.google.inject;bundle-version="3.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Automatic-Module-Name: org.agileware.natural.stepmatcher.ui
+Bundle-ActivationPolicy: lazy
+Export-Package: org.agileware.natural.stepmatcher.ui;
+ uses:="org.osgi.framework,
+ org.eclipse.jdt.core,
+ org.eclipse.jface.text,
+ org.agileware.natural.stepmatcher,
+ org.eclipse.jface.text.hyperlink,
+ org.eclipse.jdt.core.search,
+ org.eclipse.ui.plugin"
diff --git a/org.agileware.natural.common/build.properties b/org.agileware.natural.stepmatcher.ui/build.properties
similarity index 56%
rename from org.agileware.natural.common/build.properties
rename to org.agileware.natural.stepmatcher.ui/build.properties
index aa70d440..34d2e4d2 100644
--- a/org.agileware.natural.common/build.properties
+++ b/org.agileware.natural.stepmatcher.ui/build.properties
@@ -1,2 +1,4 @@
source.. = src/
+output.. = bin/
bin.includes = META-INF/,\
+ .
diff --git a/org.agileware.natural.common/pom.xml b/org.agileware.natural.stepmatcher.ui/pom.xml
similarity index 86%
rename from org.agileware.natural.common/pom.xml
rename to org.agileware.natural.stepmatcher.ui/pom.xml
index 755b6ba0..1b335e49 100644
--- a/org.agileware.natural.common/pom.xml
+++ b/org.agileware.natural.stepmatcher.ui/pom.xml
@@ -6,9 +6,8 @@
natural
1.0.0-SNAPSHOT
- org.agileware.natural.common
+ org.agileware.natural.stepmatcher.ui
eclipse-plugin
- 1.3.0-SNAPSHOT
diff --git a/org.agileware.natural.common/src/org/agileware/natural/common/AbstractAnnotationDescriptor.java b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/AbstractAnnotationDescriptor.java
similarity index 92%
rename from org.agileware.natural.common/src/org/agileware/natural/common/AbstractAnnotationDescriptor.java
rename to org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/AbstractAnnotationDescriptor.java
index b24616e1..7e9b7b95 100644
--- a/org.agileware.natural.common/src/org/agileware/natural/common/AbstractAnnotationDescriptor.java
+++ b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/AbstractAnnotationDescriptor.java
@@ -1,4 +1,4 @@
-package org.agileware.natural.common;
+package org.agileware.natural.stepmatcher.ui;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
diff --git a/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/Activator.java b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/Activator.java
new file mode 100644
index 00000000..cbfcb4eb
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/Activator.java
@@ -0,0 +1,44 @@
+package org.agileware.natural.stepmatcher.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.agileware.natural.stepmatcher.ui"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaAnnotationMatcher.java b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaAnnotationMatcher.java
new file mode 100644
index 00000000..e4ea5e39
--- /dev/null
+++ b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaAnnotationMatcher.java
@@ -0,0 +1,218 @@
+package org.agileware.natural.stepmatcher.ui;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.agileware.natural.stepmatcher.AnnotationMacthEntry;
+import org.agileware.natural.stepmatcher.IStepMatcher;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IAnnotation;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchMatch;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.SearchRequestor;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class JavaAnnotationMatcher implements IStepMatcher {
+
+ private static boolean isMatchingAnnotationValue(final String annotationValue, final String description) {
+ try {
+ return description.matches(Pattern.quote(annotationValue));
+ } catch (final PatternSyntaxException e) {
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+
+ @Inject
+ private AbstractAnnotationDescriptor descriptor;
+
+ private final Map> cache = new HashMap>();
+
+ @Override
+ public boolean isActivated() {
+ return true;
+ }
+
+ @Override
+ public Collection findMatches(final String keyword, final String description) {
+ final MatchCollector command = new MatchCollector(keyword, description);
+ findMatches(description, command);
+
+ return command.get();
+ }
+
+ protected IJavaSearchScope getScope(final String filter) {
+ if (filter == null)
+ return SearchEngine.createWorkspaceScope();
+
+ final String[] names = filter.split(",");
+ final List packages = new ArrayList();
+
+ SearchPattern pattern = null;
+ for (final String name : names) {
+ final SearchPattern current = SearchPattern.createPattern(name.trim(), IJavaSearchConstants.PACKAGE,
+ IJavaSearchConstants.ALL_OCCURRENCES, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
+ if (pattern == null) {
+ pattern = current;
+ } else {
+ pattern = SearchPattern.createOrPattern(pattern, current);
+ }
+ }
+ try {
+ new SearchEngine().search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() },
+ SearchEngine.createWorkspaceScope(), new SearchRequestor() {
+ @Override
+ public void acceptSearchMatch(final SearchMatch match) throws CoreException {
+ packages.add((IJavaElement) match.getElement());
+ }
+ }, null);
+ } catch (final CoreException e) {
+ e.printStackTrace();
+ }
+ return SearchEngine.createJavaSearchScope(packages.toArray(new IJavaElement[0]));
+ }
+
+ public void findMatches(final String description, final Command command) {
+ final long time = System.currentTimeMillis();
+ if (!cache.isEmpty()) {
+ for (final List entries : cache.values()) {
+ for (final Entry entry : entries) {
+ if (isMatchingAnnotationValue(entry.annotationValue, description)) {
+ command.match(entry.annotationValue, entry.method);
+ }
+ }
+ }
+ return;
+ }
+
+ // combine search patterns
+ SearchPattern pattern = null;
+ for (final String annotationName : descriptor.getNames()) {
+ final SearchPattern current = SearchPattern.createPattern(annotationName,
+ IJavaSearchConstants.ANNOTATION_TYPE, IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE,
+ SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
+ if (pattern == null) {
+ pattern = current;
+ } else {
+ pattern = SearchPattern.createOrPattern(pattern, current);
+ }
+ }
+ // execute search
+ try {
+ new SearchEngine().search(pattern, new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() },
+ this.getScope(null), new SearchRequestor() {
+ @Override
+ public void acceptSearchMatch(final SearchMatch match) throws CoreException {
+ if (match.getElement() instanceof IMethod) {
+ final IMethod method = (IMethod) match.getElement();
+ final IAnnotation[] annotations = method.getAnnotations();
+ for (final IAnnotation type : annotations) {
+ // check annotation package
+ if (AbstractAnnotationDescriptor.checkPackage(type, descriptor.getPackage())) {
+ // verify pattern
+ final String annotationValue = (String) type.getMemberValuePairs()[0]
+ .getValue();
+ List entries = cache.get(method.getCompilationUnit());
+ if (entries == null) {
+ entries = new ArrayList();
+ cache.put(method.getCompilationUnit(), entries);
+ }
+ entries.add(new Entry(annotationValue, method));
+ if (isMatchingAnnotationValue(annotationValue, description)) {
+ command.match(annotationValue, method);
+ }
+ }
+ }
+ }
+ }
+ }, null);
+ } catch (final CoreException e) {
+ e.printStackTrace();
+ }
+ System.out.println("stepdef match lookup completed in " + (System.currentTimeMillis() - time) + "ms");
+ }
+
+ public Collection findProposals() {
+ if (cache.isEmpty()) {
+ findMatches("", (annotationValue, method) -> {
+ });
+ }
+
+ final Collection proposals = new TreeSet();
+ for (final List entries : cache.values()) {
+ for (final Entry entry : entries) {
+ proposals.add(entry.getAnnotationValue());
+ }
+ }
+ return proposals;
+ }
+
+ public void evict(final ICompilationUnit element) {
+ cache.clear();
+ System.out.println(">>> cache cleared");
+ }
+
+ public static interface Command {
+ void match(String annotationValue, IMethod method);
+ }
+
+ private final static class MatchCollector implements JavaAnnotationMatcher.Command {
+ private final String keyword;
+ private final String description;
+
+ private final List entries = new ArrayList();
+
+ public MatchCollector(final String keyword, final String description) {
+ super();
+ this.keyword = keyword;
+ this.description = description;
+ }
+
+ public List get() {
+ return Collections.unmodifiableList(entries);
+ }
+
+ @Override
+ public void match(final String annotationValue, final IMethod method) {
+ try {
+ entries.add(new AnnotationMacthEntry(keyword, description, method.getClass().getCanonicalName(),
+ method.getSignature()));
+ } catch (final JavaModelException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static class Entry {
+ private final String annotationValue;
+ private final IMethod method;
+
+ private Entry(final String annotationValue, final IMethod method) {
+ this.annotationValue = annotationValue;
+ this.method = method;
+ }
+
+ public String getAnnotationValue() {
+ return annotationValue;
+ }
+ }
+}
diff --git a/org.agileware.natural.common/src/org/agileware/natural/common/JavaElementChangeReporter.java b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaElementChangeReporter.java
similarity index 67%
rename from org.agileware.natural.common/src/org/agileware/natural/common/JavaElementChangeReporter.java
rename to org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaElementChangeReporter.java
index 8a23deba..fa92bda9 100644
--- a/org.agileware.natural.common/src/org/agileware/natural/common/JavaElementChangeReporter.java
+++ b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaElementChangeReporter.java
@@ -1,4 +1,4 @@
-package org.agileware.natural.common;
+package org.agileware.natural.stepmatcher.ui;
import java.util.List;
@@ -11,22 +11,22 @@
import com.google.inject.Inject;
public class JavaElementChangeReporter implements IElementChangedListener {
-
+
@Inject
private JavaAnnotationMatcher matcher;
-
+
@Override
- public void elementChanged(ElementChangedEvent event) {
+ public void elementChanged(final ElementChangedEvent event) {
traverse(event.getDelta(), null);
}
- void traverse(IJavaElementDelta delta, List hyperlinks) {
+ void traverse(final IJavaElementDelta delta, final List hyperlinks) {
if (delta.getElement().getElementType() == IJavaElement.COMPILATION_UNIT) {
if ((delta.getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE) > 0) {
- matcher.evict((ICompilationUnit)delta.getElement());
+ matcher.evict((ICompilationUnit) delta.getElement());
}
}
- for (IJavaElementDelta child : delta.getAffectedChildren()) {
+ for (final IJavaElementDelta child : delta.getAffectedChildren()) {
this.traverse(child, hyperlinks);
}
}
diff --git a/org.agileware.natural.common/src/org/agileware/natural/common/JavaHyperlink.java b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaHyperlink.java
similarity index 96%
rename from org.agileware.natural.common/src/org/agileware/natural/common/JavaHyperlink.java
rename to org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaHyperlink.java
index b813655a..1830c3fb 100644
--- a/org.agileware.natural.common/src/org/agileware/natural/common/JavaHyperlink.java
+++ b/org.agileware.natural.stepmatcher.ui/src/org/agileware/natural/stepmatcher/ui/JavaHyperlink.java
@@ -1,4 +1,4 @@
-package org.agileware.natural.common;
+package org.agileware.natural.stepmatcher.ui;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.IJavaElement;
diff --git a/org.agileware.natural.stepmatcher/META-INF/MANIFEST.MF b/org.agileware.natural.stepmatcher/META-INF/MANIFEST.MF
index 162be3e4..f567ec8d 100644
--- a/org.agileware.natural.stepmatcher/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.stepmatcher/META-INF/MANIFEST.MF
@@ -1,10 +1,11 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Bundle-Name: Stepmatcher
+Bundle-Name: Cucumber JVM Annotation Matcher
Bundle-SymbolicName: org.agileware.natural.stepmatcher
Bundle-Version: 1.0.0.qualifier
-Bundle-Activator: org.agileware.natural.stepmatcher.Activator
-Require-Bundle: org.eclipse.core.runtime
-Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-Vendor: Roberto Lo Giacco
Automatic-Module-Name: org.agileware.natural.stepmatcher
-Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Import-Package: org.osgi.framework;resolution:=optional,
+ org.osgi.service.component.annotations;resolution:=optional
+Export-Package: org.agileware.natural.stepmatcher
diff --git a/org.agileware.natural.stepmatcher/build.properties b/org.agileware.natural.stepmatcher/build.properties
index 56d77655..34d2e4d2 100644
--- a/org.agileware.natural.stepmatcher/build.properties
+++ b/org.agileware.natural.stepmatcher/build.properties
@@ -1,4 +1,4 @@
source.. = src/
-output.. = target/classes/
+output.. = bin/
bin.includes = META-INF/,\
.
diff --git a/org.agileware.natural.stepmatcher/pom.xml b/org.agileware.natural.stepmatcher/pom.xml
index e215b770..ca59f73a 100644
--- a/org.agileware.natural.stepmatcher/pom.xml
+++ b/org.agileware.natural.stepmatcher/pom.xml
@@ -11,12 +11,10 @@
-
org.eclipse.xtend
xtend-maven-plugin
-
diff --git a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/Activator.java b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/Activator.java
deleted file mode 100644
index 135c81ab..00000000
--- a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/Activator.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.agileware.natural.stepmatcher;
-
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-public class Activator implements BundleActivator {
-
- private static BundleContext context;
-
- static BundleContext getContext() {
- return context;
- }
-
- public void start(BundleContext bundleContext) throws Exception {
- Activator.context = bundleContext;
- }
-
- public void stop(BundleContext bundleContext) throws Exception {
- Activator.context = null;
- }
-
-}
diff --git a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/AnnotationMacthEntry.java b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/AnnotationMacthEntry.java
new file mode 100644
index 00000000..afc59ae5
--- /dev/null
+++ b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/AnnotationMacthEntry.java
@@ -0,0 +1,34 @@
+package org.agileware.natural.stepmatcher;
+
+public class AnnotationMacthEntry {
+
+ private final String keyword;
+ private final String description;
+ private final String typeName;
+ private final String methodSignature;
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getTypeName() {
+ return typeName;
+ }
+
+ public String getMethodSignature() {
+ return methodSignature;
+ }
+
+ public AnnotationMacthEntry(final String keyword, final String description, final String typeName,
+ final String methodSignature) {
+ super();
+ this.keyword = keyword;
+ this.description = description;
+ this.typeName = typeName;
+ this.methodSignature = methodSignature;
+ }
+}
diff --git a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/DefaultStepMatcher.java b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/DefaultStepMatcher.java
new file mode 100644
index 00000000..37c6ad29
--- /dev/null
+++ b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/DefaultStepMatcher.java
@@ -0,0 +1,17 @@
+package org.agileware.natural.stepmatcher;
+
+import java.util.Collection;
+
+public class DefaultStepMatcher implements IStepMatcher {
+
+ @Override
+ public boolean isActivated() {
+ return false;
+ }
+
+ @Override
+ public Collection findMatches(final String keyword, final String description) {
+ return null;
+ }
+
+}
diff --git a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/IStepMatcher.java b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/IStepMatcher.java
new file mode 100644
index 00000000..b99e012d
--- /dev/null
+++ b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/IStepMatcher.java
@@ -0,0 +1,20 @@
+package org.agileware.natural.stepmatcher;
+
+import java.util.Collection;
+
+public interface IStepMatcher {
+
+ /**
+ * @return Returns true if step matcher is activated at runtime
+ */
+ public boolean isActivated();
+
+ /**
+ * Search for matching annotations given a Step keyword and description
+ *
+ * @param keyword
+ * @param description
+ * @return
+ */
+ public Collection findMatches(final String keyword, final String description);
+}
diff --git a/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/package-info.java b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/package-info.java
new file mode 100644
index 00000000..103e6d8c
--- /dev/null
+++ b/org.agileware.natural.stepmatcher/src/org/agileware/natural/stepmatcher/package-info.java
@@ -0,0 +1 @@
+package org.agileware.natural.stepmatcher;
\ No newline at end of file
diff --git a/org.agileware.natural.target/org.agileware.natural.target.target b/org.agileware.natural.target/org.agileware.natural.target.target
index 95ea50f8..f7183ad8 100644
--- a/org.agileware.natural.target/org.agileware.natural.target.target
+++ b/org.agileware.natural.target/org.agileware.natural.target.target
@@ -8,31 +8,26 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
+
+
-
+
+
+
-
+
\ No newline at end of file
diff --git a/org.agileware.natural.testing/META-INF/MANIFEST.MF b/org.agileware.natural.testing/META-INF/MANIFEST.MF
index 36f095a0..314d4c94 100644
--- a/org.agileware.natural.testing/META-INF/MANIFEST.MF
+++ b/org.agileware.natural.testing/META-INF/MANIFEST.MF
@@ -10,21 +10,7 @@ Export-Package: org.agileware.natural.testing;
com.google.inject,
org.eclipse.xtext.testing.formatter,
org.eclipse.xtext.testing.validation,
- org.hamcrest",
- org.hamcrest;
- uses:="org.hamcrest.internal,
- new org.hamcrest,
- javax.xml.namespace,
- org.hamcrest.core,
- org.hamcrest.collection",
- org.hamcrest.beans;uses:="org.hamcrest",
- org.hamcrest.collection;uses:="org.hamcrest",
- org.hamcrest.comparator;uses:="org.hamcrest",
- org.hamcrest.core;uses:="org.hamcrest",
- org.hamcrest.internal;uses:="org.hamcrest",
- org.hamcrest.io;uses:="org.hamcrest",
- org.hamcrest.number;uses:="org.hamcrest",
- org.hamcrest.object;uses:="org.hamcrest",
- org.hamcrest.text;uses:="org.hamcrest",
- org.hamcrest.xml;uses:="org.w3c.dom,javax.xml.namespace,org.hamcrest"
-Require-Bundle: org.eclipse.xtext.testing
+ org.hamcrest"
+Require-Bundle: org.eclipse.xtext.testing,
+ org.hamcrest.core;visibility:=reexport,
+ org.hamcrest.library;visibility:=reexport
diff --git a/org.agileware.natural.testing/antlrworks.launch b/org.agileware.natural.testing/antlrworks.launch
new file mode 100644
index 00000000..361fbfc9
--- /dev/null
+++ b/org.agileware.natural.testing/antlrworks.launch
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/org.agileware.natural.testing/build.properties b/org.agileware.natural.testing/build.properties
index a55b80b0..718c03ee 100644
--- a/org.agileware.natural.testing/build.properties
+++ b/org.agileware.natural.testing/build.properties
@@ -1,13 +1,7 @@
-source.. = src/
+source.. = src/,\
+ xtend-gen/
output.. = bin/
bin.includes = META-INF/,\
- .,\
- lib/hamcrest-2.2-javadoc.jar
-src.includes = src/,\
- pom.xml,\
- build.properties,\
- META-INF/,\
+ .
+src.includes = pom.xml,\
lib/
-jars.extra.classpath = lib/hamcrest-2.2-javadoc.jar,\
- lib/hamcrest-2.2-sources.jar,\
- lib/hamcrest-2.2.jar
diff --git a/org.agileware.natural.testing/lib/antlrworks-1.5.2-complete.jar b/org.agileware.natural.testing/lib/antlrworks-1.5.2-complete.jar
new file mode 100755
index 00000000..9b71ab0c
Binary files /dev/null and b/org.agileware.natural.testing/lib/antlrworks-1.5.2-complete.jar differ
diff --git a/org.agileware.natural.testing/lib/hamcrest-2.2-javadoc.jar b/org.agileware.natural.testing/lib/hamcrest-2.2-javadoc.jar
deleted file mode 100644
index f57125c0..00000000
Binary files a/org.agileware.natural.testing/lib/hamcrest-2.2-javadoc.jar and /dev/null differ
diff --git a/org.agileware.natural.testing/lib/hamcrest-2.2-sources.jar b/org.agileware.natural.testing/lib/hamcrest-2.2-sources.jar
deleted file mode 100644
index 61242118..00000000
Binary files a/org.agileware.natural.testing/lib/hamcrest-2.2-sources.jar and /dev/null differ
diff --git a/org.agileware.natural.testing/lib/hamcrest-2.2.jar b/org.agileware.natural.testing/lib/hamcrest-2.2.jar
deleted file mode 100644
index 71065788..00000000
Binary files a/org.agileware.natural.testing/lib/hamcrest-2.2.jar and /dev/null differ
diff --git a/org.agileware.natural.testing/pom.xml b/org.agileware.natural.testing/pom.xml
index 23efcd03..b7e7f6ba 100644
--- a/org.agileware.natural.testing/pom.xml
+++ b/org.agileware.natural.testing/pom.xml
@@ -19,11 +19,4 @@
-
-
- org.hamcrest
- hamcrest
- 2.2
-
-
diff --git a/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractExamplesTest.java b/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractExamplesTest.java
index e91973f9..4993a695 100644
--- a/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractExamplesTest.java
+++ b/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractExamplesTest.java
@@ -5,14 +5,9 @@
import static org.hamcrest.Matchers.notNullValue;
import org.eclipse.emf.ecore.EObject;
-import org.eclipse.xtext.testing.util.ParseHelper;
-import com.google.inject.Inject;
+public class AbstractExamplesTest extends AbstractParserTest {
-public class AbstractExamplesTest {
-
- @Inject ParseHelper parseHelper;
-
public void assertExampleParses(String content) throws Exception {
T model = parseHelper.parse(content);
assertThat(model, notNullValue());
diff --git a/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractFormatterTest.java b/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractFormatterTest.java
index f586c84f..74d3c3c5 100644
--- a/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractFormatterTest.java
+++ b/org.agileware.natural.testing/src/org/agileware/natural/testing/AbstractFormatterTest.java
@@ -10,21 +10,21 @@
public class AbstractFormatterTest {
@Inject
- FormatterTestHelper formatterTestHelper;
+ protected FormatterTestHelper formatterTestHelper;
@Inject
- Provider formatterRequestProvider;
+ protected Provider formatterRequestProvider;
- public void assertFormatted(String toBeFormatted, String expectation) {
+ public void assertFormatted(final String toBeFormatted, final String expectation) {
formatterTestHelper.assertFormatted(
formatterRequestProvider.get()
- .setToBeFormatted(toBeFormatted)
- .setExpectation(expectation));
+ .setToBeFormatted(toBeFormatted)
+ .setExpectation(expectation));
}
- public void assertFormatted(String toBeFormatted) {
+ public void assertFormatted(final String toBeFormatted) {
formatterTestHelper.assertFormatted(
formatterRequestProvider.get()
- .setToBeFormatted(toBeFormatted));
+ .setToBeFormatted(toBeFormatted));
}
}
diff --git a/pom.xml b/pom.xml
index f36414ad..7e80da1d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,8 +8,8 @@
1.0.0-SNAPSHOT
- 2.21.0
- 2.11.2
+ 2.22.0
+ 2.11.3
UTF-8
1.8
1.8
@@ -22,8 +22,13 @@
- org.agileware.natural.common
- org.agileware.natural.common.feature
+ org.agileware.natural.stepmatcher
+ org.agileware.natural.stepmatcher.ui
+ org.agileware.natural.lang
+ org.agileware.natural.lang.ide
+ org.agileware.natural.lang.tests
+ org.agileware.natural.lang.ui
+ org.agileware.natural.lang.ui.tests
org.agileware.natural.cucumber
org.agileware.natural.cucumber.feature
org.agileware.natural.cucumber.ide
@@ -39,8 +44,6 @@
org.agileware.natural.jbehave.tests
org.agileware.natural.jbehave.ui.tests
org.agileware.natural.repository
- org.agileware.natural.stepmatcher
- org.agileware.natural.stepmatcher.feature
org.agileware.natural.testing
org.agileware.natural.target
diff --git a/runtime-workspace/cucumber-jvm5/src/test/java/org/example/cucumber/jvm5/StepDefinitions.java b/runtime-workspace/cucumber-jvm5/src/test/java/org/example/cucumber/jvm5/StepDefinitions.java
index 339cf5ee..811b9ac4 100644
--- a/runtime-workspace/cucumber-jvm5/src/test/java/org/example/cucumber/jvm5/StepDefinitions.java
+++ b/runtime-workspace/cucumber-jvm5/src/test/java/org/example/cucumber/jvm5/StepDefinitions.java
@@ -1,12 +1,11 @@
package org.example.cucumber.jvm5;
-import static org.junit.Assert.assertTrue;
-
import io.cucumber.java.en.Given;
public class StepDefinitions {
@Given("I have a matching step definition")
- public void i_have_a_matching_step_definition() {
- assertTrue("I have a matching step definition", true);
- }
+ public void i_have_a_matching_step_definition() {}
+
+ @Given("{string} has {int} matching step definitions")
+ public void actor_has_matching_step_definitions(String actor, Integer amount) {}
}
diff --git a/runtime-workspace/cucumber-jvm5/src/test/resources/org/example/cucumber/jvm5/hello_stepmatcher.feature b/runtime-workspace/cucumber-jvm5/src/test/resources/org/example/cucumber/jvm5/hello_stepmatcher.feature
index 7b937fe0..ba3ffdc2 100644
--- a/runtime-workspace/cucumber-jvm5/src/test/resources/org/example/cucumber/jvm5/hello_stepmatcher.feature
+++ b/runtime-workspace/cucumber-jvm5/src/test/resources/org/example/cucumber/jvm5/hello_stepmatcher.feature
@@ -1,4 +1,6 @@
# language: en
Feature: Hello, StepMatcher!
- Scenario:
- Given I have a matching step definition
+
+ Scenario:
+ Given I have a matching step definition
+ And "Bob" has 0 matching step definitions
diff --git a/runtime-workspace/example/features/full_example.feature b/runtime-workspace/example/features/full_example.feature
index 02a8efa4..00f256ce 100644
--- a/runtime-workspace/example/features/full_example.feature
+++ b/runtime-workspace/example/features/full_example.feature
@@ -3,48 +3,64 @@
@version:1.0.0
@pet_store
Feature: Add a new pet
+
+ """
In order to sell a pet
As a store owner
I want to add a new pet to the catalog
+ """
+
+ ,./;'[]\-=
+ <>?:"{}|_+
+ !@$%^&*()`~
+
+ | x | y |
+ | a | 0 |
+ | b | 1 |
+
+ 田中さんにあげて下さい
+ パーティーへ行かないか
-Background: Add a dog
- Given I have the following pet
- | name | status |
- | Fido | available |
- And I add the pet to the store
- But the pet is not yet mine
+ Background: Add a dog
+ Given I have the following pet
+ | name | status |
+ | Fido | available |
+ And I add the pet to the store
+ But the pet is not yet mine
-@add @fido
-Scenario: Add another dog
- Then the should be available in the store
+ @add
+ @fido
+ Scenario: Add another dog
+ Then the should be available in the store
-@update @fido
-Scenario:
- Given the pet is available in the store -9.8
- """
- The quick brown fox
- Jumps over the lazy dog
- """
- When I update the pet with
- | name | status |
- | Fido | unavailable |
- Then the pet should be "unavailable" in the store
+ @update
+ @fido
+ Scenario:
+ Given the pet is available in the store -9.8
+ """
+ The quick brown fox
+ Jumps over the lazy dog
+ """
+ When I update the pet with
+ | name | status |
+ | Fido | unavailable |
+ Then the pet should be "unavailable" in the store
-@eat-pickles
-Scenario Outline: Eating pickles
- Given there are pickles
- When I eat pickles
- Then I should have pickles
+ @eat-pickles
+ Scenario Outline: Eating pickles
+ Given there are pickles
+ When I eat pickles
+ Then I should have pickles
- @hungry
- Examples:
- | start | eat | left |
- | 12 | 10 | 2 |
- | 20 | 15 | 5 |
+ @hungry
+ Examples:
+ | start | eat | left |
+ | 12 | 10 | 2 |
+ | 20 | 15 | 5 |
- @full
- Examples: With a title
- | start | eat | left |
- | 12 | 2 | 10 |
- | 20 | 5 | 15 |
+ @full
+ Examples: With a title
+ | start | eat | left |
+ | 12 | 2 | 10 |
+ | 20 | 5 | 15 |
diff --git a/runtime-workspace/serenity-cucumber-bdd-screenplay b/runtime-workspace/serenity-cucumber-bdd-screenplay
new file mode 160000
index 00000000..abfc5130
--- /dev/null
+++ b/runtime-workspace/serenity-cucumber-bdd-screenplay
@@ -0,0 +1 @@
+Subproject commit abfc5130e7599006586c80c4c35a2cc2fe297d2a