/** * Copyright (c) 2011 Cloudsmith Inc. and other contributors, as listed below. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cloudsmith * */ package org.cloudsmith.geppetto.pp.dsl.ui.editor.autoedit; import java.util.List; import org.cloudsmith.geppetto.pp.dsl.ui.preferences.PPPreferencesHelper; import org.eclipse.jface.text.DocumentCommand; import org.eclipse.jface.text.IAutoEditStrategy; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.custom.VerifyKeyListener; import org.eclipse.xtext.ui.editor.ISourceViewerAware; import org.eclipse.xtext.ui.editor.autoedit.DefaultAutoEditStrategyProvider; import org.eclipse.xtext.ui.editor.model.TerminalsTokenTypeToPartitionMapper; import com.google.common.base.Supplier; import com.google.common.collect.Lists; import com.google.inject.Inject; /** * Overrides the default to make auto matching/insert configurable. * */ public class PPEditStrategyProvider extends DefaultAutoEditStrategyProvider { private static class PreferenceCheckingStrategy implements IAutoEditStrategy { final private Supplier<Boolean> enablement; final protected IAutoEditStrategy wrapped; public PreferenceCheckingStrategy(IAutoEditStrategy wrapped, Supplier<Boolean> enablement) { this.enablement = enablement; this.wrapped = wrapped; } /* * (non-Javadoc) * * @see org.eclipse.jface.text.IAutoEditStrategy#customizeDocumentCommand(org.eclipse.jface.text.IDocument, * org.eclipse.jface.text.DocumentCommand) */ @Override public void customizeDocumentCommand(IDocument document, DocumentCommand command) { if(!enablement.get()) return; wrapped.customizeDocumentCommand(document, command); } } private static class WrappingAcceptor implements IEditStrategyAcceptor { private IEditStrategyAcceptor acceptor; private Supplier<Boolean> enablement; public WrappingAcceptor(IEditStrategyAcceptor acceptor, Supplier<Boolean> enablement) { this.acceptor = acceptor; this.enablement = enablement; } @Override public void accept(IAutoEditStrategy strategy, String contentType) { acceptor.accept(new PreferenceCheckingStrategy(strategy, enablement), contentType); } } @Inject private PPPreferencesHelper prefsHelper; /** * @see org.eclipse.xtext.ui.editor.autoedit.DefaultAutoEditStrategyProvider#configureCompoundBracesBlocks(org.eclipse.xtext.ui.editor.autoedit.AbstractEditStrategyProvider.IEditStrategyAcceptor) */ @Override protected void configureCompoundBracesBlocks(IEditStrategyAcceptor acceptor) { super.configureCompoundBracesBlocks(new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoCompleteBlockWanted(); } })); } @Override protected void configureCurlyBracesBlock(IEditStrategyAcceptor acceptor) { super.configureCurlyBracesBlock(new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoBraceInsertWanted(); } })); } protected void configureDqStringLiteral(IEditStrategyAcceptor acceptor) { acceptor = new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoDqStringInsertWanted(); } }); acceptor.accept(partitionInsert.newInstance("\"", "\""), IDocument.DEFAULT_CONTENT_TYPE); // The following two are registered for the default content type, because on deletion // the command.offset is cursor-1, which is outside the partition of terminals.length = 1. // How crude is that? // Note that in case you have two string literals following each other directly, the deletion strategy wouldn't apply. // One could add the same strategy for the STRING partition in addition to solve this acceptor.accept(partitionDeletion.newInstance("\"", "\""), IDocument.DEFAULT_CONTENT_TYPE); acceptor.accept( partitionEndSkippingEditStrategy.get(), TerminalsTokenTypeToPartitionMapper.STRING_LITERAL_PARTITION); } @Override protected void configureMultilineComments(IEditStrategyAcceptor acceptor) { super.configureMultilineComments(new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoMLCommentInsertWanted(); } })); } @Override protected void configureParenthesis(IEditStrategyAcceptor acceptor) { super.configureParenthesis(new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoParenthesisInsertWanted(); } })); } protected void configureSqStringLiteral(IEditStrategyAcceptor acceptor) { acceptor = new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoSqStringInsertWanted(); } }); acceptor.accept(partitionInsert.newInstance("'", "'"), IDocument.DEFAULT_CONTENT_TYPE); // The following two are registered for the default content type, because on deletion // the command.offset is cursor-1, which is outside the partition of terminals.length = 1. // How crude is that? // Note that in case you have two string literals following each other directly, the deletion strategy wouldn't apply. // One could add the same strategy for the STRING partition in addition to solve this acceptor.accept(partitionDeletion.newInstance("\"", "\""), IDocument.DEFAULT_CONTENT_TYPE); acceptor.accept( partitionEndSkippingEditStrategy.get(), TerminalsTokenTypeToPartitionMapper.STRING_LITERAL_PARTITION); } @Override protected void configureSquareBrackets(IEditStrategyAcceptor acceptor) { super.configureSquareBrackets(new WrappingAcceptor(acceptor, new Supplier<Boolean>() { @Override public Boolean get() { return prefsHelper.isAutoBracketInsertWanted(); } })); } /* * (non-Javadoc) * * @see org.eclipse.xtext.ui.editor.autoedit.DefaultAutoEditStrategyProvider#configureStringLiteral(org.eclipse.xtext.ui.editor.autoedit. * AbstractEditStrategyProvider.IEditStrategyAcceptor) */ @Override protected void configureStringLiteral(IEditStrategyAcceptor acceptor) { // separate Sq and Dq configuration configureSqStringLiteral(acceptor); configureDqStringLiteral(acceptor); } /* * Overrides the default, checking if strategy is wrapped and if so applies the view/key listener * on the wrapped strategy. * (non-Javadoc) * * @see org.eclipse.xtext.ui.editor.autoedit.AbstractEditStrategyProvider#getStrategies(org.eclipse.jface.text.source.ISourceViewer, * java.lang.String) */ @Override public List<IAutoEditStrategy> getStrategies(final ISourceViewer sourceViewer, final String contentType) { final List<IAutoEditStrategy> strategies = Lists.newArrayList(); configure(new IEditStrategyAcceptor() { public void accept(IAutoEditStrategy strategy, String type) { if(type == null || contentType.equals(type)) { IAutoEditStrategy original = strategy; if(strategy instanceof PreferenceCheckingStrategy) strategy = ((PreferenceCheckingStrategy) strategy).wrapped; if(strategy instanceof ISourceViewerAware) { ((ISourceViewerAware) strategy).setSourceViewer(sourceViewer); } if(strategy instanceof VerifyKeyListener) { sourceViewer.getTextWidget().addVerifyKeyListener((VerifyKeyListener) strategy); } strategies.add(original); } } }); return strategies; } }