Monday, 8 September 2014

Restricting auto-completion options - Scope wise

In MIB file, 2 values are required for oid value; parent object and object id. As for parent object name, editor should able to provide list of auto-completion based on previously defined object identifier plus objects that are imported from other MIB file.

The problem with this imported objects are not all are of object identifiers, some can be macro (OBJECT-TYPE) or some can be data types (NetworkAddress, IpAddress, Counter, Gauge etc). Hence its wrong to list all these as possible parent objects within the auto-completion list.


The screenshot illustrates the scenario. Therefore the challenge is to remove those options (macro and datatype) from the option list.

In order to do this, Xtext provides scope restriction. Since I have not (yet) look into cross reference with other MIB files, I will just be happy by hard-coding the exclusion list. This is temporary until I dive into MIB exports from dependency files.

While searching over net for the answer, Generally, I realized few things:

  • Unfortunately this is no longer declarative codes but need to be told imperatively - requires some 'coding'. We will use Xtend.
  • Xtend is something rather new in Xtext, therefore quite number of examples out there may use Java.
  • While Xtend simplify the expression, you may need to spend some time reading on Xtend for more effective coding!
Here is the code I wrote this achieve this:


MibScopeProvider.xtend
package com.ravi.mib.xtext.scoping

import org.eclipse.xtext.scoping.IScope
import com.ravi.mib.xtext.mib.OidValue
import org.eclipse.emf.ecore.EReference
import org.eclipse.xtext.scoping.Scopes
import com.ravi.mib.xtext.mib.Definition
import org.eclipse.xtext.EcoreUtil2
import org.eclipse.xtext.scoping.impl.SimpleScope
import java.util.HashSet

/**
 * This class contains custom scoping description.
 * 
 * see : http://www.eclipse.org/Xtext/documentation.html#scoping
 * on how and when to use it 
 *
 */
class MibScopeProvider extends org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider {
 def IScope scope_OidValue_parent(OidValue value, EReference ref) {
  val excluded = new HashSet(#["NetworkAddress", "IpAddress", "Counter", "Gauge", "TimeTicks", "OBJECT-TYPE"])
  new SimpleScope(
   Scopes.scopedElementsFor(
    EcoreUtil2::getAllContentsOfType(value.eContainer.eContainer as Definition,
     com.ravi.mib.xtext.mib.Object).filter[!excluded.contains(it.name)]));
 }
}


MibScopeProvider.xtend is a xtend file pre-generated when Xtext project was created. I find it rather interesting that method name has lot to do with context where it will be called. "scope_OidValue_parent", "OidValue" is the related EObject for the rule and "parent" is EReference that we are interested.

Here is the complement rule to go with the code:

Mib.xtext
OidValue:
 '::=' '{' parent=[Object] oidnum=INT '}';

Here is the screenshot once this implemented:



Now for fun lets compare Xtend code vs Java code that generated from it, just to show arguably how much saving + readability Xtend can provide over Java.


Bash Terminal
dev@ravi-vm:~/workspace/com.ravi.mib.xtext$ wc ./src/com/ravi/mib/xtext/scoping/MibScopeProvider.xtend
  30   78 1030 ./src/com/ravi/mib/xtext/scoping/MibScopeProvider.xtend
dev@ravi-vm:~/workspace/com.ravi.mib.xtext$ wc ./xtend-gen/com/ravi/mib/xtext/scoping/MibScopeProvider.java
  52  153 2362 ./xtend-gen/com/ravi/mib/xtext/scoping/MibScopeProvider.java
Its almost half less coding!

No comments:

Post a Comment