/**
* Copyright (c) 2005-2008 Aptana, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Aptana Public License v1.0
* which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* Redistribution, except as permitted by the above license, is prohibited.
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editor.html;
import java.net.URI;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import com.aptana.ide.editor.html.lexing.HTMLTokenTypes;
import com.aptana.ide.editors.unified.ChildOffsetMapper;
import com.aptana.ide.editors.unified.IParentOffsetMapper;
import com.aptana.ide.lexer.Lexeme;
import com.aptana.ide.lexer.LexemeList;
import com.aptana.ide.lexer.Token;
import com.aptana.ide.parsing.CodeLocation;
import com.aptana.ide.parsing.ICodeLocation;
import com.aptana.ide.server.jetty.server.HTMLPreviewConstants;
/**
* The HTMLOffsetMapper understands how to map between lexemes, offsets and the environment
*
* @author Ingo Muschenetz
*/
public class HTMLOffsetMapper extends ChildOffsetMapper
{
// private IRuntimeEnvironment environment;
/**
* @param parent
*/
public HTMLOffsetMapper(IParentOffsetMapper parent)
{
super(parent);
// environment = HTMLLanguageEnvironment.getInstance().getRuntimeEnvironment();
}
/**
* Returns a "hash name" allowing us to properly query code assist for appropriate completions.
*
* @return NameHash
*/
public String getNameHash()
{
String name = ""; //$NON-NLS-1$
int position = getCurrentLexemeIndex();
// backtrack over lexemes to find name - we are really just
// searching for the last OPEN_ELEMENT
while (position >= 0)
{
Lexeme curLexeme = getLexemeList().get(position);
// If we've jsut typed a ">", we jsut closed a tag.
if (curLexeme.getText().equals(">")) //$NON-NLS-1$
{
return ""; //$NON-NLS-1$
}
// If we've just typed a "<", we will be in an error state.
if (curLexeme.typeIndex == HTMLTokenTypes.ERROR && curLexeme.getText().equals("<")) //$NON-NLS-1$
{
return ""; //$NON-NLS-1$
}
if (curLexeme.typeIndex == HTMLTokenTypes.START_TAG)
{
return curLexeme.getText().replaceAll("<", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
position--;
}
return name;
}
/**
*
*/
public ICodeLocation findTarget(Lexeme lexeme)
{
// check for src/href attributes
if (lexeme.getToken().getLexerGroup().equals("attribute")) //$NON-NLS-1$
{
LexemeList lexemeList = getFileService().getLexemeList();
int index = getLexemeIndexFromDocumentOffset(lexeme.getStartingOffset() + 1);
if (index < 2)
{
return null;
}
Lexeme srcLexeme = lexemeList.get(index - 2); // get lexeme two tokens ago (skip the '=')
if (srcLexeme.getText().equalsIgnoreCase("src")) //$NON-NLS-1$
{
return findFile(lexeme.getText());
}
else if (srcLexeme.getText().equalsIgnoreCase("href")) //$NON-NLS-1$ // links to stylesheets (hopefully)
{
return findFile(lexeme.getText());
}
}
return null;
}
/**
* Tries to return a CodeLocation for the passed in attribute value. Strips surounding quotes, and then tries to
* resolve filename (as absolute path, relative to doc root, or relative to current file).
*
* @param name
* @return
*/
private ICodeLocation findFile(String name)
{
// strip off quotes from name, if there
if (name.startsWith("\"") || name.startsWith("'")) //$NON-NLS-1$ //$NON-NLS-2$
{
name = name.substring(1);
}
if (name.endsWith("\"") || name.endsWith("'")) //$NON-NLS-1$ //$NON-NLS-2$
{
name = name.substring(0, name.length() - 1);
}
// what if it's an http, https, ftp, mailto link?
if (name.startsWith("http:") || name.startsWith("https:") || name.startsWith("ftp:") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|| name.startsWith("mailto:")) //$NON-NLS-1$
{
return null;
}
Lexeme destLexeme = new Lexeme(new Token(null), "", 0); //$NON-NLS-1$
if (name.startsWith("file:")) //$NON-NLS-1$
{
return new CodeLocation(name, destLexeme);
}
// Try docRoot relative
IProject project = getProject();
String docRoot = getDocumentRoot(project);
if (docRoot != null && docRoot.trim().length() > 0)
{
String possiblePath = docRoot + '/' + name;
IFile file = project.getFile(possiblePath);
if (file.exists())
{
return new CodeLocation(file.getLocationURI().toString(), destLexeme);
}
}
// Now try relative to current file
String pathToCurrent = getFileService().getSourceProvider().getSourceURI();
String parentPath = pathToCurrent.substring(0, pathToCurrent.lastIndexOf('/'));
return new CodeLocation(parentPath + '/' + name, destLexeme);
}
private String getDocumentRoot(IProject project)
{
if (project == null)
return null;
try
{
return project.getPersistentProperty(new QualifiedName("", HTMLPreviewConstants.CONTEXT_ROOT)); //$NON-NLS-1$
}
catch (CoreException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private IProject getProject()
{
String fileURI = getFileService().getSourceProvider().getSourceURI();
if (fileURI.startsWith("file://"))
{
fileURI = "file:" + fileURI.substring(7);
}
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
URI rootURI = root.getLocationURI();
String rootPath = rootURI.toString();
if (fileURI.startsWith(rootPath))
{
String leftever = fileURI.substring(rootPath.length());
IPath leftoverPath = new Path(leftever);
String firstSegment = leftoverPath.segment(0);
IProject project = root.getProject(firstSegment);
if (project.exists())
{
return project;
}
}
return null;
}
}