https://wiki.eclipse.org/api.php?action=feedcontributions&user=Ccaks.bestsolution.at&feedformat=atomEclipsepedia - User contributions [en]2024-03-28T08:52:52ZUser contributionsMediaWiki 1.26.4https://wiki.eclipse.org/index.php?title=Efxclipse/SmartCode&diff=412364Efxclipse/SmartCode2016-11-29T13:05:10Z<p>Ccaks.bestsolution.at: added styling info on resizeable popups, added styling info to line ruler</p>
<hr />
<div>{{Efxclipse}}<br />
<br />
e(fx)clipse provides a SmartCode-Editing Framework who can be embedded in fairly any application (not only OSGi)<br />
<br />
= Integration into OSGi =<br />
<br />
== Setup ==<br />
<br />
Before adding the source you need to configure your application to support the smart code editor. To make that happen you need to add the following bundle to a feature or create a new one:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.e4</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.fx</code><br />
* <code>org.eclipse.fx.code.editor.e4</code><br />
* <code>org.eclipse.fx.code.editor.fx</code><br />
* <code>org.eclipse.fx.code.editor.fx.e4</code><br />
<br />
== Basic Control with Syntax Highlighting ==<br />
<br />
=== Basics ===<br />
To make it easier to define syntax highlighting for any language the smart-code framework uses unlike the Eclipse IDE a declarative language named ldef.<br />
<br />
The first step when integrating a syntax highlighting editor into your application is to create a file ending with .ldef (eg java.ldef, ...).<br />
<br />
<source lang="java"><br />
package my.plugin<br />
<br />
js {<br />
partitioning {<br />
partition __dftl_partition_content_type<br />
partition __js_single_line_comment<br />
partition __js_multi_line_comment<br />
partition __js_string<br />
partition __js_regex<br />
rule {<br />
single_line __js_single_line_comment "//" => ''<br />
multi_line __js_multi_line_comment "/*" => "*/"<br />
single_line __js_string "'" => "'" escaped by "\\"<br />
single_line __js_string '"' => '"' escaped by "\\"<br />
single_line __js_regex '/' => '/' escaped by "\\"<br />
}<br />
}<br />
lexical_highlighting {<br />
rule __dftl_partition_content_type whitespace javawhitespace {<br />
default js_default<br />
js_operator {<br />
character [ <br />
';', '.', '=', '/', '\\', '+', '-', '*', <br />
'<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~' <br />
]<br />
}<br />
js_bracket {<br />
character [ '(', ')', '{', '}', '[', ']' ]<br />
}<br />
js_keyword {<br />
keywords [<br />
"break", "case", "catch", "continue",<br />
"debugger","default", "delete", "do",<br />
"else", "finally", "for", "function",<br />
"if", "in", "instanceof", "new",<br />
"return", "switch", "this", "throw",<br />
"try", "typeof", "var", "void",<br />
"while", "with" <br />
]<br />
}<br />
js_constant {<br />
keywords [ "true", "false", "undefined" ]<br />
}<br />
js_number {<br />
pattern "\\d" containing "[\\d|\\.]"<br />
}<br />
}<br />
rule __js_single_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_multi_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_string {<br />
default js_string<br />
}<br />
rule __js_regex {<br />
default js_string<br />
}<br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
}<br />
}<br />
</source><br />
<br />
As the smart code editor framework is built on top of the EclipseText-Framework you notice that the DSL aligns heavily to the concepts you find there:<br />
* Documents are first split in partitions (eg source-code, documentation, strings, ...)<br />
* Single Partitions are then split in tokens like constants, reserved words, ...<br />
* Tokens are then associated with styling information (color, font-weight,...)<br />
<br />
Once you created an ldef-File for your favorite language the Eclipse-Tooling will generate a total of 3 files in the src-gen folder:<br />
* <code>$language$.json</code>: Configuration data loaded at runtime and used to configure Eclipse Text<br />
* <code>$language$.css</code>: Styleing information when using JavaFX as the renderer<br />
* <code>$language$-swt-style.json</code>: Styleing information when using SWT as the renderer (we are not looking into this feature in this document)<br />
<br />
=== Dependencies ===<br />
To integrate a smart editor into your application you need to add dependencies to the following bundles your MANIFEST.MF:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.ui.services</code><br />
<br />
Or if you prefer the following package-imports:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.services</code><br />
* <code>org.eclipse.fx.ui.services.theme</code><br />
<br />
=== Editor Registration ===<br />
From the DSL we generated various artifacts are generated and we need to register them in the framework:<br />
* <code>$language$.json</code> file is registered through a <code>org.eclipse.fx.code.editor.configuration.text.ConfigurationModelProvider</code> OSGi-Service-Component<br />
* <code>$language$.css</code> file is registered through a <code>org.eclipse.fx.ui.services.theme.Stylesheet</code> OSGi-Service-Component<br />
<br />
Samples for JavaScript could look like this:<br />
<br />
'''ConfigurationModelProvider-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptConfigurationProvider implements ConfigurationModelProvider {<br />
@Override<br />
public boolean applies(Input<?> input) {<br />
return ((URIProvider)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public LanguageDef getModel(Input<?> input) {<br />
try(InputStream in = getClass().getResourceAsStream("js.json");<br />
Reader r = new InputStreamReader(in)) {<br />
return EditorGModel.create().createObject(r);<br />
} catch (IOException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
'''Stylesheet-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptStylesheet implements Stylesheet {<br />
@Override<br />
public boolean appliesToTheme(Theme t) {<br />
return true;<br />
}<br />
<br />
@Override<br />
public URL getURL(Theme t) {<br />
try {<br />
return new URL("platform:/plugin/my.plugin/my/plugin/js.css");<br />
} catch (MalformedURLException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
=== Syntax Highlighting ===<br />
If you remember the ldef file we shown above we defined the token styles like this:<br />
<source lang="java"><br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
</source><br />
<br />
The first segment in between <code>""</code> is the foreground color to be used but we are not directly putting the color values (eg #ff0000) there but color references who can be defined in another css. This allows us to easily ship them with themes eg a dark theme most likely would change the colors dramatically, ... .<br />
<br />
All e(fx)clipse applications have at least one theme with a basic css all than you have to do is to change that to define color constants for the above values. <br />
<br />
The perfect place is the .root-selector:<br />
<br />
<source lang="css"><br />
.root {<br />
-source-editor-code: rgb(0, 0, 0);<br />
-source-editor-operator: rgb(0, 0, 0);<br />
-source-editor-bracket: rgb(0, 0, 0);<br />
-source-editor-keyword: rgb(127, 0, 85);<br />
-source-editor-string: rgb(42, 0, 255);<br />
-source-editor-number: #6c83c4;<br />
-source-editor-doc: rgb(63, 127, 95);<br />
}<br />
</source><br />
<br />
The above color specs provide you a eclipse like syntax highlighting.<br />
<br />
=== Editor visual customization ===<br />
<br />
Syntax colors are defined as shown above but to customize other areas of your code area the following CSS will be of great help to you:<br />
* '''.styled-text-area .invisible-char''':<br/>selector for a specialized node which is a subtype of <code>javafx.scene.text.Text</code> and additionally allows to set an -fx-content property for the text displayed<br />
* '''.styled-text-area .invisible-char.space''':<br/>selector to configure what text to display for spaces<br />
* '''.styled-text-area .invisible-char.tab''':<br/>selector to configure what text to display for tabs<br />
* '''.styled-text-area .invisible-char.enter''':<br/>selector to configure what text<br />
* '''.source-viewer.styled-text-area .selection-marker''':<br/>selector to configure how a selected area is display most likely you want to customize the -fx-background-color - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .list-view''':<br/>the content area of the text editor which is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .current-line''':<br/> selector to configure how the current cursor line is displayed - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .line-ruler-text''':<br/> selector to configure how the text in the line ruler is displayed<br />
* '''.styled-text-area .text-caret''':<br/> selector to configure how the text-caret is rendered - the javafx-Node is of type <code>javafx.scene.shape.Shape</code><br />
* '''.styled-text-hover .errors''':<br/> selector to configure how the error hover popup is displayed<br />
* '''.styled-text-hover .warnings''':<br/> selector to configure how the warnings hover popup is displayed<br />
* '''.styled-text-hover .infos''':<br/> selector to configure how the infos hover popup is displayed<br />
* '''.styled-text-hover .docs''':<br/> selector to configure how the doc hover popup is displayed<br />
* '''.styled-text-hover .others''':<br/> selector to configure how the others hover popup is displayed<br />
* '''.styled-text-hover .context-info''':<br/> selector to configure how the warnings hover popup is displayed<br />
<br />
=== Open an editor ===<br />
<br />
==== Using the editor opener service ====<br />
The smart code framework by default publishes an <code>org.eclipse.fx.code.editor.services.EditorOpener</code>-Service who can be retrieved via injection and used to open an editor based on an URI like this<br />
<br />
<source lang="java"><br />
class MyComponent {<br />
@Inject<br />
EditorOpener opener;<br />
<br />
private void openFile(File f) {<br />
opener.openEditor( f.toURI().toURL().toExternalForm() );<br />
} <br />
}<br />
</source><br />
<br />
The default implementation of the opener function will search the window/perspective for a <code>MElementContainer</code> tagged with <code>editorContainer</code>, so if you want to use that service you need to update your application model and tag eg one of your <code>MPartStack</code>s with it.<br />
<br />
==== Doing it yourself ====<br />
If you don't want to use the EditorOpener-Service but do things yourself all you need to do is to create an MPart instance like this:<br />
<br />
<source lang="java"><br />
EModelService modelService = // ...;<br />
MPart part = modelService.createModelElement(MPart.class);<br />
part.setCloseable(true);<br />
part.setLabel("MySample.js");<br />
part.setContributionURI("bundleclass://org.eclipse.fx.code.editor.fx/org.eclipse.fx.code.editor.fx.TextEditor");<br />
part.getPersistedState().put(org.eclipse.fx.code.editor.Constants.DOCUMENT_URL, uri);<br />
part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);<br />
// ...<br />
</source><br />
<br />
== Dirty State Tracking & Save ==<br />
As we don't want to force you into predefined start-state and save strategy we don't push support to your application by default but require you to handle that yourself. What we provide are to base implementation:<br />
* An addon who does the dirty state tracking <code>org.eclipse.fx.code.editor.e4.addons.DirtyStateTrackingAddon</code><br />
* A handler who saves the file a dirty file <code>org.eclipse.fx.code.editor.e4.handlers.SaveFile</code><br />
<br />
== Adding support for Autocomplete Features ==<br />
First of providing auto-completion is an optional feature you can provide for your language. Adding support is done with 2 distinct services:<br />
* list of proposals: <code>org.eclipse.fx.code.editor.services.ProposalComputer</code><br />
* (optional) presentation of proposals: <code>org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenter</code><br />
<br />
To register both services you need to push the following services to the OSGi-Service-Registry:<br />
* org.eclipse.fx.code.editor.services.ProposalComputerTypeProvider<br />
* org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenterTypeProvider<br />
<br />
For a potential JavaScript-Editor the providers could look like this:<br />
<source lang="java"><br />
@Component<br />
public class JSProposalComputerTypeProvider implements ProposalComputerTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends ProposalComputer> getType(Input<?> input) {<br />
return JSProposalComputer.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
@Component<br />
public class JSCompletionProposalPresenterTypeProvider implements CompletionProposalPresenterTypeProvider {<br />
@Override<br />
public Class<? extends CompletionProposalPresenter> getType(Input<?> s) {<br />
return JSCompletionProposalPresenter.class;<br />
}<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
The cool thing about JSProposalComputer & JSCompletionProposalPresenter is that they are created per editor instance and so you can access all informations available for an editor through Eclipse DI.<br />
<br />
The computer is responsible to talk to your language framework to detect what auto-completions are available (eg methods, ...)<br />
<source lang="java"><br />
public class JSProposalComputer implements ProposalComputer {<br />
private Logger logger;<br />
@Inject<br />
JSProposalComputer(@Log Logger logger /* more stuff */) {<br />
this.logger = logger;<br />
}<br />
<br />
public CompletableFuture<List<CompletionProposal>> compute(ProposalContext context) {<br />
// ... produce a JSCompletionProposal<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java DartProposalComputer.java]<br />
<br />
The presenter on the other hand takes the proposal objects and translates them into text and graphic informations shown by the proposal dialog.<br />
<source lang="java"><br />
public class JSCompletionProposalPresenter implements CompletionProposalPresenter {<br />
private final GraphicsLoader graphicsLoader;<br />
<br />
@Inject<br />
public DartCompletionProposalPresenter(GraphicsLoader graphicsLoader) {<br />
this.graphicsLoader = graphicsLoader;<br />
}<br />
<br />
@Override<br />
public ICompletionProposal createProposal(CompletionProposal proposal) {<br />
JSCompletionProposal p = (JSCompletionProposal) proposal;<br />
String label = p.getProposalText();<br />
Node imageNode = p.getJSType().equals("method") ? new ImageView("method.png") : new ImageView("field.png");<br />
// ...<br />
return new FXCompletionProposal( proposal, label, () -> imageNode, null, null );<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java DartCompletionProposalPresenter.java]<br />
<br />
=== Function Context Information ===<br />
TBD - see <br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartContextInformationPresenter.java<br />
<br />
== Adding support for Error-Markers ==<br />
Errors, Warnings, ... are presented called Annotations and there are 2 ways to present them in the editor:<br />
* as part of the line-ruler on the left<br />
* as part of the text-content eg underlining the text<br />
<br />
=== Providing annotations ===<br />
The first and mandatory step to show annotations in an editor is to provide an instance <code>org.eclipse.jface.text.source.AnnotationModel</code> for your language. The model keeps track of <code>org.eclipse.jface.text.source.Annotation</code>.<br />
<br />
To instruct the framework to build such a model you need to register an <code>org.eclipse.fx.code.editor.services.AnnotationModelTypeProvider</code> following the same steps you used for the auto-complete:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationModelTypeProvider implements AnnotationModelTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends IAnnotationModel> getType(Input<?> input) {<br />
return JSAnnotationModel.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
public class JSAnnotationModel extends AnnotationModel {<br />
private final ThreadSynchronize synchronize;<br />
<br />
@Inject<br />
public JSAnnotationModel(Input<?> input, ThreadSynchronize synchronize) {<br />
// observe the input and when there are compile errors update<br />
// the annotations<br />
}<br />
}<br />
</source><br />
=== Presenting annotations ===<br />
Once there's an annotation model for your language you can present it in the UI by providing an <code>org.eclipse.fx.text.ui.source.AnnotationPresenter</code> which is following the scheme you used for all other services already. <br />
<br />
You register an OSGi-Service of type <code>org.eclipse.fx.code.editor.fx.services.AnnotationPresenterTypeProvider</code> similar to this:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationPresenterTypeProvider implements AnnotationPresenterTypeProvider {<br />
@Override<br />
public Class<? extends AnnotationPresenter> getType(Input<?> s) {<br />
return JSAnnotationPresenter.class;<br />
}<br />
<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
==== Presenting annotations in line ruler ====<br />
The annotation presenter distinguishes between 2 presentation types:<br />
* <code>org.eclipse.fx.text.ui.source.ILineRulerAnnotationPresenter</code><br />
* <code>org.eclipse.fx.text.ui.source.ITextAnnotationPresenter</code><br />
<br />
To show annotations in the line ruler you need to implement the first one.<br />
<br />
===== Line Ruler Styling =====<br />
There are several possibilities to style the line ruler area:<br />
<br />
The line ruler structure is as follows:<br />
<br />
<source lang="css"><br />
.styled-text-area HBox.line-ruler-area {<br />
/* the whole area of the line ruler */<br />
}<br />
</source><br />
<source lang="css"><br />
.styled-text-area HBox.line-ruler-area > Pane.line-ruler {<br />
/* every line ruler instance */<br />
}<br />
</source><br />
<source lang="css"><br />
.styled-text-area HBox.line-ruler-area > Pane.line-ruler.specific-line-ruler-style-class {<br />
/* a specific line ruler instance */<br />
}<br />
</source><br />
where the <code>.specific-line-ruler-style-class</code> is definined by implementing the <code>ILineRulerAnnotationPresenter#getStyleClass()</code> method<br />
<source lang="css"><br />
/* also there is a spacer between the line ruler area and the editor area <br />
it can be styled like this:<br />
*/<br />
.styled-text-area .spacer {<br />
}<br />
</source><br />
<br />
==== Presenting annotations as text-overlays ====<br />
To provide text-markers all you need to do is to provide an implementation of <code>ITextAnnotationPresenter</code><br />
<source lang="java"><br />
public class TextMarker implements ITextAnnotationPresenter {<br />
@Override<br />
public boolean isApplicable(Annotation annotation) {<br />
return annotation instanceof DartAnnotation;<br />
}<br />
<br />
@Override<br />
public Node createNode() {<br />
return new Region();<br />
}<br />
<br />
@Override<br />
public void updateNode(Node node, Annotation annotation) {<br />
Region r = (Region) node;<br />
<br />
JSAnnotation a = (JSAnnotation) annotation;<br />
<br />
Color c;<br />
switch (a.getError().getSeverity()) {<br />
case ERROR: c = Color.RED; break;<br />
case WARNING: c = Color.DARKORANGE; break;<br />
default:<br />
case INFO: c = Color.BLANCHEDALMOND; break;<br />
}<br />
r.setBorder(new Border(new BorderStroke(c, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(0, 0, 1.5, 0))));<br />
}<br />
<br />
@Override<br />
public String toString() {<br />
return "JSTextMarkerAP@" + hashCode();<br />
}<br />
}<br />
</source><br />
== Code navigation ==<br />
=== Code link ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProviderTypeProvider.java<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProvider.java<br />
<br />
=== Keyboard Navigation ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/DartBehaviorContributor.java<br />
<br />
== Context information ==<br />
The context information is a popup providing additional information for the current context (caret offset).<br />
For example to display the argument types of a method invocation while typing.<br />
<br />
There are 2 ways to trigger a context information:<br />
* by providing a <code>ContextInformation</code> with the <code>CompletionProposal</code><br />
* by calling <code>EditingContext#showContextInformation(ContextInformation)</code><br />
<br />
=== implicit with CompletionProposal ===<br />
If the <code>CompletionProposal</code> contains a <code>ContextInformation</code> the context information will be automatically triggered after the completion proposal was chosen at the current caret offset. (The offset of the ContextInformation is ignored)<br />
<br />
=== explicit via EditingContext ===<br />
By invoking <code>EditingContext#showContextInformation(ContextInformation)</code> the context information will be immediately shown at the specified offset.<br />
<br />
<br />
<br />
== Hover information ==<br />
<br />
=== HTML Support ===<br />
The API always uses a <code>CharSequence</code> to transport the Hover Content. <br />
There is a <code>HtmlString</code> class which allows to pass html to the hovers.<br />
To use ist simply create an instance of it and pass it to the corresponding hover api<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
<br />
HtmlString data = new HtmlString("<h1>Very nice!</h1><div>indeed</div>");<br />
<br />
// in CompletionProposalPresenter#createProposal(CompletionProposal)<br />
return new ICompletionProposal() {<br />
...<br />
public CharSequence getHoverInfo() { return data; }<br />
...<br />
};<br />
// in DocumentHoverProvider#getHoverInfo(IDocument, int)<br />
return Collections.singleton(new HoverInfo(DefaultHoverInfoType.DOCUMENTATION, region, data, null));<br />
<br />
<br />
<br />
</source><br />
<br />
==== Links ====<br />
The <code>HtmlString</code> also allows the use of hyperlinks. <br />
Here is an example<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
import org.eclipse.fx.text.hover.LinkActionEvent;<br />
<br />
HtmlString data = new HtmlString("<h1>Interactive</h1><div><a href="foo">Foo</a> / <a href="bar">BAR</a></div>");<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_ACTION, e -> {<br />
System.err.println("The link was activated: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_CONTEXT, e -> {<br />
System.err.println("The link was right clicked: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
</source><br />
The link target always contains the content of href, while screenX and screenY contain the screen coordinates of the mouse click.<br />
<br />
<br />
== Styling of resizeable popups ==<br />
(This applies to the ''Hover Information'' and the ''Autocompletion'' popup)<br />
<br />
The Popup's root container is a customized Region with the styleclass <code>.resize-popup-pane</code>. <br />
It supports all css properties from Region and additionally <code>-efx-resize-handle-size</code>. <br />
<code>-efx-resize-handle-size</code> is in the standard JavaFX size format (see [https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#typesize JavaFX CSS Spec <size>])<br />
<br />
The root container renders the handles to resize the popup around its content. The handle size specifies their size and the actual content is inset by the handle size.<br />
The visible border seen by the user and used to grab and resize the window is actually the background of the Region.<br />
<br />
Keep in mind when setting a transparent background: JavaFX on Linux only captures mouse events if the overall transparancy is above 0.5<br />
<br />
Here is its default style:<br />
<source lang="css"><br />
.resize-popup-pane {<br />
-fx-background-color: rgba(20, 20, 20, 0.7);<br />
-fx-background-radius: 5px;<br />
-efx-resize-handle-size: 5px;<br />
}<br />
</source><br />
<br />
<br />
<br />
== Pair matching ==<br />
https://github.com/BestSolution-at/dartedit/tree/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/pair<br />
<br />
== Predefined annotations like Linenumbers, ... ==<br />
There are currently 2 predefined control annotations found in <code>org.eclipse.fx.text.ui.Feature</code>:<br />
* <code>SHOW_LINE_NUMBERS</code>: showing a ruler on the left with linenumbers (on by default)<br />
* <code>SHOW_HIDDEN_SYMBOLS</code>: displaying informations about whitespace characters like tab, line-breaks (off by default)<br />
<br />
Features are provided by <code>SourceViewerConfiguration#getFeatures() : SetProperty&lt;Feature&gt;</code> and modifying the provided Set instance - adding/removeing features - updates the editor bound to it.<br />
<br />
=== Using preferences ===<br />
When using the framework in an e4 application where <code>DefaultSourceViewerConfiguration</code> one can also use the preference system to set the features and restore them the current feature settings are stored with <br />
* key: <code>Constants.PREFERENCE_KEY_EDITOR_FEATURE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
or expressed through the e(fx)clipse DI-Addons<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Set<Feature> featureSet;<br />
</source><br />
<br />
or if you want to publish <br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Property<Set<Feature>> featureSet;<br />
</source><br />
<br />
As toggling features is a standard task there's a default handler implementation (<code>org.eclipse.fx.code.editor.fx.handlers.ToggleEditorFeature</code>) available for this task which you can register in your e4xmi-File. The command-parameter you need to pass is named <code>feature</code> and you pass in the feature name as a string.<br />
<br />
== Tabs and Spaces ==<br />
<br />
=== Tab Advance ===<br />
By default a tab (\t) character advances in the text 4 characters. If you want to customize this you need make use of the Preference-System with:<br />
* key: <code>Constants.PREFERENCE_TAB_ADVANCE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
So if you want to modify the tab-advance for the editor you can use the e(fx)clipse DI-Extensions like this:<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_TAB_ADVANCE,nodePath=Constants.PREFERENCE_NODE_PATH)<br />
Property<Integer> tabAdvancePreference;<br />
</source><br />
<br />
As updateing the tabAdvance is a standard task there's a handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.SetTabAdvance</code> who accepts a command-parameter named tabAdvance.<br />
<br />
=== Tabs instead of white spaces ===<br />
By default the control inserts a tab (\t) character if you press the tab-key but if you want to insert a certain amount of spaces instead you can configure the editor to act like that by toggleing the preference with:<br />
* key: <code>Constants.PREFERENCE_SPACES_FOR_TAB</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
As toggling the preference is a standard task there's handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.ToggleInsertSpacesForTab</code><br />
<br />
== The InputContext ==<br />
The <code>org.eclipse.fx.code.editor.InputContext</code> is a way to group inputs in a logical context (comparable to a project in your eclipse instance) by default all <code>Input</code> instances are grouped in a default-context but you are free to provide your own logic by registering a service of type <code>org.eclipse.fx.code.editor.services.InputContextProvider</code> in the service registry.<br />
<br />
== Dynamic Lexical Highlightings ==<br />
There are chances that you want to color things like library functions in your UI but those can not be preconfigured because eg they depend on what libraries you have in your application, version of your language you develop against, ...<br />
<br />
The code editing framework has support to dynamically add/remove lexical highlighting rules (even to an already opened editor). The service API responsible to provide rules dynamically is <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculator</code>. To register this service you need to push an instance of <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculatorTypeProvider</code>.<br />
<br />
A good idea to handle this stuff is to use make use of the <code>InputContext</code> in your <code>DynamicScannerRuleCalculator</code> who is grouping all editors.<br />
<br />
= Sample =<br />
The most complete sample showing the complete framework with all its features in action can be found at [https://github.com/BestSolution-at/dartedit github] implementing a Dart-Code-Editor</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/SmartCode&diff=409035Efxclipse/SmartCode2016-08-24T15:25:29Z<p>Ccaks.bestsolution.at: </p>
<hr />
<div>{{Efxclipse}}<br />
<br />
e(fx)clipse provides a SmartCode-Editing Framework who can be embedded in fairly any application (not only OSGi)<br />
<br />
= Integration into OSGi =<br />
<br />
== Setup ==<br />
<br />
Before adding the source you need to configure your application to support the smart code editor. To make that happen you need to add the following bundle to a feature or create a new one:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.e4</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.fx</code><br />
* <code>org.eclipse.fx.code.editor.e4</code><br />
* <code>org.eclipse.fx.code.editor.fx</code><br />
* <code>org.eclipse.fx.code.editor.fx.e4</code><br />
<br />
== Basic Control with Syntax Highlighting ==<br />
<br />
=== Basics ===<br />
To make it easier to define syntax highlighting for any language the smart-code framework uses unlike the Eclipse IDE a declarative language named ldef.<br />
<br />
The first step when integrating a syntax highlighting editor into your application is to create a file ending with .ldef (eg java.ldef, ...).<br />
<br />
<source lang="java"><br />
package my.plugin<br />
<br />
js {<br />
partitioning {<br />
partition __dftl_partition_content_type<br />
partition __js_single_line_comment<br />
partition __js_multi_line_comment<br />
partition __js_string<br />
partition __js_regex<br />
rule {<br />
single_line __js_single_line_comment "//" => ''<br />
multi_line __js_multi_line_comment "/*" => "*/"<br />
single_line __js_string "'" => "'" escaped by "\\"<br />
single_line __js_string '"' => '"' escaped by "\\"<br />
single_line __js_regex '/' => '/' escaped by "\\"<br />
}<br />
}<br />
lexical_highlighting {<br />
rule __dftl_partition_content_type whitespace javawhitespace {<br />
default js_default<br />
js_operator {<br />
character [ <br />
';', '.', '=', '/', '\\', '+', '-', '*', <br />
'<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~' <br />
]<br />
}<br />
js_bracket {<br />
character [ '(', ')', '{', '}', '[', ']' ]<br />
}<br />
js_keyword {<br />
keywords [<br />
"break", "case", "catch", "continue",<br />
"debugger","default", "delete", "do",<br />
"else", "finally", "for", "function",<br />
"if", "in", "instanceof", "new",<br />
"return", "switch", "this", "throw",<br />
"try", "typeof", "var", "void",<br />
"while", "with" <br />
]<br />
}<br />
js_constant {<br />
keywords [ "true", "false", "undefined" ]<br />
}<br />
js_number {<br />
pattern "\\d" containing "[\\d|\\.]"<br />
}<br />
}<br />
rule __js_single_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_multi_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_string {<br />
default js_string<br />
}<br />
rule __js_regex {<br />
default js_string<br />
}<br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
}<br />
}<br />
</source><br />
<br />
As the smart code editor framework is built on top of the EclipseText-Framework you notice that the DSL aligns heavily to the concepts you find there:<br />
* Documents are first split in partitions (eg source-code, documentation, strings, ...)<br />
* Single Partitions are then split in tokens like constants, reserved words, ...<br />
* Tokens are then associated with styling information (color, font-weight,...)<br />
<br />
Once you created an ldef-File for your favorite language the Eclipse-Tooling will generate a total of 3 files in the src-gen folder:<br />
* <code>$language$.json</code>: Configuration data loaded at runtime and used to configure Eclipse Text<br />
* <code>$language$.css</code>: Styleing information when using JavaFX as the renderer<br />
* <code>$language$-swt-style.json</code>: Styleing information when using SWT as the renderer (we are not looking into this feature in this document)<br />
<br />
=== Dependencies ===<br />
To integrate a smart editor into your application you need to add dependencies to the following bundles your MANIFEST.MF:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.ui.services</code><br />
<br />
Or if you prefer the following package-imports:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.services</code><br />
* <code>org.eclipse.fx.ui.services.theme</code><br />
<br />
=== Editor Registration ===<br />
From the DSL we generated various artifacts are generated and we need to register them in the framework:<br />
* <code>$language$.json</code> file is registered through a <code>org.eclipse.fx.code.editor.configuration.text.ConfigurationModelProvider</code> OSGi-Service-Component<br />
* <code>$language$.css</code> file is registered through a <code>org.eclipse.fx.ui.services.theme.Stylesheet</code> OSGi-Service-Component<br />
<br />
Samples for JavaScript could look like this:<br />
<br />
'''ConfigurationModelProvider-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptConfigurationProvider implements ConfigurationModelProvider {<br />
@Override<br />
public boolean applies(Input<?> input) {<br />
return ((URIProvider)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public LanguageDef getModel(Input<?> input) {<br />
try(InputStream in = getClass().getResourceAsStream("js.json");<br />
Reader r = new InputStreamReader(in)) {<br />
return EditorGModel.create().createObject(r);<br />
} catch (IOException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
'''Stylesheet-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptStylesheet implements Stylesheet {<br />
@Override<br />
public boolean appliesToTheme(Theme t) {<br />
return true;<br />
}<br />
<br />
@Override<br />
public URL getURL(Theme t) {<br />
try {<br />
return new URL("platform:/plugin/my.plugin/my/plugin/js.css");<br />
} catch (MalformedURLException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
=== Syntax Highlighting ===<br />
If you remember the ldef file we shown above we defined the token styles like this:<br />
<source lang="java"><br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
</source><br />
<br />
The first segment in between <code>""</code> is the foreground color to be used but we are not directly putting the color values (eg #ff0000) there but color references who can be defined in another css. This allows us to easily ship them with themes eg a dark theme most likely would change the colors dramatically, ... .<br />
<br />
All e(fx)clipse applications have at least one theme with a basic css all than you have to do is to change that to define color constants for the above values. <br />
<br />
The perfect place is the .root-selector:<br />
<br />
<source lang="css"><br />
.root {<br />
-source-editor-code: rgb(0, 0, 0);<br />
-source-editor-operator: rgb(0, 0, 0);<br />
-source-editor-bracket: rgb(0, 0, 0);<br />
-source-editor-keyword: rgb(127, 0, 85);<br />
-source-editor-string: rgb(42, 0, 255);<br />
-source-editor-number: #6c83c4;<br />
-source-editor-doc: rgb(63, 127, 95);<br />
}<br />
</source><br />
<br />
The above color specs provide you a eclipse like syntax highlighting.<br />
<br />
=== Editor visual customization ===<br />
<br />
Syntax colors are defined as shown above but to customize other areas of your code area the following CSS will be of great help to you:<br />
* '''.styled-text-area .invisible-char''':<br/>selector for a specialized node which is a subtype of <code>javafx.scene.text.Text</code> and additionally allows to set an -fx-content property for the text displayed<br />
* '''.styled-text-area .invisible-char.space''':<br/>selector to configure what text to display for spaces<br />
* '''.styled-text-area .invisible-char.tab''':<br/>selector to configure what text to display for tabs<br />
* '''.styled-text-area .invisible-char.enter''':<br/>selector to configure what text<br />
* '''.source-viewer.styled-text-area .selection-marker''':<br/>selector to configure how a selected area is display most likely you want to customize the -fx-background-color - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .list-view''':<br/>the content area of the text editor which is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .current-line''':<br/> selector to configure how the current cursor line is displayed - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .line-ruler-text''':<br/> selector to configure how the text in the line ruler is displayed<br />
* '''.styled-text-area .text-caret''':<br/> selector to configure how the text-caret is rendered - the javafx-Node is of type <code>javafx.scene.shape.Shape</code><br />
* '''.styled-text-hover .errors''':<br/> selector to configure how the error hover popup is displayed<br />
* '''.styled-text-hover .warnings''':<br/> selector to configure how the warnings hover popup is displayed<br />
* '''.styled-text-hover .infos''':<br/> selector to configure how the infos hover popup is displayed<br />
* '''.styled-text-hover .docs''':<br/> selector to configure how the doc hover popup is displayed<br />
* '''.styled-text-hover .others''':<br/> selector to configure how the others hover popup is displayed<br />
* '''.styled-text-hover .context-info''':<br/> selector to configure how the warnings hover popup is displayed<br />
<br />
=== Open an editor ===<br />
<br />
==== Using the editor opener service ====<br />
The smart code framework by default publishes an <code>org.eclipse.fx.code.editor.services.EditorOpener</code>-Service who can be retrieved via injection and used to open an editor based on an URI like this<br />
<br />
<source lang="java"><br />
class MyComponent {<br />
@Inject<br />
EditorOpener opener;<br />
<br />
private void openFile(File f) {<br />
opener.openEditor( f.toURI().toURL().toExternalForm() );<br />
} <br />
}<br />
</source><br />
<br />
The default implementation of the opener function will search the window/perspective for a <code>MElementContainer</code> tagged with <code>editorContainer</code>, so if you want to use that service you need to update your application model and tag eg one of your <code>MPartStack</code>s with it.<br />
<br />
==== Doing it yourself ====<br />
If you don't want to use the EditorOpener-Service but do things yourself all you need to do is to create an MPart instance like this:<br />
<br />
<source lang="java"><br />
EModelService modelService = // ...;<br />
MPart part = modelService.createModelElement(MPart.class);<br />
part.setCloseable(true);<br />
part.setLabel("MySample.js");<br />
part.setContributionURI("bundleclass://org.eclipse.fx.code.editor.fx/org.eclipse.fx.code.editor.fx.TextEditor");<br />
part.getPersistedState().put(org.eclipse.fx.code.editor.Constants.DOCUMENT_URL, uri);<br />
part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);<br />
// ...<br />
</source><br />
<br />
== Dirty State Tracking & Save ==<br />
As we don't want to force you into predefined start-state and save strategy we don't push support to your application by default but require you to handle that yourself. What we provide are to base implementation:<br />
* An addon who does the dirty state tracking <code>org.eclipse.fx.code.editor.e4.addons.DirtyStateTrackingAddon</code><br />
* A handler who saves the file a dirty file <code>org.eclipse.fx.code.editor.e4.handlers.SaveFile</code><br />
<br />
== Adding support for Autocomplete Features ==<br />
First of providing auto-completion is an optional feature you can provide for your language. Adding support is done with 2 distinct services:<br />
* list of proposals: <code>org.eclipse.fx.code.editor.services.ProposalComputer</code><br />
* (optional) presentation of proposals: <code>org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenter</code><br />
<br />
To register both services you need to push the following services to the OSGi-Service-Registry:<br />
* org.eclipse.fx.code.editor.services.ProposalComputerTypeProvider<br />
* org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenterTypeProvider<br />
<br />
For a potential JavaScript-Editor the providers could look like this:<br />
<source lang="java"><br />
@Component<br />
public class JSProposalComputerTypeProvider implements ProposalComputerTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends ProposalComputer> getType(Input<?> input) {<br />
return JSProposalComputer.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
@Component<br />
public class JSCompletionProposalPresenterTypeProvider implements CompletionProposalPresenterTypeProvider {<br />
@Override<br />
public Class<? extends CompletionProposalPresenter> getType(Input<?> s) {<br />
return JSCompletionProposalPresenter.class;<br />
}<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
The cool thing about JSProposalComputer & JSCompletionProposalPresenter is that they are created per editor instance and so you can access all informations available for an editor through Eclipse DI.<br />
<br />
The computer is responsible to talk to your language framework to detect what auto-completions are available (eg methods, ...)<br />
<source lang="java"><br />
public class JSProposalComputer implements ProposalComputer {<br />
private Logger logger;<br />
@Inject<br />
JSProposalComputer(@Log Logger logger /* more stuff */) {<br />
this.logger = logger;<br />
}<br />
<br />
public CompletableFuture<List<CompletionProposal>> compute(ProposalContext context) {<br />
// ... produce a JSCompletionProposal<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java DartProposalComputer.java]<br />
<br />
The presenter on the other hand takes the proposal objects and translates them into text and graphic informations shown by the proposal dialog.<br />
<source lang="java"><br />
public class JSCompletionProposalPresenter implements CompletionProposalPresenter {<br />
private final GraphicsLoader graphicsLoader;<br />
<br />
@Inject<br />
public DartCompletionProposalPresenter(GraphicsLoader graphicsLoader) {<br />
this.graphicsLoader = graphicsLoader;<br />
}<br />
<br />
@Override<br />
public ICompletionProposal createProposal(CompletionProposal proposal) {<br />
JSCompletionProposal p = (JSCompletionProposal) proposal;<br />
String label = p.getProposalText();<br />
Node imageNode = p.getJSType().equals("method") ? new ImageView("method.png") : new ImageView("field.png");<br />
// ...<br />
return new FXCompletionProposal( proposal, label, () -> imageNode, null, null );<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java DartCompletionProposalPresenter.java]<br />
<br />
=== Function Context Information ===<br />
TBD - see <br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartContextInformationPresenter.java<br />
<br />
== Adding support for Error-Markers ==<br />
Errors, Warnings, ... are presented called Annotations and there are 2 ways to present them in the editor:<br />
* as part of the line-ruler on the left<br />
* as part of the text-content eg underlining the text<br />
<br />
=== Providing annotations ===<br />
The first and mandatory step to show annotations in an editor is to provide an instance <code>org.eclipse.jface.text.source.AnnotationModel</code> for your language. The model keeps track of <code>org.eclipse.jface.text.source.Annotation</code>.<br />
<br />
To instruct the framework to build such a model you need to register an <code>org.eclipse.fx.code.editor.services.AnnotationModelTypeProvider</code> following the same steps you used for the auto-complete:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationModelTypeProvider implements AnnotationModelTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends IAnnotationModel> getType(Input<?> input) {<br />
return JSAnnotationModel.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
public class JSAnnotationModel extends AnnotationModel {<br />
private final ThreadSynchronize synchronize;<br />
<br />
@Inject<br />
public JSAnnotationModel(Input<?> input, ThreadSynchronize synchronize) {<br />
// observe the input and when there are compile errors update<br />
// the annotations<br />
}<br />
}<br />
</source><br />
=== Presenting annotations ===<br />
Once there's an annotation model for your language you can present it in the UI by providing an <code>org.eclipse.fx.text.ui.source.AnnotationPresenter</code> which is following the scheme you used for all other services already. <br />
<br />
You register an OSGi-Service of type <code>org.eclipse.fx.code.editor.fx.services.AnnotationPresenterTypeProvider</code> similar to this:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationPresenterTypeProvider implements AnnotationPresenterTypeProvider {<br />
@Override<br />
public Class<? extends AnnotationPresenter> getType(Input<?> s) {<br />
return JSAnnotationPresenter.class;<br />
}<br />
<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
==== Presenting annotations in line ruler ====<br />
The annotation presenter distinguishes between 2 presentation types:<br />
* <code>org.eclipse.fx.text.ui.source.ILineRulerAnnotationPresenter</code><br />
* <code>org.eclipse.fx.text.ui.source.ITextAnnotationPresenter</code><br />
<br />
To show annotations in the line ruler you need to implement the first one.<br />
<br />
==== Presenting annotations as text-overlays ====<br />
To provide text-markers all you need to do is to provide an implementation of <code>ITextAnnotationPresenter</code><br />
<source lang="java"><br />
public class TextMarker implements ITextAnnotationPresenter {<br />
@Override<br />
public boolean isApplicable(Annotation annotation) {<br />
return annotation instanceof DartAnnotation;<br />
}<br />
<br />
@Override<br />
public Node createNode() {<br />
return new Region();<br />
}<br />
<br />
@Override<br />
public void updateNode(Node node, Annotation annotation) {<br />
Region r = (Region) node;<br />
<br />
JSAnnotation a = (JSAnnotation) annotation;<br />
<br />
Color c;<br />
switch (a.getError().getSeverity()) {<br />
case ERROR: c = Color.RED; break;<br />
case WARNING: c = Color.DARKORANGE; break;<br />
default:<br />
case INFO: c = Color.BLANCHEDALMOND; break;<br />
}<br />
r.setBorder(new Border(new BorderStroke(c, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(0, 0, 1.5, 0))));<br />
}<br />
<br />
@Override<br />
public String toString() {<br />
return "JSTextMarkerAP@" + hashCode();<br />
}<br />
}<br />
</source><br />
== Code navigation ==<br />
=== Code link ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProviderTypeProvider.java<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProvider.java<br />
<br />
=== Keyboard Navigation ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/DartBehaviorContributor.java<br />
<br />
== Context information ==<br />
The context information is a popup providing additional information for the current context (caret offset).<br />
For example to display the argument types of a method invocation while typing.<br />
<br />
There are 2 ways to trigger a context information:<br />
* by providing a <code>ContextInformation</code> with the <code>CompletionProposal</code><br />
* by calling <code>EditingContext#showContextInformation(ContextInformation)</code><br />
<br />
=== implicit with CompletionProposal ===<br />
If the <code>CompletionProposal</code> contains a <code>ContextInformation</code> the context information will be automatically triggered after the completion proposal was chosen at the current caret offset. (The offset of the ContextInformation is ignored)<br />
<br />
=== explicit via EditingContext ===<br />
By invoking <code>EditingContext#showContextInformation(ContextInformation)</code> the context information will be immediately shown at the specified offset.<br />
<br />
<br />
<br />
== Hover information ==<br />
<br />
=== HTML Support ===<br />
The API always uses a <code>CharSequence</code> to transport the Hover Content. <br />
There is a <code>HtmlString</code> class which allows to pass html to the hovers.<br />
To use ist simply create an instance of it and pass it to the corresponding hover api<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
<br />
HtmlString data = new HtmlString("<h1>Very nice!</h1><div>indeed</div>");<br />
<br />
// in CompletionProposalPresenter#createProposal(CompletionProposal)<br />
return new ICompletionProposal() {<br />
...<br />
public CharSequence getHoverInfo() { return data; }<br />
...<br />
};<br />
// in DocumentHoverProvider#getHoverInfo(IDocument, int)<br />
return Collections.singleton(new HoverInfo(DefaultHoverInfoType.DOCUMENTATION, region, data, null));<br />
<br />
<br />
<br />
</source><br />
<br />
==== Links ====<br />
The <code>HtmlString</code> also allows the use of hyperlinks. <br />
Here is an example<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
import org.eclipse.fx.text.hover.LinkActionEvent;<br />
<br />
HtmlString data = new HtmlString("<h1>Interactive</h1><div><a href="foo">Foo</a> / <a href="bar">BAR</a></div>");<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_ACTION, e -> {<br />
System.err.println("The link was activated: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_CONTEXT, e -> {<br />
System.err.println("The link was right clicked: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
</source><br />
The link target always contains the content of href, while screenX and screenY contain the screen coordinates of the mouse click.<br />
<br />
== Pair matching ==<br />
https://github.com/BestSolution-at/dartedit/tree/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/pair<br />
<br />
== Predefined annotations like Linenumbers, ... ==<br />
There are currently 2 predefined control annotations found in <code>org.eclipse.fx.text.ui.Feature</code>:<br />
* <code>SHOW_LINE_NUMBERS</code>: showing a ruler on the left with linenumbers (on by default)<br />
* <code>SHOW_HIDDEN_SYMBOLS</code>: displaying informations about whitespace characters like tab, line-breaks (off by default)<br />
<br />
Features are provided by <code>SourceViewerConfiguration#getFeatures() : SetProperty&lt;Feature&gt;</code> and modifying the provided Set instance - adding/removeing features - updates the editor bound to it.<br />
<br />
=== Using preferences ===<br />
When using the framework in an e4 application where <code>DefaultSourceViewerConfiguration</code> one can also use the preference system to set the features and restore them the current feature settings are stored with <br />
* key: <code>Constants.PREFERENCE_KEY_EDITOR_FEATURE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
or expressed through the e(fx)clipse DI-Addons<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Set<Feature> featureSet;<br />
</source><br />
<br />
or if you want to publish <br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Property<Set<Feature>> featureSet;<br />
</source><br />
<br />
As toggling features is a standard task there's a default handler implementation (<code>org.eclipse.fx.code.editor.fx.handlers.ToggleEditorFeature</code>) available for this task which you can register in your e4xmi-File. The command-parameter you need to pass is named <code>feature</code> and you pass in the feature name as a string.<br />
<br />
== Tabs and Spaces ==<br />
<br />
=== Tab Advance ===<br />
By default a tab (\t) character advances in the text 4 characters. If you want to customize this you need make use of the Preference-System with:<br />
* key: <code>Constants.PREFERENCE_TAB_ADVANCE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
So if you want to modify the tab-advance for the editor you can use the e(fx)clipse DI-Extensions like this:<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_TAB_ADVANCE,nodePath=Constants.PREFERENCE_NODE_PATH)<br />
Property<Integer> tabAdvancePreference;<br />
</source><br />
<br />
As updateing the tabAdvance is a standard task there's a handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.SetTabAdvance</code> who accepts a command-parameter named tabAdvance.<br />
<br />
=== Tabs instead of white spaces ===<br />
By default the control inserts a tab (\t) character if you press the tab-key but if you want to insert a certain amount of spaces instead you can configure the editor to act like that by toggleing the preference with:<br />
* key: <code>Constants.PREFERENCE_SPACES_FOR_TAB</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
As toggling the preference is a standard task there's handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.ToggleInsertSpacesForTab</code><br />
<br />
== The InputContext ==<br />
The <code>org.eclipse.fx.code.editor.InputContext</code> is a way to group inputs in a logical context (comparable to a project in your eclipse instance) by default all <code>Input</code> instances are grouped in a default-context but you are free to provide your own logic by registering a service of type <code>org.eclipse.fx.code.editor.services.InputContextProvider</code> in the service registry.<br />
<br />
== Dynamic Lexical Highlightings ==<br />
There are chances that you want to color things like library functions in your UI but those can not be preconfigured because eg they depend on what libraries you have in your application, version of your language you develop against, ...<br />
<br />
The code editing framework has support to dynamically add/remove lexical highlighting rules (even to an already opened editor). The service API responsible to provide rules dynamically is <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculator</code>. To register this service you need to push an instance of <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculatorTypeProvider</code>.<br />
<br />
A good idea to handle this stuff is to use make use of the <code>InputContext</code> in your <code>DynamicScannerRuleCalculator</code> who is grouping all editors.<br />
<br />
= Sample =<br />
The most complete sample showing the complete framework with all its features in action can be found at [https://github.com/BestSolution-at/dartedit github] implementing a Dart-Code-Editor</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/SmartCode&diff=409001Efxclipse/SmartCode2016-08-23T16:03:29Z<p>Ccaks.bestsolution.at: </p>
<hr />
<div>{{Efxclipse}}<br />
<br />
e(fx)clipse provides a SmartCode-Editing Framework who can be embedded in fairly any application (not only OSGi)<br />
<br />
= Integration into OSGi =<br />
<br />
== Setup ==<br />
<br />
Before adding the source you need to configure your application to support the smart code editor. To make that happen you need to add the following bundle to a feature or create a new one:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.e4</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text.fx</code><br />
* <code>org.eclipse.fx.code.editor.e4</code><br />
* <code>org.eclipse.fx.code.editor.fx</code><br />
* <code>org.eclipse.fx.code.editor.fx.e4</code><br />
<br />
== Basic Control with Syntax Highlighting ==<br />
<br />
=== Basics ===<br />
To make it easier to define syntax highlighting for any language the smart-code framework uses unlike the Eclipse IDE a declarative language named ldef.<br />
<br />
The first step when integrating a syntax highlighting editor into your application is to create a file ending with .ldef (eg java.ldef, ...).<br />
<br />
<source lang="java"><br />
package my.plugin<br />
<br />
js {<br />
partitioning {<br />
partition __dftl_partition_content_type<br />
partition __js_single_line_comment<br />
partition __js_multi_line_comment<br />
partition __js_string<br />
partition __js_regex<br />
rule {<br />
single_line __js_single_line_comment "//" => ''<br />
multi_line __js_multi_line_comment "/*" => "*/"<br />
single_line __js_string "'" => "'" escaped by "\\"<br />
single_line __js_string '"' => '"' escaped by "\\"<br />
single_line __js_regex '/' => '/' escaped by "\\"<br />
}<br />
}<br />
lexical_highlighting {<br />
rule __dftl_partition_content_type whitespace javawhitespace {<br />
default js_default<br />
js_operator {<br />
character [ <br />
';', '.', '=', '/', '\\', '+', '-', '*', <br />
'<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~' <br />
]<br />
}<br />
js_bracket {<br />
character [ '(', ')', '{', '}', '[', ']' ]<br />
}<br />
js_keyword {<br />
keywords [<br />
"break", "case", "catch", "continue",<br />
"debugger","default", "delete", "do",<br />
"else", "finally", "for", "function",<br />
"if", "in", "instanceof", "new",<br />
"return", "switch", "this", "throw",<br />
"try", "typeof", "var", "void",<br />
"while", "with" <br />
]<br />
}<br />
js_constant {<br />
keywords [ "true", "false", "undefined" ]<br />
}<br />
js_number {<br />
pattern "\\d" containing "[\\d|\\.]"<br />
}<br />
}<br />
rule __js_single_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_multi_line_comment {<br />
default js_doc_default<br />
}<br />
rule __js_string {<br />
default js_string<br />
}<br />
rule __js_regex {<br />
default js_string<br />
}<br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
}<br />
}<br />
</source><br />
<br />
As the smart code editor framework is built on top of the EclipseText-Framework you notice that the DSL aligns heavily to the concepts you find there:<br />
* Documents are first split in partitions (eg source-code, documentation, strings, ...)<br />
* Single Partitions are then split in tokens like constants, reserved words, ...<br />
* Tokens are then associated with styling information (color, font-weight,...)<br />
<br />
Once you created an ldef-File for your favorite language the Eclipse-Tooling will generate a total of 3 files in the src-gen folder:<br />
* <code>$language$.json</code>: Configuration data loaded at runtime and used to configure Eclipse Text<br />
* <code>$language$.css</code>: Styleing information when using JavaFX as the renderer<br />
* <code>$language$-swt-style.json</code>: Styleing information when using SWT as the renderer (we are not looking into this feature in this document)<br />
<br />
=== Dependencies ===<br />
To integrate a smart editor into your application you need to add dependencies to the following bundles your MANIFEST.MF:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.ui.services</code><br />
<br />
Or if you prefer the following package-imports:<br />
* <code>org.eclipse.fx.code.editor</code><br />
* <code>org.eclipse.fx.code.editor.configuration</code><br />
* <code>org.eclipse.fx.code.editor.configuration.text</code><br />
* <code>org.eclipse.fx.code.editor.services</code><br />
* <code>org.eclipse.fx.ui.services.theme</code><br />
<br />
=== Editor Registration ===<br />
From the DSL we generated various artifacts are generated and we need to register them in the framework:<br />
* <code>$language$.json</code> file is registered through a <code>org.eclipse.fx.code.editor.configuration.text.ConfigurationModelProvider</code> OSGi-Service-Component<br />
* <code>$language$.css</code> file is registered through a <code>org.eclipse.fx.ui.services.theme.Stylesheet</code> OSGi-Service-Component<br />
<br />
Samples for JavaScript could look like this:<br />
<br />
'''ConfigurationModelProvider-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptConfigurationProvider implements ConfigurationModelProvider {<br />
@Override<br />
public boolean applies(Input<?> input) {<br />
return ((URIProvider)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public LanguageDef getModel(Input<?> input) {<br />
try(InputStream in = getClass().getResourceAsStream("js.json");<br />
Reader r = new InputStreamReader(in)) {<br />
return EditorGModel.create().createObject(r);<br />
} catch (IOException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
'''Stylesheet-Component'''<br />
<source lang="java"><br />
@Component<br />
public class JavaScriptStylesheet implements Stylesheet {<br />
@Override<br />
public boolean appliesToTheme(Theme t) {<br />
return true;<br />
}<br />
<br />
@Override<br />
public URL getURL(Theme t) {<br />
try {<br />
return new URL("platform:/plugin/my.plugin/my/plugin/js.css");<br />
} catch (MalformedURLException e) {<br />
throw new RuntimeException(e);<br />
}<br />
}<br />
}<br />
</source><br />
<br />
=== Syntax Highlighting ===<br />
If you remember the ldef file we shown above we defined the token styles like this:<br />
<source lang="java"><br />
token_def {<br />
js_default "-source-editor-code";<br />
js_operator "-source-editor-operator";<br />
js_bracket "-source-editor-bracket";<br />
js_keyword "-source-editor-keyword" bold;<br />
js_doc_default "-source-editor-doc";<br />
js_string "-source-editor-string";<br />
js_constant "-source-editor-keyword" bold;<br />
js_number "-source-editor-number";<br />
}<br />
</source><br />
<br />
The first segment in between <code>""</code> is the foreground color to be used but we are not directly putting the color values (eg #ff0000) there but color references who can be defined in another css. This allows us to easily ship them with themes eg a dark theme most likely would change the colors dramatically, ... .<br />
<br />
All e(fx)clipse applications have at least one theme with a basic css all than you have to do is to change that to define color constants for the above values. <br />
<br />
The perfect place is the .root-selector:<br />
<br />
<source lang="css"><br />
.root {<br />
-source-editor-code: rgb(0, 0, 0);<br />
-source-editor-operator: rgb(0, 0, 0);<br />
-source-editor-bracket: rgb(0, 0, 0);<br />
-source-editor-keyword: rgb(127, 0, 85);<br />
-source-editor-string: rgb(42, 0, 255);<br />
-source-editor-number: #6c83c4;<br />
-source-editor-doc: rgb(63, 127, 95);<br />
}<br />
</source><br />
<br />
The above color specs provide you a eclipse like syntax highlighting.<br />
<br />
=== Editor visual customization ===<br />
<br />
Syntax colors are defined as shown above but to customize other areas of your code area the following CSS will be of great help to you:<br />
* '''.styled-text-area .invisible-char''':<br/>selector for a specialized node which is a subtype of <code>javafx.scene.text.Text</code> and additionally allows to set an -fx-content property for the text displayed<br />
* '''.styled-text-area .invisible-char.space''':<br/>selector to configure what text to display for spaces<br />
* '''.styled-text-area .invisible-char.tab''':<br/>selector to configure what text to display for tabs<br />
* '''.styled-text-area .invisible-char.enter''':<br/>selector to configure what text<br />
* '''.source-viewer.styled-text-area .selection-marker''':<br/>selector to configure how a selected area is display most likely you want to customize the -fx-background-color - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .list-view''':<br/>the content area of the text editor which is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .current-line''':<br/> selector to configure how the current cursor line is displayed - the javafx-Node is of type <code>javafx.scene.layout.Region</code><br />
* '''.styled-text-area .line-ruler-text''':<br/> selector to configure how the text in the line ruler is displayed<br />
* '''.styled-text-area .text-caret''':<br/> selector to configure how the text-caret is rendered - the javafx-Node is of type <code>javafx.scene.shape.Shape</code><br />
* '''.styled-text-hover .errors''':<br/> selector to configure how the error hover popup is displayed<br />
* '''.styled-text-hover .warnings''':<br/> selector to configure how the warnings hover popup is displayed<br />
* '''.styled-text-hover .infos''':<br/> selector to configure how the infos hover popup is displayed<br />
* '''.styled-text-hover .docs''':<br/> selector to configure how the doc hover popup is displayed<br />
* '''.styled-text-hover .others''':<br/> selector to configure how the others hover popup is displayed<br />
* '''.styled-text-hover .context-info''':<br/> selector to configure how the warnings hover popup is displayed<br />
<br />
=== Open an editor ===<br />
<br />
==== Using the editor opener service ====<br />
The smart code framework by default publishes an <code>org.eclipse.fx.code.editor.services.EditorOpener</code>-Service who can be retrieved via injection and used to open an editor based on an URI like this<br />
<br />
<source lang="java"><br />
class MyComponent {<br />
@Inject<br />
EditorOpener opener;<br />
<br />
private void openFile(File f) {<br />
opener.openEditor( f.toURI().toURL().toExternalForm() );<br />
} <br />
}<br />
</source><br />
<br />
The default implementation of the opener function will search the window/perspective for a <code>MElementContainer</code> tagged with <code>editorContainer</code>, so if you want to use that service you need to update your application model and tag eg one of your <code>MPartStack</code>s with it.<br />
<br />
==== Doing it yourself ====<br />
If you don't want to use the EditorOpener-Service but do things yourself all you need to do is to create an MPart instance like this:<br />
<br />
<source lang="java"><br />
EModelService modelService = // ...;<br />
MPart part = modelService.createModelElement(MPart.class);<br />
part.setCloseable(true);<br />
part.setLabel("MySample.js");<br />
part.setContributionURI("bundleclass://org.eclipse.fx.code.editor.fx/org.eclipse.fx.code.editor.fx.TextEditor");<br />
part.getPersistedState().put(org.eclipse.fx.code.editor.Constants.DOCUMENT_URL, uri);<br />
part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);<br />
// ...<br />
</source><br />
<br />
== Dirty State Tracking & Save ==<br />
As we don't want to force you into predefined start-state and save strategy we don't push support to your application by default but require you to handle that yourself. What we provide are to base implementation:<br />
* An addon who does the dirty state tracking <code>org.eclipse.fx.code.editor.e4.addons.DirtyStateTrackingAddon</code><br />
* A handler who saves the file a dirty file <code>org.eclipse.fx.code.editor.e4.handlers.SaveFile</code><br />
<br />
== Adding support for Autocomplete Features ==<br />
First of providing auto-completion is an optional feature you can provide for your language. Adding support is done with 2 distinct services:<br />
* list of proposals: <code>org.eclipse.fx.code.editor.services.ProposalComputer</code><br />
* (optional) presentation of proposals: <code>org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenter</code><br />
<br />
To register both services you need to push the following services to the OSGi-Service-Registry:<br />
* org.eclipse.fx.code.editor.services.ProposalComputerTypeProvider<br />
* org.eclipse.fx.code.editor.fx.services.CompletionProposalPresenterTypeProvider<br />
<br />
For a potential JavaScript-Editor the providers could look like this:<br />
<source lang="java"><br />
@Component<br />
public class JSProposalComputerTypeProvider implements ProposalComputerTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends ProposalComputer> getType(Input<?> input) {<br />
return JSProposalComputer.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
@Component<br />
public class JSCompletionProposalPresenterTypeProvider implements CompletionProposalPresenterTypeProvider {<br />
@Override<br />
public Class<? extends CompletionProposalPresenter> getType(Input<?> s) {<br />
return JSCompletionProposalPresenter.class;<br />
}<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
The cool thing about JSProposalComputer & JSCompletionProposalPresenter is that they are created per editor instance and so you can access all informations available for an editor through Eclipse DI.<br />
<br />
The computer is responsible to talk to your language framework to detect what auto-completions are available (eg methods, ...)<br />
<source lang="java"><br />
public class JSProposalComputer implements ProposalComputer {<br />
private Logger logger;<br />
@Inject<br />
JSProposalComputer(@Log Logger logger /* more stuff */) {<br />
this.logger = logger;<br />
}<br />
<br />
public CompletableFuture<List<CompletionProposal>> compute(ProposalContext context) {<br />
// ... produce a JSCompletionProposal<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java DartProposalComputer.java]<br />
<br />
The presenter on the other hand takes the proposal objects and translates them into text and graphic informations shown by the proposal dialog.<br />
<source lang="java"><br />
public class JSCompletionProposalPresenter implements CompletionProposalPresenter {<br />
private final GraphicsLoader graphicsLoader;<br />
<br />
@Inject<br />
public DartCompletionProposalPresenter(GraphicsLoader graphicsLoader) {<br />
this.graphicsLoader = graphicsLoader;<br />
}<br />
<br />
@Override<br />
public ICompletionProposal createProposal(CompletionProposal proposal) {<br />
JSCompletionProposal p = (JSCompletionProposal) proposal;<br />
String label = p.getProposalText();<br />
Node imageNode = p.getJSType().equals("method") ? new ImageView("method.png") : new ImageView("field.png");<br />
// ...<br />
return new FXCompletionProposal( proposal, label, () -> imageNode, null, null );<br />
}<br />
}<br />
</source><br />
You can take a look at how the dart-language tooling does it at [https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java DartCompletionProposalPresenter.java]<br />
<br />
=== Function Context Information ===<br />
TBD - see <br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/complete/DartProposalComputer.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartCompletionProposalPresenter.java<br />
* https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor/src/at/bestsolution/dart/editor/complete/DartContextInformationPresenter.java<br />
<br />
== Adding support for Error-Markers ==<br />
Errors, Warnings, ... are presented called Annotations and there are 2 ways to present them in the editor:<br />
* as part of the line-ruler on the left<br />
* as part of the text-content eg underlining the text<br />
<br />
=== Providing annotations ===<br />
The first and mandatory step to show annotations in an editor is to provide an instance <code>org.eclipse.jface.text.source.AnnotationModel</code> for your language. The model keeps track of <code>org.eclipse.jface.text.source.Annotation</code>.<br />
<br />
To instruct the framework to build such a model you need to register an <code>org.eclipse.fx.code.editor.services.AnnotationModelTypeProvider</code> following the same steps you used for the auto-complete:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationModelTypeProvider implements AnnotationModelTypeProvider {<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
<br />
@Override<br />
public Class<? extends IAnnotationModel> getType(Input<?> input) {<br />
return JSAnnotationModel.class;<br />
}<br />
}<br />
</source><br />
<source lang="java"><br />
public class JSAnnotationModel extends AnnotationModel {<br />
private final ThreadSynchronize synchronize;<br />
<br />
@Inject<br />
public JSAnnotationModel(Input<?> input, ThreadSynchronize synchronize) {<br />
// observe the input and when there are compile errors update<br />
// the annotations<br />
}<br />
}<br />
</source><br />
=== Presenting annotations ===<br />
Once there's an annotation model for your language you can present it in the UI by providing an <code>org.eclipse.fx.text.ui.source.AnnotationPresenter</code> which is following the scheme you used for all other services already. <br />
<br />
You register an OSGi-Service of type <code>org.eclipse.fx.code.editor.fx.services.AnnotationPresenterTypeProvider</code> similar to this:<br />
<source lang="java"><br />
@Component<br />
public class JSAnnotationPresenterTypeProvider implements AnnotationPresenterTypeProvider {<br />
@Override<br />
public Class<? extends AnnotationPresenter> getType(Input<?> s) {<br />
return JSAnnotationPresenter.class;<br />
}<br />
<br />
@Override<br />
public boolean test(Input<?> input) {<br />
return input instanceof SourceFileInput && ((SourceFileInput)input).getURI().endsWith(".js");<br />
}<br />
}<br />
</source><br />
<br />
==== Presenting annotations in line ruler ====<br />
The annotation presenter distinguishes between 2 presentation types:<br />
* <code>org.eclipse.fx.text.ui.source.ILineRulerAnnotationPresenter</code><br />
* <code>org.eclipse.fx.text.ui.source.ITextAnnotationPresenter</code><br />
<br />
To show annotations in the line ruler you need to implement the first one.<br />
<br />
==== Presenting annotations as text-overlays ====<br />
To provide text-markers all you need to do is to provide an implementation of <code>ITextAnnotationPresenter</code><br />
<source lang="java"><br />
public class TextMarker implements ITextAnnotationPresenter {<br />
@Override<br />
public boolean isApplicable(Annotation annotation) {<br />
return annotation instanceof DartAnnotation;<br />
}<br />
<br />
@Override<br />
public Node createNode() {<br />
return new Region();<br />
}<br />
<br />
@Override<br />
public void updateNode(Node node, Annotation annotation) {<br />
Region r = (Region) node;<br />
<br />
JSAnnotation a = (JSAnnotation) annotation;<br />
<br />
Color c;<br />
switch (a.getError().getSeverity()) {<br />
case ERROR: c = Color.RED; break;<br />
case WARNING: c = Color.DARKORANGE; break;<br />
default:<br />
case INFO: c = Color.BLANCHEDALMOND; break;<br />
}<br />
r.setBorder(new Border(new BorderStroke(c, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, new BorderWidths(0, 0, 1.5, 0))));<br />
}<br />
<br />
@Override<br />
public String toString() {<br />
return "JSTextMarkerAP@" + hashCode();<br />
}<br />
}<br />
</source><br />
== Code navigation ==<br />
=== Code link ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProviderTypeProvider.java<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/navigation/DartNavigationProvider.java<br />
<br />
=== Keyboard Navigation ===<br />
https://github.com/BestSolution-at/dartedit/blob/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/DartBehaviorContributor.java<br />
<br />
== Hover information ==<br />
<br />
=== HTML Support ===<br />
The API always uses a <code>CharSequence</code> to transport the Hover Content. <br />
There is a <code>HtmlString</code> class which allows to pass html to the hovers.<br />
To use ist simply create an instance of it and pass it to the corresponding hover api<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
<br />
HtmlString data = new HtmlString("<h1>Very nice!</h1><div>indeed</div>");<br />
<br />
// in CompletionProposalPresenter#createProposal(CompletionProposal)<br />
return new ICompletionProposal() {<br />
...<br />
public CharSequence getHoverInfo() { return data; }<br />
...<br />
};<br />
// in DocumentHoverProvider#getHoverInfo(IDocument, int)<br />
return Collections.singleton(new HoverInfo(DefaultHoverInfoType.DOCUMENTATION, region, data, null));<br />
<br />
<br />
<br />
</source><br />
<br />
==== Links ====<br />
The <code>HtmlString</code> also allows the use of hyperlinks. <br />
Here is an example<br />
<source lang="java"><br />
import org.eclipse.fx.text.hover.HtmlString;<br />
import org.eclipse.fx.text.hover.LinkActionEvent;<br />
<br />
HtmlString data = new HtmlString("<h1>Interactive</h1><div><a href="foo">Foo</a> / <a href="bar">BAR</a></div>");<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_ACTION, e -> {<br />
System.err.println("The link was activated: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
<br />
data.addEventHandler(LinkActionEvent.LINK_CONTEXT, e -> {<br />
System.err.println("The link was right clicked: " + e.getLinkTarget() + " @ " + e.getScreenX() + " / " + e.getScreenY());<br />
});<br />
</source><br />
The link target always contains the content of href, while screenX and screenY contain the screen coordinates of the mouse click.<br />
<br />
== Pair matching ==<br />
https://github.com/BestSolution-at/dartedit/tree/master/bundles/at.bestsolution.dart.editor.services/src/at/bestsolution/dart/editor/services/pair<br />
<br />
== Predefined annotations like Linenumbers, ... ==<br />
There are currently 2 predefined control annotations found in <code>org.eclipse.fx.text.ui.Feature</code>:<br />
* <code>SHOW_LINE_NUMBERS</code>: showing a ruler on the left with linenumbers (on by default)<br />
* <code>SHOW_HIDDEN_SYMBOLS</code>: displaying informations about whitespace characters like tab, line-breaks (off by default)<br />
<br />
Features are provided by <code>SourceViewerConfiguration#getFeatures() : SetProperty&lt;Feature&gt;</code> and modifying the provided Set instance - adding/removeing features - updates the editor bound to it.<br />
<br />
=== Using preferences ===<br />
When using the framework in an e4 application where <code>DefaultSourceViewerConfiguration</code> one can also use the preference system to set the features and restore them the current feature settings are stored with <br />
* key: <code>Constants.PREFERENCE_KEY_EDITOR_FEATURE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
or expressed through the e(fx)clipse DI-Addons<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Set<Feature> featureSet;<br />
</source><br />
<br />
or if you want to publish <br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) <br />
Property<Set<Feature>> featureSet;<br />
</source><br />
<br />
As toggling features is a standard task there's a default handler implementation (<code>org.eclipse.fx.code.editor.fx.handlers.ToggleEditorFeature</code>) available for this task which you can register in your e4xmi-File. The command-parameter you need to pass is named <code>feature</code> and you pass in the feature name as a string.<br />
<br />
== Tabs and Spaces ==<br />
<br />
=== Tab Advance ===<br />
By default a tab (\t) character advances in the text 4 characters. If you want to customize this you need make use of the Preference-System with:<br />
* key: <code>Constants.PREFERENCE_TAB_ADVANCE</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
So if you want to modify the tab-advance for the editor you can use the e(fx)clipse DI-Extensions like this:<br />
<source lang="java"><br />
@Inject<br />
@Preference(key=Constants.PREFERENCE_TAB_ADVANCE,nodePath=Constants.PREFERENCE_NODE_PATH)<br />
Property<Integer> tabAdvancePreference;<br />
</source><br />
<br />
As updateing the tabAdvance is a standard task there's a handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.SetTabAdvance</code> who accepts a command-parameter named tabAdvance.<br />
<br />
=== Tabs instead of white spaces ===<br />
By default the control inserts a tab (\t) character if you press the tab-key but if you want to insert a certain amount of spaces instead you can configure the editor to act like that by toggleing the preference with:<br />
* key: <code>Constants.PREFERENCE_SPACES_FOR_TAB</code><br />
* nodePath: <code>Constants.PREFERENCE_NODE_PATH</code><br />
<br />
As toggling the preference is a standard task there's handler implementation available named <code>org.eclipse.fx.code.editor.fx.handlers.ToggleInsertSpacesForTab</code><br />
<br />
== The InputContext ==<br />
The <code>org.eclipse.fx.code.editor.InputContext</code> is a way to group inputs in a logical context (comparable to a project in your eclipse instance) by default all <code>Input</code> instances are grouped in a default-context but you are free to provide your own logic by registering a service of type <code>org.eclipse.fx.code.editor.services.InputContextProvider</code> in the service registry.<br />
<br />
== Dynamic Lexical Highlightings ==<br />
There are chances that you want to color things like library functions in your UI but those can not be preconfigured because eg they depend on what libraries you have in your application, version of your language you develop against, ...<br />
<br />
The code editing framework has support to dynamically add/remove lexical highlighting rules (even to an already opened editor). The service API responsible to provide rules dynamically is <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculator</code>. To register this service you need to push an instance of <code>org.eclipse.fx.code.editor.configuration.text.DynamicScannerRuleCalculatorTypeProvider</code>.<br />
<br />
A good idea to handle this stuff is to use make use of the <code>InputContext</code> in your <code>DynamicScannerRuleCalculator</code> who is grouping all editors.<br />
<br />
= Sample =<br />
The most complete sample showing the complete framework with all its features in action can be found at [https://github.com/BestSolution-at/dartedit github] implementing a Dart-Code-Editor</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/BndtoolsSupport&diff=379684Efxclipse/BndtoolsSupport2015-03-10T09:51:31Z<p>Ccaks.bestsolution.at: updated repository information</p>
<hr />
<div>= Bndtools Support =<br />
<br />
This page is used to collect information about how to support bndtools.<br />
<br />
Contributions are welcome ;-)<br />
<br />
This is our root bug for the support:<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418]<br />
<br />
Google groups discussion: [https://groups.google.com/forum/#!topic/bndtools-users/r0xifzZZhoo bndtools-users]<br />
== Build system ==<br />
=== runtime repository ===<br />
bndtools uses repositories to access bundles (similar to pde's target platform).<br />
It seems that bnd has no p2 repository plugin, so we need to provide a bnd compatible repository to access the efxclipse runtime<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=450811 Bug 450811]<br />
<br />
We use now repoindex to create our repository meta info.<br />
To include it in our build process we created a little maven plugin which wraps [http://search.maven.org/#artifactdetails|biz.aQute.bnd|org.osgi.impl.bundle.repoindex.cli|2.1.5|jar biz.aQute.bnd:org.osgi.impl.bundle.repoindex.cli:2.1.5]<br />
<br />
[http://search.maven.org/#artifactdetails|at.bestsolution|bindex-maven-plugin|1.0.0|maven-plugin at.bestsolution:bindex-maven-plugin:1.0.0]<br />
[https://github.com/BestSolution-at/bindex-maven-plugin source]<br />
<br />
The index can be found here: [http://download.eclipse.org/efxclipse/runtime-nightly/site/repository.xml.gz runtime-nightly/site/repository.xml.gz]<br />
<br />
== tooling ==<br />
=== wizards ===<br />
we need some new project wizards to create<br />
* e4fx bnd project<br />
* fx bnd project<br />
* bnd cnf project<br />
<br />
=== template project ===<br />
Im working on a template project for the wizards. You can find it on github: [https://github.com/redrezo/e4fx-bnd e4fx-bnd].<br />
It is already possible to launch the demo application.<br />
<br />
=== automatic classpath management ===<br />
in pde we add some dependencies automatically to the classpath.<br />
<br />
How do we solve this for bndtools?<br />
<br />
<br />
== launching ==<br />
bndtools comes with its own launcher. It uses .bndrun files to describe the osgi setup to be launched.<br />
we need to generate a default .bndrun file, so that users can instantly start their applications.<br />
<br />
=== Issues ===<br />
==== resolver issue with org.eclipse.osgi from our own repo ====<br />
Our runtime repository provides everything needed to launch an e4fx application. However if bndtools tries to resolve with our bundled equinox implementation it always fails.<br />
Unable to resolve <<INITIAL>> version=null:<br />
missing requirement Require[osgi.identity]{}{filter=(osgi.identity=dummy)} [caused by:<br />
Unable to resolve dummy version=0.0.0:<br />
missing requirement Require[osgi.wiring.package]{}{filter=(osgi.wiring.package=javafx.application)} [caused by:<br />
Unable to resolve org.eclipse.fx.javafx version=2.2.0.201411100602:<br />
missing requirement Require[osgi.ee]{}{filter=(|(osgi.ee=JavaSE-1.7))}]]<br />
<br />
If it uses org.eclipse.osgi from bundlehub it succeds. Both are the same version.. I suspect the index to be at fault...<br />
<br />
== developing e4fx applications with bndtools ==<br />
<br />
=== Issues ===<br />
==== bnd development cycle and e4 ====<br />
bndtools rebuilds on every change the resulting bundle and updates it in the running osgi container.<br />
It seems that the e4 platform cannot handle dynamic changes correctly and the application will somehow fail afterwards.</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/BndtoolsSupport&diff=373539Efxclipse/BndtoolsSupport2014-11-11T08:16:43Z<p>Ccaks.bestsolution.at: /* Bndtools Support */ added link to google-groups discussion</p>
<hr />
<div>= Bndtools Support =<br />
<br />
This page is used to collect information about how to support bndtools.<br />
<br />
Contributions are welcome ;-)<br />
<br />
This is our root bug for the support:<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418]<br />
<br />
Google groups discussion: [https://groups.google.com/forum/#!topic/bndtools-users/r0xifzZZhoo bndtools-users]<br />
== Build system ==<br />
=== runtime repository ===<br />
bndtools uses repositories to access bundles (similar to pde's target platform).<br />
It seems that bnd has no p2 repository plugin, so we need to provide a bnd compatible repository to access the efxclipse runtime<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=450811 Bug 450811]<br />
<br />
for now we use the maven-bundle-plugin to create a repository.xml index file within our p2 page.<br />
<br />
The documentation of the plugin claims that it is an OBR index.<br />
<br />
Our nightly update site already contains the index: [http://download.eclipse.org/efxclipse/runtime-nightly/site/repository.xml nightly repository.xml]<br />
<br />
Should we use an R5 index instead? I have not yet found a maven plugin to generate R5.<br />
<br />
<br />
== tooling ==<br />
=== wizards ===<br />
we need some new project wizards to create<br />
* e4fx bnd project<br />
* fx bnd project<br />
* bnd cnf project<br />
<br />
=== template project ===<br />
Im working on a template project for the wizards. You can find it on github: [https://github.com/redrezo/e4fx-bnd e4fx-bnd].<br />
It is already possible to launch the demo application.<br />
<br />
=== automatic classpath management ===<br />
in pde we add some dependencies automatically to the classpath.<br />
<br />
How do we solve this for bndtools?<br />
<br />
<br />
== launching ==<br />
bndtools comes with its own launcher. It uses .bndrun files to describe the osgi setup to be launched.<br />
we need to generate a default .bndrun file, so that users can instantly start their applications.<br />
<br />
=== Issues ===<br />
==== resolver issue with org.eclipse.osgi from our own repo ====<br />
Our runtime repository provides everything needed to launch an e4fx application. However if bndtools tries to resolve with our bundled equinox implementation it always fails.<br />
Unable to resolve <<INITIAL>> version=null:<br />
missing requirement Require[osgi.identity]{}{filter=(osgi.identity=dummy)} [caused by:<br />
Unable to resolve dummy version=0.0.0:<br />
missing requirement Require[osgi.wiring.package]{}{filter=(osgi.wiring.package=javafx.application)} [caused by:<br />
Unable to resolve org.eclipse.fx.javafx version=2.2.0.201411100602:<br />
missing requirement Require[osgi.ee]{}{filter=(|(osgi.ee=JavaSE-1.7))}]]<br />
<br />
If it uses org.eclipse.osgi from bundlehub it succeds. Both are the same version.. I suspect the index to be at fault...<br />
<br />
== developing e4fx applications with bndtools ==<br />
<br />
=== Issues ===<br />
==== bnd development cycle and e4 ====<br />
bndtools rebuilds on every change the resulting bundle and updates it in the running osgi container.<br />
It seems that the e4 platform cannot handle dynamic changes correctly and the application will somehow fail afterwards.</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/BndtoolsSupport&diff=373522Efxclipse/BndtoolsSupport2014-11-10T17:02:53Z<p>Ccaks.bestsolution.at: </p>
<hr />
<div>= Bndtools Support =<br />
<br />
This page is used to collect information about how to support bndtools.<br />
<br />
Contributions are welcome ;-)<br />
<br />
This is our root bug for the support:<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418]<br />
<br />
== Build system ==<br />
=== runtime repository ===<br />
bndtools uses repositories to access bundles (similar to pde's target platform).<br />
It seems that bnd has no p2 repository plugin, so we need to provide a bnd compatible repository to access the efxclipse runtime<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=450811 Bug 450811]<br />
<br />
for now we use the maven-bundle-plugin to create a repository.xml index file within our p2 page.<br />
<br />
The documentation of the plugin claims that it is an OBR index.<br />
<br />
Our nightly update site already contains the index: [http://download.eclipse.org/efxclipse/runtime-nightly/site/repository.xml nightly repository.xml]<br />
<br />
Should we use an R5 index instead? I have not yet found a maven plugin to generate R5.<br />
<br />
<br />
== tooling ==<br />
=== wizards ===<br />
we need some new project wizards to create<br />
* e4fx bnd project<br />
* fx bnd project<br />
* bnd cnf project<br />
<br />
=== template project ===<br />
Im working on a template project for the wizards. You can find it on github: [https://github.com/redrezo/e4fx-bnd e4fx-bnd].<br />
It is already possible to launch the demo application.<br />
<br />
=== automatic classpath management ===<br />
in pde we add some dependencies automatically to the classpath.<br />
<br />
How do we solve this for bndtools?<br />
<br />
<br />
== launching ==<br />
bndtools comes with its own launcher. It uses .bndrun files to describe the osgi setup to be launched.<br />
we need to generate a default .bndrun file, so that users can instantly start their applications.<br />
<br />
=== Issues ===<br />
==== resolver issue with org.eclipse.osgi from our own repo ====<br />
Our runtime repository provides everything needed to launch an e4fx application. However if bndtools tries to resolve with our bundled equinox implementation it always fails.<br />
Unable to resolve <<INITIAL>> version=null:<br />
missing requirement Require[osgi.identity]{}{filter=(osgi.identity=dummy)} [caused by:<br />
Unable to resolve dummy version=0.0.0:<br />
missing requirement Require[osgi.wiring.package]{}{filter=(osgi.wiring.package=javafx.application)} [caused by:<br />
Unable to resolve org.eclipse.fx.javafx version=2.2.0.201411100602:<br />
missing requirement Require[osgi.ee]{}{filter=(|(osgi.ee=JavaSE-1.7))}]]<br />
<br />
If it uses org.eclipse.osgi from bundlehub it succeds. Both are the same version.. I suspect the index to be at fault...<br />
<br />
== developing e4fx applications with bndtools ==<br />
<br />
=== Issues ===<br />
==== bnd development cycle and e4 ====<br />
bndtools rebuilds on every change the resulting bundle and updates it in the running osgi container.<br />
It seems that the e4 platform cannot handle dynamic changes correctly and the application will somehow fail afterwards.</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/BndtoolsSupport&diff=373518Efxclipse/BndtoolsSupport2014-11-10T16:00:35Z<p>Ccaks.bestsolution.at: </p>
<hr />
<div>= Bndtools Support =<br />
<br />
This page is used to collect information about how to support bndtools.<br />
<br />
Contributions are welcome ;-)<br />
<br />
This is our root bug for the support:<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418]<br />
<br />
== Build system ==<br />
=== runtime repository ===<br />
bndtools uses repositories to access bundles (similar to pde's target platform).<br />
It seems that bnd has no p2 repository plugin, so we need to provide a bnd compatible repository to access the efxclipse runtime<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=450811 Bug 450811]<br />
<br />
for now we use the maven-bundle-plugin to create a repository.xml index file within our p2 page.<br />
<br />
The documentation of the plugin claims that it is an OBR index.<br />
<br />
Our nightly update site already contains the index: [http://download.eclipse.org/efxclipse/runtime-nightly/site/repository.xml nightly repository.xml]<br />
<br />
Should we use an R5 index instead? I have not yet found a maven plugin to generate R5.<br />
<br />
<br />
== tooling ==<br />
=== wizards ===<br />
we need some new project wizards to create<br />
* e4fx bnd project<br />
* fx bnd project<br />
* bnd cnf project<br />
<br />
=== automatic classpath management ===<br />
in pde we add some dependencies automatically to the classpath.<br />
<br />
How do we solve this for bndtools?<br />
<br />
<br />
== launching ==<br />
bndtools comes with its own launcher. It uses .bndrun files to describe the osgi setup to be launched.<br />
we need to generate a default .bndrun file, so that users can instantly start their applications.<br />
<br />
=== Issues ===<br />
==== resolver issue with org.eclipse.osgi from our own repo ====<br />
Our runtime repository provides everything needed to launch an e4fx application. However if bndtools tries to resolve with our bundled equinox implementation it always fails.<br />
Unable to resolve <<INITIAL>> version=null:<br />
missing requirement Require[osgi.identity]{}{filter=(osgi.identity=dummy)} [caused by:<br />
Unable to resolve dummy version=0.0.0:<br />
missing requirement Require[osgi.wiring.package]{}{filter=(osgi.wiring.package=javafx.application)} [caused by:<br />
Unable to resolve org.eclipse.fx.javafx version=2.2.0.201411100602:<br />
missing requirement Require[osgi.ee]{}{filter=(|(osgi.ee=JavaSE-1.7))}]]<br />
<br />
If it uses org.eclipse.osgi from bundlehub it succeds. Both are the same version.. I suspect the index to be at fault...<br />
<br />
== developing e4fx applications with bndtools ==<br />
<br />
=== Issues ===<br />
==== bnd development cycle and e4 ====<br />
bndtools rebuilds on every change the resulting bundle and updates it in the running osgi container.<br />
It seems that the e4 platform cannot handle dynamic changes correctly and the application will somehow fail afterwards.</div>Ccaks.bestsolution.athttps://wiki.eclipse.org/index.php?title=Efxclipse/BndtoolsSupport&diff=373505Efxclipse/BndtoolsSupport2014-11-10T14:00:45Z<p>Ccaks.bestsolution.at: Created page with "= Bndtools Support = This page is used to collect information about how to support bndtools [https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418] == Build syste..."</p>
<hr />
<div>= Bndtools Support =<br />
<br />
This page is used to collect information about how to support bndtools<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=414418 Bug 414418]<br />
<br />
== Build system ==<br />
=== runtime repository ===<br />
bndtools uses repositories to access bundles (similar to pde's target platform).<br />
It seems that bnd has no p2 repository plugin, so we need to provide a bnd compatible repository to access the efxclipse runtime<br />
<br />
[https://bugs.eclipse.org/bugs/show_bug.cgi?id=450811 Bug 450811]<br />
<br />
for now we use the maven-bundle-plugin to create a repository.xml index file within our p2 page.<br />
<br />
The documentation of the plugin claims that it is an OBR index.<br />
<br />
Should we use an R5 index instead? I have not yet found a maven plugin to generate R5.<br />
<br />
<br />
== tooling ==<br />
=== wizards ===<br />
we need some new project wizards to create<br />
* e4fx bnd project<br />
* fx bnd project<br />
* bnd cnf project<br />
<br />
=== automatic classpath management ===<br />
in pde we add some dependencies automatically to the classpath.<br />
<br />
How do we solve this for bndtools?<br />
<br />
<br />
== launching ==<br />
bndtools comes with its own launcher. It uses .bndrun files to describe the osgi setup to be launched.<br />
we need at least to generate a default .bndrun file.<br />
<br />
Our runtime repository provides everything needed to launch an e4fx application. However if bndtools tries to resolve with our bundled equinox implementation it always fails.<br />
Unable to resolve <<INITIAL>> version=null:<br />
missing requirement Require[osgi.identity]{}{filter=(osgi.identity=dummy)} [caused by:<br />
Unable to resolve dummy version=0.0.0:<br />
missing requirement Require[osgi.wiring.package]{}{filter=(osgi.wiring.package=javafx.application)} [caused by:<br />
Unable to resolve org.eclipse.fx.javafx version=2.2.0.201411100602:<br />
missing requirement Require[osgi.ee]{}{filter=(|(osgi.ee=JavaSE-1.7))}]]<br />
<br />
If it uses the org.eclipse.osgi from bundlehub it succeds. Both are the same version.. I suspect the index to be at fault...</div>Ccaks.bestsolution.at