package com.redhat.ceylon.eclipse.code.editor; import static com.redhat.ceylon.eclipse.util.EditorUtil.getCurrentEditor; import static com.redhat.ceylon.eclipse.util.EditorUtil.getSelection; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.*; import java.io.IOException; import java.io.StringWriter; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.ParserRuleContext; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextSelection; import org.eclipse.ltk.core.refactoring.DocumentChange; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.text.edits.ReplaceEdit; import com.redhat.ceylon.compiler.typechecker.parser.CeylonLexer; import com.redhat.ceylon.compiler.typechecker.parser.CeylonParser; import com.redhat.ceylon.compiler.typechecker.util.NewlineFixingStringStream; import com.redhat.ceylon.eclipse.code.refactor.AbstractHandler; import com.redhat.ceylon.eclipse.code.style.CeylonStyle; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.eclipse.util.StringBuilderWriter; import com.redhat.ceylon.ide.common.model.CeylonIdeConfig; import com.redhat.ceylon.ide.common.model.JavaToCeylonConverterConfig; import ceylon.formatter.format_; import ceylon.formatter.options.SparseFormattingOptions; import ceylon.formatter.options.combinedOptions_; import ceylon.formatter.options.loadProfile_; import ceylon.language.Singleton; import ceylon.tool.converter.java2ceylon.Java8Lexer; import ceylon.tool.converter.java2ceylon.Java8Parser; import ceylon.tool.converter.java2ceylon.JavaToCeylonConverter; import ceylon.tool.converter.java2ceylon.ScopeTree; public class PasteAsCeylonHandler extends AbstractHandler { private static final class Transformer implements IRunnableWithProgress { private final IProject project; private final String javaCode; private String ceylonCode; private Transformer(IProject project, String javaCode) { this.project = project; this.javaCode = javaCode; } public String getCeylonCode() { return ceylonCode; } @Override public void run(IProgressMonitor monitor) { monitor.beginTask("Converting Java to Ceylon", -1); try { CeylonIdeConfig ideConfig = modelJ2C().ceylonModel() .getProject(project) .getIdeConfiguration(); ceylonCode = transformJavaToCeylon(javaCode, ideConfig); } catch (IOException e) { CeylonPlugin.log(IStatus.ERROR, "Could not transform Java code", e); } monitor.done(); } } @Override public Object execute(ExecutionEvent event) throws ExecutionException { Clipboard cb = new Clipboard(null); final String javaCode = (String) cb.getContents(TextTransfer.getInstance()); CeylonEditor editor = (CeylonEditor) getCurrentEditor(); final IProject project = editor.getParseController() .getProject(); String ceylonCode; try { Transformer transformer = new Transformer(project, javaCode); editor.getEditorSite() .getWorkbenchWindow() .run(true, true, transformer); ceylonCode = transformer.getCeylonCode(); } catch (Exception e) { e.printStackTrace(); return null; } ceylonCode = format(ceylonCode, editor); insertTextInEditor(ceylonCode, editor); return null; } private static String transformJavaToCeylon( String javaCode, CeylonIdeConfig ideConfig) throws IOException { ANTLRInputStream input = new ANTLRInputStream(javaCode); Java8Lexer lexer = new Java8Lexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); Java8Parser parser = new Java8Parser(tokens); ParserRuleContext tree = parser.compilationUnit(); StringWriter out = new StringWriter(); JavaToCeylonConverterConfig config = ideConfig.getConverterConfig(); ScopeTree scopeTree = new ScopeTree(); tree.accept(scopeTree); JavaToCeylonConverter converter = new JavaToCeylonConverter(out, config.getTransformGetters(), config.getUseValues(), scopeTree); ideConfig.save(); tree.accept(converter); String ceylonCode = out.toString(); if (ceylonCode.equals("")) { return javaCode; } else { return ceylonCode; } } private void insertTextInEditor(String ceylonCode, CeylonEditor editor) { ITextSelection selection = getSelection(editor); if (selection==null) { selection = new TextSelection(0, 0); } IDocument doc = editor.getCeylonSourceViewer() .getDocument(); DocumentChange change = new DocumentChange("Paste Java as Ceylon", doc); change.setEdit(new ReplaceEdit( selection.getOffset(), selection.getLength(), ceylonCode)); try { change.perform(new NullProgressMonitor()); editor.getSelectionProvider().setSelection( new TextSelection( selection.getOffset() + ceylonCode.length(), 0)); } catch (CoreException e) { CeylonPlugin.log(IStatus.ERROR, "Could not paste transformed code", e); } } private String format(String ceylonCode, CeylonEditor editor) { IProject project = editor.getParseController() .getProject(); IDocument doc = editor.getCeylonSourceViewer() .getDocument(); // get initial indentation int indentation = 0; ITextSelection selection = getSelection(editor); if (selection!=null) { try { IRegion region = doc.getLineInformation( selection.getStartLine()); String line = doc.get(region.getOffset(), region.getLength()); char[] chars = line.toCharArray(); loop: for (int i=0; i<chars.length; i++) { switch (chars[i]) { case '\t': indentation += utilJ2C().indents().getIndentSpaces(); break; case ' ': indentation += 1; break; default: break loop; } } indentation /= utilJ2C().indents().getIndentSpaces(); } catch (BadLocationException e) { indentation = 0; } } StringBuilder builder = new StringBuilder(ceylonCode.length()); NewlineFixingStringStream stream = new NewlineFixingStringStream(ceylonCode + " "); CeylonLexer lexer = new CeylonLexer(stream); org.antlr.runtime.CommonTokenStream tokenStream = new org.antlr.runtime.CommonTokenStream(lexer); tokenStream.fill(); CeylonParser ceylonParser = new CeylonParser(tokenStream); try { format_.format( ceylonParser.compilationUnit(), combinedOptions_.combinedOptions( loadProfile_.loadProfile( CeylonStyle.getFormatterProfile(project), /* inherit = */ false, /* baseDir = */ project.getLocation().toOSString()), new Singleton<SparseFormattingOptions> (SparseFormattingOptions.$TypeDescriptor$, CeylonStyle.getEclipseWsOptions(doc))), new StringBuilderWriter(builder), //new BufferedTokenStream(lexer), null, indentation); } catch (Exception e) { CeylonPlugin.log(IStatus.ERROR, "Error during converted code formatting", e); return ceylonCode; } catch (ceylon.language.AssertionError e) { CeylonPlugin.log(IStatus.ERROR, "Error during converted code formatting", e); return ceylonCode; } return builder.toString(); } @Override protected boolean isEnabled(CeylonEditor editor) { return true; } }