/*
* ScopeList.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client.workbench.views.source.editors.text;
import com.google.gwt.core.client.JsArray;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.js.JsUtil;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Range;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Represents a flattened list of scopes in the given DocDisplay. It takes a
* snapshot at the time of construction, so don't hold onto a ScopeList whose
* document is changing.
*/
public class ScopeList implements Iterable<Scope>
{
public interface ScopePredicate
{
boolean test(Scope scope);
}
public static class ContainsFoldPredicate implements ScopePredicate
{
public ContainsFoldPredicate(Range range)
{
range_ = range;
}
@Override
public boolean test(Scope scope)
{
return scope.getFoldStart().isBeforeOrEqualTo(range_.getStart()) &&
scope.getEnd().isAfterOrEqualTo(range_.getStart()) &&
scope.getFoldStart().isBeforeOrEqualTo(range_.getEnd()) &&
scope.getEnd().isAfterOrEqualTo(range_.getEnd());
}
private final Range range_;
}
public static final ScopePredicate CHUNK = new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.isChunk();
}
};
public static final ScopePredicate SECT = new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.isSection();
}
};
public static final ScopePredicate FUNC = new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.isBrace() && !StringUtil.isNullOrEmpty(scope.getLabel());
}
};
public static final ScopePredicate ANON_BRACE = new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.isBrace() && StringUtil.isNullOrEmpty(scope.getLabel());
}
};
public ScopeList(DocDisplay docDisplay)
{
addScopes(docDisplay.getScopeTree());
}
@Override
public Iterator<Scope> iterator()
{
return scopes_.iterator();
}
public Scope[] getScopes()
{
return scopes_.toArray(new Scope[scopes_.size()]);
}
public Scope get(int index)
{
return scopes_.get(index);
}
public int size()
{
return scopes_.size();
}
public void removeAll(ScopePredicate shouldRemove)
{
for (int i = 0; i < scopes_.size(); i++)
if (shouldRemove.test(scopes_.get(i)))
scopes_.remove(i--);
}
public void selectAll(ScopePredicate shouldRetain)
{
for (int i = 0; i < scopes_.size(); i++)
if (!shouldRetain.test(scopes_.get(i)))
scopes_.remove(i--);
}
public Scope findFirst(ScopePredicate predicate)
{
for (Scope scope : scopes_)
if (predicate.test(scope))
return scope;
return null;
}
public Scope findLast(ScopePredicate predicate)
{
for (int i = scopes_.size() - 1; i >= 0; i--)
if (predicate.test(scopes_.get(i)))
return scopes_.get(i);
return null;
}
private void addScopes(JsArray<Scope> scopes)
{
for (Scope scope : JsUtil.asIterable(scopes))
{
scopes_.add(scope);
addScopes(scope.getChildren());
}
}
private final ArrayList<Scope> scopes_ = new ArrayList<Scope>();
}