private Set<String> outputFoldersForProject(final IJavaProject project) {
    final Set<String> outputFolders = new HashSet<String>();
    final IPath projectLocation = projectLocationPath(project);

    try {
      final IPath defaultOutputLocation = project.getOutputLocation();
      if (defaultOutputLocation != null) {
        final IPath fullPath = appendPathTo(projectLocation, defaultOutputLocation);
        if (fullPath.toFile().exists()) {
          outputFolders.add(fullPath.toOSString());
        }
      }
      for (final IClasspathEntry entry : project.getRawClasspath()) {
        if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
          final IPath outputLocation = entry.getOutputLocation();
          if (outputLocation != null) {
            final IPath fullPath = appendPathTo(projectLocation, outputLocation);
            if (fullPath.toFile().exists()) {
              outputFolders.add(fullPath.toOSString());
            }
          }
        }
      }
    } catch (final JavaModelException ex) {
      FeatureEditorPlugin.instance()
          .warn("Could not get output folder location for project " + project.getElementName());
    }

    return outputFolders;
  }
  @Override
  public Syntax from(final IProject project) {

    if (SubstepsNature.isSubstepsProject(project)) {
      final IJavaProject javaProject = new ProjectToJavaProjectTransformer().from(project);
      if (javaProject != null) {
        final ClassLoader classLoader = new JavaProjectClassLoader(javaProject);
        final Set<String> outputFolders = outputFoldersForProject(javaProject);
        final File substepsFolder =
            new File(projectManager.substepsFolderFor(project).toOSString());

        final List<Class<?>> stepClasses = new ArrayList<Class<?>>();
        for (final String outputFolder : outputFolders) {
          final ClassLocator classLocator = new StepClassLocator(outputFolder, classLoader);
          stepClasses.addAll(stepClasses(outputFolder, classLocator));
        }
        // augment step classes with externally dependent classes
        stepClasses.addAll(externalDependenciesFor(project, classLoader));

        try {
          return buildSyntaxFor(
              project, substepsFolder, stepClasses, classLoader, syntaxErrorReporterFor(project));
        } catch (final RuntimeException ex) {
          FeatureEditorPlugin.instance()
              .warn(
                  "Error when building syntax for project " + project + ": " + ex.getMessage(), ex);
        }
      }
    }
    // If we get to here, we can't resolve a valid syntax, return a null one
    final Syntax nullSyntax = new Syntax();
    nullSyntax.setSubStepsMap(new PatternMap<ParentStep>());
    return nullSyntax;
  }
 private Class<?> loadClass(final String stepClassName, final ClassLoader classLoader) {
   try {
     return classLoader.loadClass(stepClassName);
   } catch (final ClassNotFoundException ex) {
     FeatureEditorPlugin.instance().error("Could not load class " + stepClassName, ex);
     return null;
   }
 }
 private IRegion getLineRegionAtOffset(final IDocument document, final int offset) {
   try {
     return document.getLineInformationOfOffset(offset);
   } catch (final BadLocationException ex) {
     FeatureEditorPlugin.instance().error("Could not find line for offset " + offset, ex);
   }
   return null;
 }
 private boolean isJavaProject(final IProject project) {
   try {
     return project.hasNature(JavaCore.NATURE_ID);
   } catch (final CoreException e) {
     FeatureEditorPlugin.instance()
         .log(
             IStatus.WARNING,
             "Could not determine if project " + project.getName() + " is a java project");
     return false;
   }
 }
 private Collection<Class<?>> externalDependenciesFor(
     final IProject project, final ClassLoader classLoader) {
   final List<String> externalDependencies =
       FeatureEditorPlugin.instance().externalDependencyStepClasses(project);
   final Collection<Class<?>> classes = new ArrayList<Class<?>>(externalDependencies.size());
   for (final String className : externalDependencies) {
     final Class<?> clazz = loadClass(className, classLoader);
     if (clazz != null) {
       classes.add(clazz);
     }
   }
   return Collections.unmodifiableCollection(classes);
 }
  @Override
  public String getHoverInfo(final ITextViewer textViewer, final IRegion hoverRegion) {
    final IProject project = currentProject();

    final String line = lineFor(textViewer, hoverRegion);

    final Syntax syntax = FeatureEditorPlugin.instance().syntaxFor(project);

    final HoverModel hoverModel = hoverModelAtLine(line, syntax);
    if (hoverModel != null) {
      return hoverModel.serializeToString();
    }
    return null;
  }
 private String lineFor(final ITextViewer textViewer, final IRegion region) {
   try {
     return textViewer.getDocument().get(region.getOffset(), region.getLength()).trim();
   } catch (final BadLocationException e) {
     FeatureEditorPlugin.instance()
         .error(
             "Couldn't get line at region ("
                 + region.getOffset()
                 + ", "
                 + region.getLength()
                 + ")");
   }
   return null;
 }
  private List<StepImplementationsDescriptor> findStepImplementationDescriptorsForDependency(
      final String path) {
    JarFile jarFile = null;
    try {
      jarFile = new JarFile(new File(path));
      final List<StepImplementationsDescriptor> stepImplementationDescriptors =
          serializer.loadStepImplementationsDescriptorFromJar(jarFile);
      return stepImplementationDescriptors != null
          ? stepImplementationDescriptors
          : Collections.<StepImplementationsDescriptor>emptyList();
    } catch (final IOException ex) {
      FeatureEditorPlugin.instance().log(IStatus.WARNING, "Could not open jar file " + path);
    } finally {
      try {
        if (jarFile != null) {
          jarFile.close();
        }
      } catch (final IOException e) {
        FeatureEditorPlugin.instance().log(IStatus.WARNING, "Could not close jar file " + path);
      }
    }

    return Collections.<StepImplementationsDescriptor>emptyList();
  }
 @Override
 public String format(
     final String content,
     final boolean isLineStart,
     final String indentation,
     final int[] positions) {
   FeatureEditorPlugin.log(
       Status.INFO,
       "Formatting line: "
           + content
           + ", isLineStart: "
           + isLineStart
           + ", indentation: "
           + indentation);
   return super.format(content, isLineStart, indentation, positions);
 }
 private String[] findDependenciesFor(final IJavaProject javaProject) {
   try {
     final IPackageFragmentRoot[] fragmentRoots = javaProject.getPackageFragmentRoots();
     final Collection<String> rootPaths = new ArrayList<String>(fragmentRoots.length);
     for (int i = 0; i < fragmentRoots.length; i++) {
       final String path = getPathFor(fragmentRoots[i]);
       if (path != null) {
         rootPaths.add(path);
       }
     }
     return rootPaths.toArray(new String[rootPaths.size()]);
   } catch (final JavaModelException ex) {
     FeatureEditorPlugin.instance()
         .log(
             IStatus.WARNING,
             "Could not get package fragment roots for project "
                 + javaProject.getProject().getName());
     return new String[0];
   }
 }