Skip to main content
Jump to: navigation, search

Difference between revisions of "Efxclipse/SmartCode"

(Tabs and Spaces)
(Tab Advance)
Line 288: Line 288:
  
 
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.
 
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.
 +
 +
=== Tabs instead of white spaces ===
  
 
= Sample =
 
= Sample =
 
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
 
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

Revision as of 19:06, 16 March 2016


e(fx)clipse provides a SmartCode-Editing Framework who can be embedded in fairly any application (not only OSGi)

Integration into OSGi

Setup

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:

  • org.eclipse.fx.code.editor
  • org.eclipse.fx.code.editor.configuration
  • org.eclipse.fx.code.editor.configuration.text
  • org.eclipse.fx.code.editor.configuration.text.e4
  • org.eclipse.fx.code.editor.configuration.text.fx
  • org.eclipse.fx.code.editor.e4
  • org.eclipse.fx.code.editor.fx
  • org.eclipse.fx.code.editor.fx.e4

Basic Control with Syntax Highlighting

Basics

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.

The first step when integrating a syntax highlighting editor into your application is to create a file ending with .ldef (eg java.ldef, ...).

package my.plugin
 
js {
  partitioning {
    partition __dftl_partition_content_type
    partition __js_single_line_comment
    partition __js_multi_line_comment
    partition __js_string
    partition __js_regex
    rule {
      single_line __js_single_line_comment  "//"  => ''
      multi_line __js_multi_line_comment    "/*"  => "*/"
      single_line __js_string               "'"   => "'" escaped by "\\"
      single_line __js_string               '"'   => '"' escaped by "\\"
      single_line __js_regex                '/'   => '/' escaped by "\\"
    }
  }
  lexical_highlighting {
    rule __dftl_partition_content_type whitespace javawhitespace {
      default js_default
      js_operator {
        character [ 
          ';', '.', '=', '/', '\\', '+', '-', '*', 
          '<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~' 
        ]
      }
      js_bracket {
        character [ '(', ')', '{', '}', '[', ']' ]
      }
      js_keyword {
        keywords [
          "break", "case", "catch", "continue",
          "debugger","default",	"delete", "do",
          "else", "finally", "for", "function",
          "if", "in", "instanceof", "new",
          "return", "switch", "this", "throw",
          "try", "typeof", "var", "void",
          "while", "with" 
        ]
      }
      js_constant {
        keywords [ "true", "false", "undefined" ]
      }
      js_number {
        pattern "\\d" containing "[\\d|\\.]"
      }
    }
    rule __js_single_line_comment {
      default js_doc_default
    }
    rule __js_multi_line_comment {
      default js_doc_default
    }
    rule __js_string {
      default js_string
    }
    rule __js_regex {
      default js_string
    }
    token_def {
      js_default "-source-editor-code";
      js_operator "-source-editor-operator";
      js_bracket "-source-editor-bracket";
      js_keyword "-source-editor-keyword" bold;
      js_doc_default "-source-editor-doc";
      js_string "-source-editor-string";
      js_constant "-source-editor-keyword" bold;
      js_number "-source-editor-number";
    }
  }
}

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:

  • Documents are first split in partitions (eg source-code, documentation, strings, ...)
  • Single Partitions are then split in tokens like constants, reserved words, ...
  • Tokens are then associated with styling information (color, font-weight,...)

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:

  • $language$.json: Configuration data loaded at runtime and used to configure Eclipse Text
  • $language$.css: Styleing information when using JavaFX as the renderer
  • $language$-swt-style.json: Styleing information when using SWT as the renderer (we are not looking into this feature in this document)

Dependencies

To integrate a smart editor into your application you need to add dependencies to the following bundles your MANIFEST.MF:

  • org.eclipse.fx.code.editor
  • org.eclipse.fx.code.editor.configuration
  • org.eclipse.fx.code.editor.configuration.text
  • org.eclipse.fx.ui.services

Or if you prefer the following package-imports:

  • org.eclipse.fx.code.editor
  • org.eclipse.fx.code.editor.configuration
  • org.eclipse.fx.code.editor.configuration.text
  • org.eclipse.fx.code.editor.services
  • org.eclipse.fx.ui.services.theme

Editor Registration

From the DSL we generated various artifacts are generated and we need to register them in the framework:

  • $language$.json file is registered through a org.eclipse.fx.code.editor.configuration.text.ConfigurationModelProvider OSGi-Service-Component
  • $language$.css file is registered through a org.eclipse.fx.ui.services.theme.Stylesheet OSGi-Service-Component

Samples for JavaScript could look like this:

ConfigurationModelProvider-Component

@Component
public class JavaScriptConfigurationProvider implements ConfigurationModelProvider {
  @Override
  public boolean applies(Input<?> input) {
    return ((URIProvider)input).getURI().endsWith(".js");
  }
 
  @Override
  public LanguageDef getModel(Input<?> input) {
    try(InputStream in = getClass().getResourceAsStream("js.json");
        Reader r = new InputStreamReader(in)) {
      return EditorGModel.create().createObject(r);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}

Stylesheet-Component

@Component
public class JavaScriptStylesheet implements Stylesheet {
  @Override
  public boolean appliesToTheme(Theme t) {
    return true;
  }
 
  @Override
  public URL getURL(Theme t) {
    try {
      return new URL("platform:/plugin/my.plugin/my/plugin/js.css");
    } catch (MalformedURLException e) {
      throw new RuntimeException(e);
    }
  }
}

Syntax Highlighting

If you remember the ldef file we shown above we defined the token styles like this:

token_def {
  js_default "-source-editor-code";
  js_operator "-source-editor-operator";
  js_bracket "-source-editor-bracket";
  js_keyword "-source-editor-keyword" bold;
  js_doc_default "-source-editor-doc";
  js_string "-source-editor-string";
  js_constant "-source-editor-keyword" bold;
  js_number "-source-editor-number";
  }

The first segment in between "" 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, ... .

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.

The perfect place is the .root-selector:

.root {
  -source-editor-code: rgb(0, 0, 0);
  -source-editor-operator: rgb(0, 0, 0);
  -source-editor-bracket: rgb(0, 0, 0);
  -source-editor-keyword: rgb(127, 0, 85);
  -source-editor-string:  rgb(42, 0, 255);
  -source-editor-number:  #6c83c4;
  -source-editor-doc: rgb(63, 127, 95);
}

The above color specs provide you a eclipse like syntax highlighting.

Open an editor

Using the editor opener service

The smart code framework by default publishes an org.eclipse.fx.code.editor.services.EditorOpener-Service who can be retrieved via injection and used to open an editor based on an URI like this

class MyComponent {
  @Inject
  EditorOpener opener;
 
  private void openFile(File f) {
    opener.openEditor( f.toURI().toURL().toExternalForm() );
  } 
}

The default implementation of the opener function will search the window/perspective for a MElementContainer tagged with editorContainer, so if you want to use that service you need to update your application model and tag eg one of your MPartStacks with it.

Doing it yourself

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:

EModelService modelService = // ...;
MPart part = modelService.createModelElement(MPart.class);
part.setCloseable(true);
part.setLabel("MySample.js");
part.setContributionURI("bundleclass://org.eclipse.fx.code.editor.fx/org.eclipse.fx.code.editor.fx.TextEditor");
part.getPersistedState().put(org.eclipse.fx.code.editor.Constants.DOCUMENT_URL, uri);
part.getTags().add(EPartService.REMOVE_ON_HIDE_TAG);
// ...

Dirty State Tracking & Save

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:

  • An addon who does the dirty state tracking org.eclipse.fx.code.editor.e4.addons.DirtyStateTrackingAddon
  • A handler who saves the file a dirty file org.eclipse.fx.code.editor.e4.handlers.SaveFile

Adding support for Autocomplete Features

Adding support for Error-Markers

Predefined annotations like Linenumbers, ...

There are currently 2 predefined control annotations found in org.eclipse.fx.text.ui.Feature:

  • SHOW_LINE_NUMBERS: showing a ruler on the left with linenumbers (on by default)
  • SHOW_HIDDEN_SYMBOLS: displaying informations about whitespace characters like tab, line-breaks (off by default)

Features are provided by SourceViewerConfiguration#getFeatures() : SetProperty<Feature> and modifying the provided Set instance - adding/removeing features - updates the editor bound to it.

Using preferences

When using the framework in an e4 application where DefaultSourceViewerConfiguration one can also use the preference system to set the features and restore them the current feature settings are stored with

  • key: Constants.PREFERENCE_KEY_EDITOR_FEATURE
  • nodePath: Constants.PREFERENCE_NODE_PATH

or expressed through the e(fx)clipse DI-Addons

@Inject
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) 
Set<Feature> featureSet;

or if you want to publish

@Inject
@Preference(key=Constants.PREFERENCE_KEY_EDITOR_FEATURE,nodePath=Constants.PREFERENCE_NODE_PATH) 
Property<Set<Feature>> featureSet;

As toggling features is a standard task there's a default handler implementation (org.eclipse.fx.code.editor.fx.handlers.ToggleEditorFeature) available for this task which you can register in your e4xmi-File. The command-parameter you need to pass is named feature and you pass in the feature name as a string.

Tabs and Spaces

Tab Advance

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:

  • key: Constants.PREFERENCE_TAB_ADVANCE
  • nodePath: Constants.PREFERENCE_NODE_PATH

So if you want to modify the tab-advance for the editor you can use the e(fx)clipse DI-Extensions like this:

@Inject
@Preference(key=Constants.PREFERENCE_TAB_ADVANCE,nodePath=Constants.PREFERENCE_NODE_PATH)
Property<Integer> tabAdvancePreference;

As updateing the tabAdvance is a standard task there's a handler implementation available named org.eclipse.fx.code.editor.fx.handlers.SetTabAdvance who accepts a command-parameter named tabAdvance.

Tabs instead of white spaces

Sample

The most complete sample showing the complete framework with all its features in action can be found at github implementing a Dart-Code-Editor

Back to the top