Skip to content

Commit

Permalink
[Editor] Show a warning when editing a file that is not part of the e…
Browse files Browse the repository at this point in the history
…nvironment (#175)

A quick fix allows to automatically add the file to the environment.

Signed-off-by: Emmanuel Chebbi <[email protected]>
  • Loading branch information
echebbi authored and dvojtise committed Jul 16, 2020
1 parent 728195a commit a1a0bf8
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- [#115](https://github.com/gemoc/ale-lang/pull/115) The interpreter can be run by right-clicking on an ALE project
- [#129](https://github.com/gemoc/ale-lang/pull/129) The editor warns when the `+=` and `-=` operators ared used on the `result` variable in a void method
- [#131](https://github.com/gemoc/ale-lang/pull/131) The editor autocompletes attributes and methods of local variables and method parameters (support limited to model instances)
- [#153](https://github.com/gemoc/ale-lang/pull/153) The editor shows a warning when editing an _.ale_ source file that is not part of the project's ALE environment. A quick fix allows to automatically add the _.ale_ source file to the project's ALE environment
- [#169](https://github.com/gemoc/ale-lang/pull/169) The editor shows documentation about the _open_ and _behavior_ keywords on hover
- [#169](https://github.com/gemoc/ale-lang/pull/169) The editor shows the fully qualified name of an open class on hover as well as information about its EPackage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,73 @@
*/
package org.eclipse.emf.ecoretools.ui.quickfix

import java.util.Optional
import java.util.Set
import org.eclipse.core.resources.IFile
import org.eclipse.core.resources.ProjectScope
import org.eclipse.core.runtime.preferences.IEclipsePreferences
import org.eclipse.core.runtime.preferences.IScopeContext
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecoretools.ale.core.env.IAleEnvironment
import org.eclipse.emf.ecoretools.ale.core.env.impl.FileBasedAleEnvironment
import org.eclipse.emf.ecoretools.ale.core.io.IOResources
import org.eclipse.emf.ecoretools.ale.ide.project.IAleProject
import org.eclipse.emf.ecoretools.ale.xtext.ui.internal.XtextActivator
import org.eclipse.emf.ecoretools.validation.AleMarkerTypes
import org.eclipse.xtext.ui.editor.quickfix.DefaultQuickfixProvider
import org.eclipse.xtext.ui.editor.quickfix.Fix
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor
import org.eclipse.xtext.validation.Issue
import org.osgi.service.prefs.BackingStoreException

import static org.eclipse.emf.ecoretools.ale.ide.project.AleProjectPreferences.ALE_SOURCE_FILES

/**
* Custom quickfixes.
*
* See https://www.eclipse.org/Xtext/documentation/310_eclipse_support.html#quick-fixes
*/
class AleQuickfixProvider extends DefaultQuickfixProvider {

public static final String CORE_PLUGIN_ID = "org.eclipse.emf.ecoretools.ale.core";

// @Fix(AleValidator.INVALID_NAME)
// def capitalizeName(Issue issue, IssueResolutionAcceptor acceptor) {
// acceptor.accept(issue, 'Capitalize name', 'Capitalize the name.', 'upcase.png') [
// context |
// val xtextDocument = context.xtextDocument
// val firstLetter = xtextDocument.get(issue.offset, 1)
// xtextDocument.replace(issue.offset, 1, firstLetter.toUpperCase)
// ]
// }
@Fix(AleMarkerTypes.SOURCE_FILE_NOT_IN_ENV)
def capitalize(Issue issue, IssueResolutionAcceptor acceptor) {
acceptor.accept(issue, 'Add file to ALE environment', 'Adds the file to the project\'s ALE environment (either in the configured .dsl file\nor in project`s preferences)', 'upcase.png') [
context |
val xtextDocument = context.xtextDocument
val Optional<IFile> aleFile = IOResources.toIFile(xtextDocument.resourceURI)

if (aleFile.isPresent) {
val IAleProject project = IAleProject.from(aleFile.get.project)
val IAleEnvironment env = project.environment

val Set<String> aleSourceFilesPath = env.behaviorsSources
val URI aleFileURI = URI.createPlatformResourceURI(aleFile.get.fullPath.toString, true)
aleSourceFilesPath += aleFileURI.toString

if (project.isConfiguredFromPreferences) {
val IScopeContext projectContext = new ProjectScope(aleFile.get.project);
val IEclipsePreferences preferences = projectContext.getNode(CORE_PLUGIN_ID);
val commaSeparatedPaths = aleSourceFilesPath.map[trim].filter[!isEmpty].join(",")

try {
preferences.put(ALE_SOURCE_FILES.property, commaSeparatedPaths)
preferences.flush()
}
catch (IllegalStateException | BackingStoreException unlikelyToHappen) {
XtextActivator.instance.log.error("An unexpected error occurred while saving preferences", unlikelyToHappen);
}
}
else {
val dsl = project.findDslFile
if (dsl.isPresent) {
val FileBasedAleEnvironment dslEnv = IAleEnvironment.fromFile(dsl.get)
val IAleEnvironment newEnv = IAleEnvironment.fromPaths(env.metamodelsSources, aleSourceFilesPath)
dslEnv.save(newEnv)
}
}
}
]
}
}
11 changes: 10 additions & 1 deletion plugins/org.eclipse.emf.ecoretools.ale.xtext/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
<super type="org.eclipse.core.resources.problemmarker" />
<super type="org.eclipse.core.resources.textmarker" />
<persistent value="true" />
<super
type="org.eclipse.emf.ecoretools.ale.xtext.ui.ale.check.normal">
</super>
</extension>

<extension point="org.eclipse.core.resources.markers"
id="SourceFileNotInEnvironmentMarker"
name="ALE Problem">
<persistent value="true" />
<super type="org.eclipse.emf.ecoretools.ale.xtext.AleMarker" />
</extension>

</plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.eclipse.emf.ecoretools.validation

/**
* IDs of ALE markers.
*/
class AleMarkerTypes {

/**
* Default marker ID.
*/
public static val String DEFAULT = "org.eclipse.emf.ecoretools.ale.xtext.AleMarker"

/**
* Marker indicating that the source file is not in the project's ALE environment.
*/
public static val String SOURCE_FILE_NOT_IN_ENV = "org.eclipse.emf.ecoretools.ale.xtext.SourceFileNotInEnvironmentMarker"


}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ import org.eclipse.xtext.Keyword
import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.eclipse.xtext.validation.Check
import org.eclipse.xtext.validation.Issue

/**
* Delegate validation to ALE validator
*/
class AleValidator extends AbstractAleValidator {

public static String ALE_MARKER = "org.eclipse.emf.ecoretools.ale.xtext.AleMarker";

@Check
def checkIsValid(Unit root) {

Expand All @@ -56,6 +55,13 @@ class AleValidator extends AbstractAleValidator {
interpreter.initScope(Sets.newHashSet(),Sets.newHashSet(#[project.name]))
val parsedSemantics = env.behaviors.parsedFiles

val parsed = parsedSemantics.findFirst[sem | aleFile == IOResources.toIFile(new File(sem.sourceFile))]
val aleFileIsNotInEnv = parsed === null
if (aleFileIsNotInEnv) {
aleFile.createFileNotInEnvMarker()
return
}

/*
* Register services
*/
Expand Down Expand Up @@ -92,7 +98,7 @@ class AleValidator extends AbstractAleValidator {
.forEach[msg | markerFactory.doSwitch(msg)]
}
catch (Exception e) {
val marker = aleFile.createMarker(ALE_MARKER)
val marker = aleFile.createMarker(AleMarkerTypes.DEFAULT)
marker.setAttribute(IMarker.MESSAGE, "An internal error occurred while validating the file: " + e.message)
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR)
marker.setAttribute(IMarker.CHAR_START, 0)
Expand Down Expand Up @@ -162,6 +168,35 @@ class AleValidator extends AbstractAleValidator {
}

private def cleanUpMarkers(IFile file) {
file.deleteMarkers(ALE_MARKER, true, IResource.DEPTH_ZERO);
file.deleteMarkers(AleMarkerTypes.DEFAULT, true, IResource.DEPTH_ZERO);
file.deleteMarkers(AleMarkerTypes.SOURCE_FILE_NOT_IN_ENV, true, IResource.DEPTH_ZERO);
}

/** Adds a marker warning about the file not being part of ALE environment */
private static def createFileNotInEnvMarker(IFile file) {
val marker = file.createMarker(AleMarkerTypes.SOURCE_FILE_NOT_IN_ENV)
marker.setAttribute(IMarker.MESSAGE, "This file is not part of the project's ALE environment, it won't be validated")
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING)
marker.setAttribute(IMarker.CHAR_START, 0)
marker.setAttribute(IMarker.LINE_NUMBER, 0)
marker.setAttribute(IMarker.LOCATION, "line: " + 0 + " " + file.fullPath.toString())

// Attributes used by Xtext to find the associated quick fix

marker.setAttribute(Issue.CODE_KEY, AleMarkerTypes.SOURCE_FILE_NOT_IN_ENV)
marker.setAttribute(Issue.COLUMN_KEY, 0)
marker.setAttribute(Issue.URI_KEY, URI.createPlatformResourceURI(file.fullPath.toString(), true).toString)
marker.setAttribute("FIXABLE_KEY", true);

/*
* MUST BE SET LAST.
*
* Looks like the editor is updated when CHAR_END is set,
* and the editor must be updated once all other attributes
* are properly set.
*
* See https://www.eclipse.org/forums/index.php?t=msg&th=1104367&goto=1829410&#msg_1829410
*/
marker.setAttribute(IMarker.CHAR_END, 0)
}
}

0 comments on commit a1a0bf8

Please sign in to comment.