/*
* TextEditingTargetScopeHelper.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 org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.regex.Match;
import org.rstudio.core.client.regex.Pattern;
import org.rstudio.core.client.regex.Pattern.ReplaceOperation;
import org.rstudio.studio.client.workbench.views.source.editors.text.ScopeList.ScopePredicate;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Position;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Range;
public class TextEditingTargetScopeHelper
{
public TextEditingTargetScopeHelper(DocDisplay docDisplay)
{
docDisplay_ = docDisplay;
}
public Scope getCurrentSweaveChunk()
{
return getCurrentSweaveChunk(null);
}
public Scope getCurrentSweaveChunk(Position position)
{
if (position != null)
return docDisplay_.getCurrentChunk(position);
else
return docDisplay_.getCurrentChunk();
}
private class SweaveIncludeContext
{
private SweaveIncludeContext()
{
scopeList_ = new ScopeList(docDisplay_);
scopeList_.selectAll(ScopeList.CHUNK);
}
public String getSweaveChunkText(final Scope chunk, Range range)
{
String text = docDisplay_.getCode(range.getStart(), range.getEnd());
return Pattern.create("^<<(.*?)>>.*").replaceAll(text, new ReplaceOperation()
{
@Override
public String replace(Match m)
{
String label = m.getGroup(1).trim();
Scope included = getScopeByChunkLabel(label,
chunk.getPreamble());
if (included == null)
return m.getValue();
else
return getSweaveChunkText(included,
getSweaveChunkInnerRange(included));
}
});
}
private Scope getScopeByChunkLabel(String label, Position beforeHere)
{
for (Scope s : scopeList_)
{
if (beforeHere != null
&& s.getPreamble().isAfterOrEqualTo(beforeHere))
return null;
if (StringUtil.notNull(s.getChunkLabel()).equals(label))
return s;
}
return null;
}
private final ScopeList scopeList_;
}
public String getSweaveChunkText(Scope chunk)
{
return getSweaveChunkText(chunk, null);
}
public String getSweaveChunkText(Scope chunk, Range range)
{
if (range == null)
range = getSweaveChunkInnerRange(chunk);
assert chunk.getPreamble().isBeforeOrEqualTo(range.getStart())
&& chunk.getEnd().isAfterOrEqualTo(range.getEnd());
return new SweaveIncludeContext().getSweaveChunkText(chunk, range);
}
public Range getSweaveChunkInnerRange(Scope chunk)
{
if (chunk == null)
return null;
assert chunk.isChunk();
Position start = Position.create(chunk.getPreamble().getRow() + 1, 0);
Position end = Position.create(chunk.getEnd().getRow(), 0);
if (start.getRow() != end.getRow())
{
end = Position.create(end.getRow()-1,
docDisplay_.getLine(end.getRow()-1).length());
}
return Range.fromPoints(start, end);
}
public Scope[] getPreviousSweaveChunks()
{
return getSweaveChunks(null, PREVIOUS_CHUNKS);
}
public Scope[] getSweaveChunks(Position startPosition,
final int which)
{
// provide default position based on selection if necessary
final Position position = startPosition != null ?
startPosition :
docDisplay_.getSelectionStart();
ScopeList scopeList = new ScopeList(docDisplay_);
scopeList.selectAll(ScopeList.CHUNK);
scopeList.selectAll(new ScopePredicate() {
@Override
public boolean test(Scope scope)
{
if (!scope.isChunk())
return false;
int dir = scope.getEnd().compareTo(position);
if (which == PREVIOUS_CHUNKS)
return dir < 0;
else
return dir > 0;
}
});
return scopeList.getScopes();
}
public Scope getNextSweaveChunk()
{
ScopeList scopeList = new ScopeList(docDisplay_);
scopeList.selectAll(ScopeList.CHUNK);
final Position selectionEnd = docDisplay_.getSelectionEnd();
return scopeList.findFirst(new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.getPreamble().compareTo(selectionEnd) > 0;
}
});
}
public Scope getNextFunction(final Position position)
{
ScopeList scopeList = new ScopeList(docDisplay_);
scopeList.selectAll(ScopeList.FUNC);
return scopeList.findFirst(new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.getPreamble().compareTo(position) > 0;
}
});
}
public Scope getPreviousFunction(final Position position)
{
ScopeList scopeList = new ScopeList(docDisplay_);
scopeList.selectAll(ScopeList.FUNC);
return scopeList.findLast(new ScopePredicate()
{
@Override
public boolean test(Scope scope)
{
return scope.getPreamble().compareTo(position) < 0;
}
});
}
public final static int PREVIOUS_CHUNKS = 0;
public final static int FOLLOWING_CHUNKS = 1;
private DocDisplay docDisplay_;
}