/*******************************************************************************
* This file is part of the Twig eclipse plugin.
*
* (c) Robert Gruendler <r.gruendler@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
******************************************************************************/
package com.dubture.twig.core.model;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.index2.search.ISearchEngine;
import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule;
import org.eclipse.dltk.core.index2.search.ISearchEngine.SearchFor;
import org.eclipse.dltk.core.index2.search.ISearchRequestor;
import org.eclipse.dltk.core.index2.search.ModelAccess;
import org.eclipse.dltk.core.search.IDLTKSearchScope;
import org.eclipse.dltk.core.search.SearchEngine;
import org.eclipse.dltk.internal.core.ModelElement;
import org.eclipse.dltk.internal.core.SourceModule;
import org.eclipse.dltk.internal.core.util.LRUCache;
import org.eclipse.php.internal.core.PHPLanguageToolkit;
import org.eclipse.php.internal.core.model.PhpModelAccess;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.dubture.twig.core.ExtensionManager;
import com.dubture.twig.core.log.Logger;
import com.dubture.twig.core.parser.SourceParserUtil;
import com.dubture.twig.core.parser.ast.node.BlockStatement;
import com.dubture.twig.core.parser.ast.node.StringLiteral;
import com.dubture.twig.core.parser.ast.node.TwigModuleDeclaration;
/**
*
*
*
*
*
* @author Robert Gruendler <r.gruendler@gmail.com>
*
*/
@SuppressWarnings("restriction")
public class TwigModelAccess extends PhpModelAccess
{
private static TwigModelAccess instance = null;
private List<Template> templates = new ArrayList<Template>();
private LRUCache tagCache = new LRUCache();
private TwigModelAccess()
{
}
public static TwigModelAccess getDefault()
{
if (instance == null) {
instance = new TwigModelAccess();
}
return instance;
}
public Template getTemplate(ISourceModule sourceModule)
{
for (Template template : templates) {
if (template.getSourceModule().equals(sourceModule))
return template;
}
return null;
}
public void addTemplate(Template twigTemplate)
{
if (templates.contains(twigTemplate))
templates.remove(twigTemplate);
templates.add(twigTemplate);
}
/**
*
* Get all Functions defined in the {@link IScriptProject}.
*
*
* @param scriptProject
* @return
*/
public Function[] getFunctions(IScriptProject scriptProject)
{
IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject);
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final JSONParser parser = new JSONParser();
final List<Function> functions = new ArrayList<Function>();
engine.search(ITwigModelElement.FUNCTION, null, null, 0, 0, 100,
SearchFor.REFERENCES, MatchRule.PREFIX, scope,
new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
Function function = new Function((ModelElement) sourceModule, elementName);
if (metadata != null) {
JSONObject mdata = (JSONObject) parser
.parse(new StringReader(metadata));
if (mdata != null && mdata.size() > 0) {
function.setPhpClass((String) mdata
.get(TwigType.PHPCLASS));
function.setInternalFunction((String) mdata.get(TwigType.INTERNAL));
}
}
functions.add(function);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
return (Function[]) functions.toArray(new Function[functions.size()]);
}
/**
*
* Get all Filters defined in the {@link IScriptProject}.
*
*
* @param scriptProject
* @return
*/
public Filter[] getFilters(IScriptProject scriptProject)
{
IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject);
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final JSONParser parser = new JSONParser();
final List<Filter> filters = new ArrayList<Filter>();
engine.search(ITwigModelElement.FILTER, null, null, 0, 0, 100,
SearchFor.REFERENCES, MatchRule.PREFIX, scope,
new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
Filter filter = new Filter((ModelElement) sourceModule, elementName);
if (metadata != null) {
JSONObject mdata = (JSONObject) parser
.parse(new StringReader(metadata));
filter.setMetadata(mdata);
}
filters.add(filter);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
return (Filter[]) filters.toArray(new Filter[filters.size()]);
}
/**
*
* Check for a valid startTag in the given {@link IScriptProject}.
*
*
*
* @param scriptProject
* @param text
* @return
*/
public boolean isStartTag(IScriptProject scriptProject, String text)
{
return isTag(scriptProject, text, ITwigModelElement.START_TAG);
}
/**
*
* Check for a valid endTag in the {@link IScriptProject}.
*
* @param scriptProject
* @param text
* @return
*/
public boolean isEndTag(IScriptProject scriptProject, String text)
{
return isTag(scriptProject, text, ITwigModelElement.END_TAG);
}
/**
* Check if a given tag has a corresponding end tag.
*
* @param scriptProject
* @param text
* @return
*/
public boolean hasEndTag(IScriptProject scriptProject, String text)
{
IDLTKSearchScope scope = null;
int type = ITwigModelElement.START_TAG;
if (scriptProject != null)
scope = SearchEngine.createSearchScope(scriptProject);
else
SearchEngine.createWorkspaceScope(PHPLanguageToolkit.getDefault());
if (scope == null)
return false;
String cacheKey = scriptProject.getElementName() + text + type;
if (tagCache.get(cacheKey) != null) {
return true;
}
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final JSONParser parser = new JSONParser();
final List<String> tags = new ArrayList<String>();
engine.search(type, null, text, 0, 0, 1, SearchFor.REFERENCES,
MatchRule.EXACT, scope, new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
JSONObject data = (JSONObject) parser
.parse(new StringReader(metadata));
boolean hasEnd = (Boolean) data
.get(TwigType.IS_OPEN_CLOSE);
if (hasEnd == true)
tags.add(elementName);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
if (tags.size() == 1) {
String tagName = tags.get(0);
cacheKey = scriptProject.getElementName() + tagName;
tagCache.put(cacheKey, text);
return true;
}
return false;
}
/**
*
* Check if the given tag is valid for the {@link IScriptProject}.
*
*
* @param scriptProject
* @param text
* @param type
* @return
*/
private boolean isTag(IScriptProject scriptProject, String text, int type)
{
IDLTKSearchScope scope = null;
if (scriptProject != null)
scope = SearchEngine.createSearchScope(scriptProject);
else
scope = SearchEngine.createWorkspaceScope(PHPLanguageToolkit
.getDefault());
if (scope == null)
return false;
String cacheKey = scriptProject.getElementName() + text + type;
if (tagCache.get(cacheKey) != null) {
String cached = (String) tagCache.get(cacheKey);
return cached == null || cached.length() == 0;
}
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final List<String> tags = new ArrayList<String>();
engine.search(type, null, text, 0, 0, 1, SearchFor.REFERENCES,
MatchRule.EXACT, scope, new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
tags.add(elementName);
}
}, null);
if (tags.size() == 1) {
String tagName = tags.get(0);
cacheKey = scriptProject.getElementName() + tagName;
tagCache.put(cacheKey, text);
return true;
}
tagCache.put(cacheKey, "");
return false;
}
public boolean isTwigTag(IScriptProject scriptProject, String nodeName)
{
boolean isTag = isStartTag(scriptProject, nodeName);
if (isTag == true)
return true;
return isEndTag(scriptProject, nodeName);
}
public void clearTagCache()
{
tagCache.flush();
}
public void clearCache()
{
clearTagCache();
}
/**
*
*
*
*
* @param scriptProject
* @return
*/
public Tag[] findTags(IScriptProject scriptProject)
{
IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject);
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final List<Tag> tags = new ArrayList<Tag>();
final JSONParser parser = new JSONParser();
engine.search(ITwigModelElement.START_TAG, null, null, 0, 0, 200,
SearchFor.REFERENCES, MatchRule.PREFIX, scope,
new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
Tag tag = new Tag(elementName);
if (metadata != null) {
JSONObject data = (JSONObject) parser
.parse(new StringReader(metadata));
if (data.size() > 0)
tag.setPhpClass((String) data
.get(TwigType.PHPCLASS));
if (data.size() > 1)
tag.setDescription((String) data
.get(TwigType.DOC));
}
tags.add(tag);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
engine.search(ITwigModelElement.END_TAG, null, null, 0, 0, 200,
SearchFor.REFERENCES, MatchRule.PREFIX, scope,
new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
Tag tag = new Tag(elementName);
if (metadata != null) {
JSONObject data = (JSONObject) parser
.parse(new StringReader(metadata));
if (data.size() > 0)
tag.setPhpClass((String) data
.get(TwigType.PHPCLASS));
if (data.size() > 1)
tag.setDescription((String) data
.get(TwigType.DOC));
}
tags.add(tag);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
return (Tag[]) tags.toArray(new Tag[tags.size()]);
}
public Test[] getTests(IScriptProject scriptProject)
{
IDLTKSearchScope scope = SearchEngine.createSearchScope(scriptProject);
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit
.getDefault());
final JSONParser parser = new JSONParser();
final List<Test> tests = new ArrayList<Test>();
engine.search(ITwigModelElement.TEST, null, null, 0, 0, 100,
SearchFor.REFERENCES, MatchRule.PREFIX, scope,
new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset,
int length, int nameOffset, int nameLength,
String elementName, String metadata, String doc,
String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
try {
Test test = new Test(elementName);
if (metadata != null) {
JSONObject mdata = (JSONObject) parser
.parse(new StringReader(metadata));
test.setMetadata(mdata);
}
tests.add(test);
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
return (Test[]) tests.toArray(new Test[tests.size()]);
}
public String getParentPath(TwigModuleDeclaration child, IScriptProject project)
{
BlockStatement statement = child.getExtends();
if (statement == null) {
return null;
}
StringLiteral name = (StringLiteral) statement.getFirstChild();
if (name == null) {
return null;
}
return name.getValue();
}
public TwigModuleDeclaration getParent(TwigModuleDeclaration child, IScriptProject project)
{
TwigModuleDeclaration parent = null;
String path = getParentPath(child, project);
for (ITemplateResolver resolver : ExtensionManager.getInstance().getTemplateProviders()) {
SourceModule module = resolver.revolePath(path, project);
if (module != null) {
try {
parent = (TwigModuleDeclaration) SourceParserUtil.parseSourceModule(module);
} catch (ModelException e) {
Logger.logException(e);
} catch (IOException e) {
Logger.logException(e);
}
if (parent != null) {
return parent;
}
}
}
return parent;
}
/**
* @param sourceModule
* @param scriptProject
* @return
*/
public List<BlockName> findBlocks(SourceModule sourceModule,
IScriptProject scriptProject)
{
IDLTKSearchScope scope = SearchEngine.createSearchScope(sourceModule);
ISearchEngine engine = ModelAccess.getSearchEngine(PHPLanguageToolkit.getDefault());
final List<BlockName> blocks = new ArrayList<BlockName>();
ISearchRequestor requestor = new ISearchRequestor()
{
@Override
public void match(int elementType, int flags, int offset, int length,
int nameOffset, int nameLength, String elementName,
String metadata, String doc, String qualifier, String parent,
ISourceModule sourceModule, boolean isReference)
{
BlockName blockName = new BlockName(sourceModule, elementName, offset, offset+length, offset, offset+length, "block");
blocks.add(blockName);
}
};
if (scope == null || scope.getLanguageToolkit() == null) {
return null;
}
engine.search(ITwigModelElement.BLOCK, null, null, 0, 0, 200, SearchFor.REFERENCES, null, scope, requestor, null);
return blocks;
}
}