X

Geertjan's Blog

  • October 14, 2010

Embedding JavaScript Editor in Java Editor

Geertjan Wielenga
Product Manager
Via Dmitry Safonov on the dev at platform dot netbeans dot org mailing list:

Code:

import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.java.lexer.JavaTokenId;
import org.netbeans.api.lexer.InputAttributes;
import org.netbeans.api.lexer.Language;
import org.netbeans.api.lexer.LanguagePath;
import org.netbeans.api.lexer.Token;
import org.netbeans.api.lexer.TokenUtilities;
import org.netbeans.spi.lexer.LanguageEmbedding;
import org.netbeans.spi.lexer.LanguageProvider;
import org.openide.util.lookup.ServiceProvider;
@ServiceProvider(service = LanguageProvider.class)
public class EmbeddingLanguageProvider extends LanguageProvider {
private Language embeddedLanguage;
public static final String START_FRAGMENT = "/\*-{";
public static final String END_FRAGMENT = "}-\*/";
@Override
public Language<?> findLanguage(String mimeType) {
return null;
}
@Override
public LanguageEmbedding<?> findLanguageEmbedding(Token<?> token, LanguagePath languagePath, InputAttributes inputAttributes) {
initLanguage();
if (JavaTokenId.BLOCK_COMMENT == token.id()) {
if (token.text() != null
&& TokenUtilities.startsWith(token.text(), START_FRAGMENT)
&& TokenUtilities.endsWith(token.text(), END_FRAGMENT)) {
return LanguageEmbedding.create(embeddedLanguage, START_FRAGMENT.length(), END_FRAGMENT.length());
}
}
return null;
}
private void initLanguage() {
embeddedLanguage = MimeLookup.getLookup("text/javascript").lookup(Language.class);
if(embeddedLanguage == null) {
throw new NullPointerException("Can't find language for embedding");
}
}
}

From e-mail from Dmitry: "Lexer-based coloring (keywords, string literals) works fine, as well as completion for abbreviations (start typing "switch" and press ctrl+space), but semantic highlighting and more advanced completion doesn't seem to work. One disadvantage of such language extension is that modules which provide original languages often are Non-API modules and if you want to use TokenId definitions from original language in your code you should specify Implementation dependency on them."

Thanks Dmitry.

Join the discussion

Comments ( 3 )
  • guest Monday, May 23, 2011
    how do I add the so defined LanguageProvider to the lookup file layers.xml?
  • Geertjan Monday, January 23, 2012

    Via the @ServiceProvider annotation that you see in the code above. If you have that annotation when you build the module, then the layer.xml entries will be created by the NetBeans annotation processor. You will see those entries not in your module's layer.xml file, but in the generated-layer.xml file in the 'build' folder, which you can only see in the Files or Favorites window.


  • guest Monday, February 11, 2013

    This works, until there is a block comment in the target document that appears before the embedded-style comment and does not match the embedded-sytle and/or is a different kind of embedded language (maybe javadoc?). The NetBeans platform seems to cache the first result of LanguageProvider.findLanguageEmbedding(..) for all JavaTokenId.BLOCK_COMMENT tokens and the method will no longer be called, resulting in no more embedded language support.

    From what I can see the platform uses the org.netbeans.spi.lexer.EmbeddingPresence Enum to allow configuration of this caching behavior. But I cannot see how to do this without providing my very own root language. Any idea how this can be applied to the Java language without having to provide a completely new Java support?


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.