Sunday, July 06, 2014

Code highlighting/completion for MocOCL Web-Interface

The motivation of this project is the enhancement of the user experience of the existing MocOCL user-interface by extending it with two features, code-completion and syntax-highlighting. The existing web-interface offers only a simple HTML text field where the user specifies the desired cOCL expressions that should be evaluated by MocOCL. The evaluation request is then sent to an application server which handles the processing of the evaluation. Unfortunately, the user has to know exactly the structure of the underlying model to formulate these cOCL expressions correctly.

Code-Completion

The code-completion feature suggests keywords or properties to the user which are likely to occur at the current position within the cOCL expression. The keywords that are contained in the suggestion are specified by a grammar. This grammar is defined in a file using Xtext. Therefore we have to extract the keywords from an existing Xtext grammar and provide them as content for the code completion. How you can parse an Xtext file is documented below.

Syntax-Highlighting

Syntax-highlighting states that essential keywords of the cOCL language should visually stand out from the rest of the code to provide a better overview on the written cOCL expression. It should support the users when they read a specified cOCL expression to realise its structure and to understand the expression more quickly. The keywords are defined in an Xtext grammar file as mentioned previously. The syntax-highlighting was realized using CodeMirror, a JavaScript framework for advanced editor functionality.

Implementation of Syntax-Highlighting using CodeMirror

CodeMirror is a multifunctional text editor implemented in JavaScript with its main focus on providing advanced editing functionality for editing code. CodeMirror can be integrated into a simple HTML page like follows:

<! -- CodeMirror -->
<link rel="stylesheet" href="codemirror/lib/codemirror.css">


<! -- Highlighting -->
<script src="codemirror/lib/codemirror.js"></ script>
<script src="codemirror/mode/mococl/mococl.js"></ script>


<! -- Completion -->
<link rel="stylesheet" href="codemirror/addon/hint/show-hint.css">
<script src="codemirror/addon/hint/show-hint.js"></script>
<script src="codemirror/addon/hint/mococl-hint.js"></script>


CodeMirror comes along with a simple directory structure. The main functionality is located in the lib directory in the file codemirror.js. The file codemirror.css defines the default style for the editor. The MocOCL mode, which defines the actual language to highlight, is specified in mococl.js. The optional files mococl-hint.js, show-hint.js and show-hint.css located in the addon/hint directory are required to offer code-completion.
The enhancment of a HTML text area element is done as follows:

<label for="codeArea">Code:</label><br />
<textarea id="codeArea" rows="20" cols="100"></textarea>

<script>

var editor = CodeMirror.fromTextArea(document.
             getElementById("codeArea"),{
    mode: "mococl",
    value: "Start Code...",
    extraKeys: {"Ctrl-Space": "autocomplete"},
    textWrapping: true,
    lineNumbers: true,
    smartIndent: false
});
</script>


The definition of the extraKeys triggers the auto-completion implemented in the JavaScript files which requests the keywords/properties via a HTTP-GET request from the application. The an example for the auto-completion in action is shown. below.



Xtext parsing at the application server

The server-side implementation is responsible for parsing the provided Xtext and Ecore file as well as for processing the HTTP-GET requests it receives from the client-side.

Since the xtext-parsing is not done within the Eclipse environment, an Xtext-standalone version must be used and  dependencies that would otherwise already be provided by Eclipse must be added. This concerns libraries from org.eclipse.emf, org.eclipse.xtext, guice, guava and javax.inject. The following code demonstrates how a standalone parser can be obtained:

public class XtextParser{

    @Inject
    private IParser parser;
   
    public XtextParser() {
        setupParser();
    }
   
    private void setupParser() {
        Injector injector = new XtextStandaloneSetup().createInjectorAndDoEMFRegistration();
        injector.injectMembers(this);
    }
}


After initialisation the parser can be used to parse Xtext files. It generates the abstract syntax tree (AST) and returns the root element.

public EObject parse(Reader reader) throws IOException {
    IParseResult result = parser.parse(reader);
    if (result.hasSyntaxErrors()) {
        throw new ParseException("Provided input " +
            "contains syntax errors.");
    }
    return result.getRootASTElement();
}


Starting from the root element we recursively obtain all contained objects and check if they are instances of AssignmentImpl, KeywordImpl or ParserRuleImpl. These instances contain the required information which is collected and sent to client for the auto-completion.





No comments:

Post a Comment