Skip to content

Commit

Permalink
support for nested projects in VSCode
Browse files Browse the repository at this point in the history
  • Loading branch information
ydaveluy committed Apr 7, 2024
1 parent 6e54730 commit 82f05a3
Show file tree
Hide file tree
Showing 23 changed files with 284 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,27 @@ class XsmpcatIdeContentProposalProvider extends XsmpIdeContentProposalProvider {
array ${1:name} = ${2|«getCrossReferences(context.currentModel, XsmpPackage.Literals.ARRAY__ITEM_TYPE)»|}[$0]
''', "Create an Array Type", context), snippetPriority);
}
def protected complete_nativeType(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) {
acceptor.accept(getProposalCreator().createSnippet('''
/**
* @type native_type
* @location native_location
* @namespace native_namespace
* @uuid «generateUuid»
*/
class ${1:name}
''', "Create a Native type", context), snippetPriority);
}
def protected complete_attributeType(ContentAssistContext context, IIdeContentProposalAcceptor acceptor) {
acceptor.accept(getProposalCreator().createSnippet('''
/**
* // @allowMultiple
* @usage ...
* @uuid «generateUuid»
*/
attribute ${1|«getCrossReferences(context.currentModel, XsmpPackage.Literals.ATTRIBUTE_TYPE__TYPE)»|} ${2:name} = $0
''', "Create an Attribute type", context), snippetPriority);
}

def private String getCrossReferences(EObject eObject, EReference eReference) {
val scope = scopeProvider.getScope(eObject, eReference)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
package org.eclipse.xsmp.ide.hover;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.HoverParams;
import org.eclipse.xsmp.model.xsmp.NamedElement;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.ide.server.Document;
import org.eclipse.xtext.ide.server.hover.HoverContext;
import org.eclipse.xtext.ide.server.hover.HoverService;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.CancelIndicator;

import com.google.inject.Inject;
import com.google.inject.Singleton;
Expand Down Expand Up @@ -69,4 +72,18 @@ protected HoverContext createContext(Document document, XtextResource resource,
return super.createContext(document, resource, offset);
}

@Override
public Hover hover(Document document, XtextResource resource, HoverParams params,
CancelIndicator cancelIndicator)
{
try
{
return super.hover(document, resource, params, cancelIndicator);
}
catch (final IndexOutOfBoundsException e)
{
return null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class XsmpcatKeywordHovers implements IKeywordHovers {
<br />Optionally, the <b>PrimitiveType</b> used to encode the integer value may be specified (one of <b>Int8</b>, <b>Int16</b>, <b>Int32</b>, <b>Int64</b>, <b>UIn8</b>, <b>UInt16</b>, <b>UInt32</b>, <b>UInt64</b>, where the default is <b>Int32</b>).</p>
'''
case ga.namespaceMemberAccess.floatKeyword_3_10_2: '''
<p><code>«visibility()» «kw("float")» <em>name</em> [«kw("extends")» <em>(Float32|Float64)</em>] [«kw("in")» <em>(*|decimalExpression) ... (*|decimalExpression)</em>]</code></p>
<p><code>«visibility()» «kw("float")» <em>name</em> [«kw("extends")» <em>(Float32|Float64)</em>] [«kw("in")» <em>(*|decimalExpression) (...|<..|..<|<.<) (*|decimalExpression)</em>]</code></p>
<br/>
<p>A <b>Float</b> type represents floating-point values with a given range of valid values (via the Minimum and Maximum attributes).
<br />The MinInclusive and MaxInclusive attributes determine whether the boundaries are included in the range or not.
Expand Down Expand Up @@ -171,11 +171,23 @@ class XsmpcatKeywordHovers implements IKeywordHovers {
<br />The metaclasses derived from <b>SimpleValue</b>, however, are pre-defined and cannot be extended.</p>
'''
case ga.namespaceMemberAccess.nativeKeyword_3_14_2: '''
<p><code>
<span style="color: #3F5FBF;">
/**<br/>
* <strong><span style="color: #7F9FBF;">@namespace</span></strong> native_namespace<br/>
* <strong><span style="color: #7F9FBF;">@type</span></strong> native_typename<br/>
* <strong><span style="color: #7F9FBF;">@location</span></strong> native_location<br/>
*/</span><br/>
«visibility()» «kw("native")» <em>name</em>
</code></p>
<br/>
A <b>Native</b> Type specifies a type with any number of platform mappings. It is used to anchor existing or user-defined types into different target platforms.
<p>This mechanism is used within the specification to define the SMDL primitive types with respect to the Metamodel, but it can also be used to define native types within an arbitrary SMDL catalogue for use by models.
<br />In the latter case, native types are typically used to bind a model to some external library or existing Application Programming <b>Interface</b> (API).</p>
'''
case ga.namespaceMemberAccess.attributeKeyword_3_15_2: '''
<p><code>«visibility()» «kw("attribute")» <em>type name</em> = defaultValueExpression</code></p>
<br/>
An <b>Attribute</b> Type defines a new type available for adding attributes to elements.
<p><br />The AllowMultiple attribute specifies if a corresponding Attribute may be attached more than once to a language element, while the Usage element defines to which language elements attributes of this type can be attached.
<br />An attribute type always references a value type, and specifies a Default value.</p>
Expand All @@ -200,7 +212,7 @@ class XsmpcatKeywordHovers implements IKeywordHovers {
<br />These flags default to false, but can be changed from their default value to support dataflow-based design.</p>
'''
case ga.constantDeclarationAccess.constantKeyword_1: '''
<p><code>«visibility()» «kw("constant")» <em>type name</em> = valueExpression</code></p>
<p><code>«visibility()» «kw("constant")» <em>type name</em> = valueExpression</code></p>
<br/>
A <b>Constant</b> is a feature that is typed by a simple type and that must have a Value.
'''
Expand Down Expand Up @@ -292,6 +304,18 @@ class XsmpcatKeywordHovers implements IKeywordHovers {
case ga.visibilityModifiersAccess.publicKeyword_2: '''
The element is globally visible.
'''
case ga.classModifiersAccess.privateKeyword_0: '''
The type is visible only within its containing namespace.
'''
case ga.classModifiersAccess.protectedKeyword_1: '''
The type is visible within its containing containing <b>Catalogue</b>.
'''
case ga.classModifiersAccess.publicKeyword_2: '''
The type is globally visible.
'''
case ga.classModifiersAccess.abstractKeyword_3: '''
The type is abstract. Abstract types cannot be instantiated, but they can be subtyped.
'''
case ga.parameterDirectionKindAccess.inInKeyword_0_0: '''
The parameter is read-only to the operation, i.e. its value must be specified on call, and cannot be changed inside the operation.
'''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,16 @@ class XsmpprojectKeywordHovers implements IKeywordHovers {
case ga.sourcePathAccess.sourceKeyword_0: '''
<p><code>«kw("source")» <em>name</em></code></p>
<br/>
The <b>Source</b> defines the location of modeling files.
The <b>Source</b> directive defines the location of modeling files.
<br />It must be relative to project root.
<br />It can be a folder or a file name.
'''
case ga.sourcePathAccess.sourceKeyword_0: '''
<p><code>«kw("include")» <em>name</em></code></p>
<br/>
The <b>Include</b> directive defines the location of nested project(s).
<br />It must be relative to project root.
'''
case ga.projectReferenceAccess.dependencyKeyword_0: '''
<p><code>«kw("dependency")» <em>name</em></code></p>
<br/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
******************************************************************************/
package org.eclipse.xsmp.ide.labeling;

import java.net.URI;
import java.util.Collections;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -298,11 +297,11 @@ protected String text(Reference elem)

protected String text(SourcePath ele)
{
if (".".equals(ele.getName()))
if (ele.getName() == null || ele.getName().isEmpty())
{
return ele.getName();
return ".";
}
return URI.create(ele.getName()).normalize().getPath();
return ele.getName();
}

protected String text(ProjectReference ele)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xsmp.model.xsmp.VisibilityElement;
import org.eclipse.xsmp.model.xsmp.XsmpPackage;
import org.eclipse.xtext.ide.server.symbol.DocumentSymbolMapper.DocumentSymbolDetailsProvider;

public class XsmpDocumentSymbolDetailsProvider extends DocumentSymbolDetailsProvider
Expand All @@ -34,7 +35,16 @@ public String getDetails(EObject object)

switch (object.eClass().getClassifierID())
{
case SOURCE_PATH -> builder.append("Source");
case SOURCE_PATH -> {
if (object.eContainingFeature() == XsmpPackage.Literals.PROJECT__SOURCES)
{
builder.append("Source");
}
else
{
builder.append("Include");
}
}
case TOOL_REFERENCE -> builder.append("Tool");
case PROFILE_REFERENCE -> builder.append("Profile");
case PROJECT_REFERENCE -> builder.append("Dependency");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@
******************************************************************************/
package org.eclipse.xsmp.ide.workspace;

import java.net.URI;
import static org.eclipse.xtext.xbase.lib.IterableExtensions.findFirst;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.eclipse.emf.common.util.URI;
import org.eclipse.xsmp.model.xsmp.Project;
import org.eclipse.xsmp.model.xsmp.ProjectReference;
import org.eclipse.xsmp.model.xsmp.ToolReference;
import org.eclipse.xsmp.workspace.IXsmpProjectConfig;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.workspace.FileProjectConfig;
import org.eclipse.xtext.workspace.FileSourceFolder;
import org.eclipse.xtext.workspace.ISourceFolder;
import org.eclipse.xtext.workspace.IWorkspaceConfig;

public class XsmpProjectConfig extends FileProjectConfig implements IXsmpProjectConfig
Expand All @@ -31,6 +37,8 @@ public class XsmpProjectConfig extends FileProjectConfig implements IXsmpProject

private final List<String> dependencies;

private final Set<FileSourceFolder> includeFolders = new HashSet<>();

public XsmpProjectConfig(Project project, IWorkspaceConfig workspaceConfig)
{
super(EcoreUtil2.getNormalizedResourceURI(project).trimSegments(1), project.getName(),
Expand All @@ -41,8 +49,15 @@ public XsmpProjectConfig(Project project, IWorkspaceConfig workspaceConfig)
dependencies = project.getReferencedProjects().stream().map(ProjectReference::getName)
.filter(Objects::nonNull).toList();

project.getSources().forEach(folder -> addSourceFolder(".".equals(folder.getName()) ? ""
: URI.create(folder.getName()).normalize().getPath()));
project.getSources().forEach(folder -> addSourceFolder(folder.getName()));
project.getIncludes().forEach(folder -> addIncludeFolder(folder.getName()));
}

public FileSourceFolder addIncludeFolder(String relativePath)
{
final var includeFolder = new FileSourceFolder(this, relativePath);
includeFolders.add(includeFolder);
return includeFolder;
}

@Override
Expand Down Expand Up @@ -75,4 +90,16 @@ public int hashCode()
return super.hashCode();
}

@Override
public Set< ? extends ISourceFolder> getIncludeFolders()
{
return includeFolders;
}

@Override
public ISourceFolder findIncludeFolderContaining(URI member)
{
return findFirst(includeFolders, f -> f.contains(member));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.function.Predicate;

import org.eclipse.emf.common.util.URI;
import org.eclipse.xsmp.XsmpConstants;
Expand All @@ -30,6 +31,44 @@
public class XsmpProjectConfigFactory extends MultiProjectWorkspaceConfigFactory
{

private final class ProjectVisitor extends SimpleFileVisitor<Path>
{
private final WorkspaceConfig workspaceConfig;

private final Predicate<Path> filter;

private ProjectVisitor(WorkspaceConfig workspaceConfig, Predicate<Path> filter)
{
this.workspaceConfig = workspaceConfig;
this.filter = filter;
}

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
{
if (attrs.isSymbolicLink())
{
return FileVisitResult.SKIP_SUBTREE;
}
final var xsmpProjectFile = dir.resolve(XsmpConstants.XSMP_PROJECT_FILENAME);
if (filter.test(dir) && Files.exists(xsmpProjectFile))
{
final var config = projectConfigProvider.createProjectConfig(
URI.createFileURI(xsmpProjectFile.toString()), workspaceConfig);
workspaceConfig.addProject(config);
if (!config.getIncludeFolders().isEmpty())
{
Files.walkFileTree(Paths.get(config.getPath().path()),
new ProjectVisitor(workspaceConfig, p -> !p.equals(dir) && config
.findIncludeFolderContaining(URI.createFileURI(p.toString())) != null));
}

return FileVisitResult.SKIP_SUBTREE;
}
return super.preVisitDirectory(dir, attrs);
}
}

@Inject
private XsmpProjectConfigProvider projectConfigProvider;

Expand All @@ -47,25 +86,8 @@ public void findProjects(WorkspaceConfig workspaceConfig, URI uri)
}
try
{
Files.walkFileTree(Paths.get(baseFile.toURI()), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException
{
if (attrs.isSymbolicLink())
{
return FileVisitResult.SKIP_SUBTREE;
}
final var xsmpProjectFile = dir.resolve(XsmpConstants.XSMP_PROJECT_FILENAME);
if (Files.exists(xsmpProjectFile))
{
workspaceConfig.addProject(projectConfigProvider.createProjectConfig(
URI.createFileURI(xsmpProjectFile.toString()), workspaceConfig));
return FileVisitResult.SKIP_SUBTREE;
}
return super.preVisitDirectory(dir, attrs);
}
});
Files.walkFileTree(Paths.get(baseFile.toURI()),
new ProjectVisitor(workspaceConfig, p -> true));
}
catch (final IOException e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ public Collection<URI> initContainedURIs(String containerHandle)
final Set<URI> result = new HashSet<>();
for (final var source : settings.getSourceFolders())
{
if (".".equals(source.getName()) || source.getName().isEmpty())
final var path = source.getName();
if (path.isEmpty())
{
result.addAll(getMapper().getAllEntries(project).keySet());
}
else
{
final var path = source.getName();
final var f = project.getFolder(path);
if (f.exists())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
******************************************************************************/
package org.eclipse.xsmp.ui.labeling;

import java.net.URI;

import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.xsmp.model.xsmp.Document;
import org.eclipse.xsmp.model.xsmp.ProfileReference;
Expand Down Expand Up @@ -47,11 +45,11 @@ String image(Document ele)

String text(SourcePath ele)
{
if (".".equals(ele.getName()))
if (ele.getName() == null || ele.getName().isEmpty())
{
return ele.getName();
return ".";
}
return URI.create(ele.getName()).normalize().getPath();
return ele.getName();
}

String image(SourcePath ele)
Expand Down
Loading

0 comments on commit 82f05a3

Please sign in to comment.