/******************************************************************************* * Copyright (c) 2009 IBM Corporation. * 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: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package com.redhat.ceylon.eclipse.code.outline; import static com.redhat.ceylon.eclipse.code.outline.CeylonOutlineNode.DEFAULT_CATEGORY; import static com.redhat.ceylon.eclipse.code.outline.CeylonOutlineNode.IMPORT_LIST_CATEGORY; import static com.redhat.ceylon.eclipse.code.outline.CeylonOutlineNode.ROOT_CATEGORY; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import org.eclipse.compare.IEditableContent; import org.eclipse.compare.IEncodedStreamContentAccessor; import org.eclipse.compare.ISharedDocumentAdapter; import org.eclipse.compare.IStreamContentAccessor; import org.eclipse.compare.ResourceNode; import org.eclipse.compare.structuremergeviewer.DocumentRangeNode; import org.eclipse.compare.structuremergeviewer.IStructureComparator; import org.eclipse.compare.structuremergeviewer.StructureCreator; import org.eclipse.compare.structuremergeviewer.StructureRootNode; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.text.IDocument; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.eclipse.code.parse.CeylonParseController; /** * @author rfuhrer */ public class CeylonStructureCreator extends StructureCreator { @Override public String getName() { return "Ceylon Structure Compare"; } @Override protected IStructureComparator createStructureComparator(Object input, IDocument document, ISharedDocumentAdapter sharedDocumentAdapter, IProgressMonitor monitor) throws CoreException { if (input instanceof CeylonDocumentRangeNode) { return (CeylonDocumentRangeNode) input; } final boolean isEditable; if (input instanceof IEditableContent) { IEditableContent ec = (IEditableContent) input; isEditable = ec.isEditable(); } else { isEditable = false; } StructureRootNode structureRootNode = new StructureRootNode(document, input, this, sharedDocumentAdapter) { @Override public boolean isEditable() { return isEditable; } }; CeylonParseController pc = new CeylonParseController(); if (input instanceof ResourceNode) { ResourceNode node = (ResourceNode) input; IResource file = node.getResource(); pc.initialize(file.getProjectRelativePath(), file.getProject(), null); } else { pc.initialize(null, null, null); } if (pc.parseAndTypecheck(document, 10, monitor, null) != null) { // now visit the model, creating TreeCompareNodes for each ModelTreeNode CeylonOutlineNode tree = new CeylonOutlineBuilder() { //don't create nodes for shortcut refinement //because we can't distinguish them w/o a //full typecheck public void visit(Tree.SpecifierStatement that) {} }.buildTree(pc); if (tree!=null) { buildCompareTree(tree, structureRootNode, document); } } return structureRootNode; } private void buildCompareTree(CeylonOutlineNode outlineNode, DocumentRangeNode parent, IDocument document) { CeylonDocumentRangeNode compareNode; switch (outlineNode.getCategory()) { case ROOT_CATEGORY: //attach children of the unit node directly to our root compareNode = new CeylonDocumentRangeNode(parent, "@root", outlineNode, document) { @Override public String getName() { return "Ceylon Source File"; } }; break; case IMPORT_LIST_CATEGORY: compareNode = new CeylonDocumentRangeNode(parent, "@importlist", outlineNode, document); break; case DEFAULT_CATEGORY: compareNode = new CeylonDocumentRangeNode(parent, outlineNode.getIdentifier(), outlineNode, document); break; default: // The outline view has some extra nodes // we don't care about so just do nothing return; } for (CeylonOutlineNode treeChild: outlineNode.getChildren()) { buildCompareTree(treeChild, compareNode, document); } parent.addChild(compareNode); } @Override public String getContents(Object node, boolean ignoreWhitespace) { if (node instanceof IStreamContentAccessor) { IStreamContentAccessor sca = (IStreamContentAccessor) node; try { String contents = readString(sca); return ignoreWhitespace ? contents.replaceAll("\\p{javaWhitespace}+", " ") : contents; } catch (CoreException ex) { ex.printStackTrace(); } } return null; } private static String readString(InputStream is, String encoding) { if (is == null) { return null; } BufferedReader reader = null; try { StringBuffer buffer= new StringBuffer(); char[] part = new char[2048]; int read = 0; reader = new BufferedReader(new InputStreamReader(is, encoding)); while ((read= reader.read(part)) != -1) { buffer.append(part, 0, read); } return buffer.toString(); } catch (IOException ex) { // NeedWork } finally { if (reader != null) { try { reader.close(); } catch (IOException ex) { // silently ignored } } } return null; } public static String readString(IStreamContentAccessor sa) throws CoreException { InputStream is= sa.getContents(); if (is != null) { String encoding = null; if (sa instanceof IEncodedStreamContentAccessor) { try { encoding = ((IEncodedStreamContentAccessor) sa).getCharset(); } catch (Exception e) {} } if (encoding == null) encoding = ResourcesPlugin.getEncoding(); return readString(is, encoding); } return null; } @Override protected String[] getPath(Object element, Object input) { return super.getPath(element, input); } @Override protected String getDocumentPartitioning() { return IDocument.DEFAULT_CONTENT_TYPE; } }