Search code examples
eclipse-pluginxtextxtend

auto pretty formatting in xtext


I want to ask that is there a way to do Pretty formatting in xtext automatically without (ctrl+shift+f) or turning it on from preference menu. What I actually want is whenever a user completes writing the code it is automatically pretty formatted (or on runtime) without (ctrl+shift+f).


Solution

  • There is a way for doing that which is called "AutoEdit". It's not exactly when the user completes writing but it's with every token. That's at least what I have done. You can for sure change that. I will give you an example that I implemented myself for my project. It basically capitalizes everykeyword as the user types (triggered by spaces and endlines).

    It is a UI thing. So, In your UI project:

    in MyDslUiModule.java you need to attach your AutoEdit custom made class do that like this:

    public Class<? extends DefaultAutoEditStrategyProvider> bindDefaultAutoEditStrategyProvider() 
    {
        return MyDslAutoEditStrategyProvider.class;
    }
    

    Our class will be called MyDslAutoEditStrategyProvider so, go ahead and create it in a MyDslAutoEditStrategyProvider.java file. Mine had this to do what i explained in the introduction:

    import java.util.Set;
    
    import org.eclipse.jface.text.DocumentCommand;
    import org.eclipse.jface.text.IAutoEditStrategy;
    import org.eclipse.jface.text.IDocument;
    import org.eclipse.jface.text.IRegion;
    import org.eclipse.xtext.GrammarUtil;
    import org.eclipse.xtext.IGrammarAccess;
    import org.eclipse.xtext.ui.editor.autoedit.DefaultAutoEditStrategyProvider;
    import org.eclipse.xtext.ui.editor.model.XtextDocument;
    
    import com.google.inject.Inject;
    import com.google.inject.Provider;
    
    public class MyDslAutoEditStrategyProvider extends DefaultAutoEditStrategyProvider {
    
    @Inject
    Provider<IGrammarAccess> iGrammar;
    
    private Set<String> KWDS;
    
    @Override
    protected void configure(IEditStrategyAcceptor acceptor) {
    
        KWDS = GrammarUtil.getAllKeywords(iGrammar.get().getGrammar());
    
        IAutoEditStrategy strategy = new IAutoEditStrategy() 
        {
    
            @Override
            public void customizeDocumentCommand(IDocument document, DocumentCommand command) 
            {
                if ( command.text.length() == 0 || command.text.charAt(0) > ' ') return;
    
                IRegion reg = ((XtextDocument) document).getLastDamage();
    
                try {
                    String token = document.get(reg.getOffset(), reg.getLength());
                    String possibleKWD = token.toLowerCase();
                    if ( token.equals(possibleKWD.toUpperCase()) || !KWDS.contains(possibleKWD) ) return;
                    document.replace(reg.getOffset(), reg.getLength(), possibleKWD.toUpperCase());
    
                } 
                catch (Exception e) 
                {
                    System.out.println("AutoEdit error.\n" + e.getMessage());   
                }
            }
        };
    
        acceptor.accept(strategy, IDocument.DEFAULT_CONTENT_TYPE);
    
        super.configure(acceptor);
    
        }
    }
    

    I assume you saying "user completes writing" can be as "user saves file". If so here is how to trigger the formatter on save:

    in MyDslUiModule.java:

    public Class<? extends XtextDocumentProvider> bindXtextDocumentProvider() 
    {
        return MyDslDocumentProvider.class;
    }
    

    Create the MyDslDocumentProvider class:

    import org.eclipse.core.runtime.CoreException;
    import org.eclipse.core.runtime.IProgressMonitor;
    import org.eclipse.jface.text.IDocument;
    import org.eclipse.ui.PlatformUI;
    import org.eclipse.ui.handlers.IHandlerService;
    import org.eclipse.xtext.ui.editor.model.XtextDocumentProvider;
    
    public class MyDslDocumentProvider extends XtextDocumentProvider 
    {
        @Override
        protected void doSaveDocument(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
                throws CoreException {
            IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
            try {
                service.executeCommand("org.eclipse.xtext.ui.FormatAction", null);
            } catch (Exception e) 
            {
                e.printStackTrace();
            }
            super.doSaveDocument(monitor, element, document, overwrite);
        }
    }