blob: 554aee66c19948b3636a9bdde9e44e924ecdf667 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2014, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.ui.search;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.statet.jcommons.text.core.TextLineInformation;
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.workbench.search.ui.LineElement;
import org.eclipse.statet.ltk.core.SourceContent;
import org.eclipse.statet.ltk.model.core.element.SourceUnit;
import org.eclipse.statet.r.core.RProject;
import org.eclipse.statet.r.core.model.RElementAccess;
import org.eclipse.statet.r.core.model.RElementName;
import org.eclipse.statet.r.core.model.RFrame;
import org.eclipse.statet.r.core.model.RModel;
import org.eclipse.statet.r.core.model.RModelManager;
import org.eclipse.statet.r.core.model.RSourceFrame;
import org.eclipse.statet.r.core.model.RSourceUnit;
import org.eclipse.statet.r.core.model.RSourceUnitModelInfo;
import org.eclipse.statet.r.core.refactoring.RElementSearchProcessor;
import org.eclipse.statet.r.core.rsource.ast.RAsts;
import org.eclipse.statet.r.core.rsource.ast.RAstNode;
public class RElementSearch extends RElementSearchProcessor {
private final boolean searchWrite;
RElementSearchResult result;
private final StringBuilder sb= new StringBuilder();
public RElementSearch(final RElementName name,
final RSourceUnit sourceUnit, final RElementAccess mainAccess,
final Mode mode, final boolean searchWrite) {
super(name, sourceUnit, mainAccess, mode, ALLOW_SUB_NAMEDPART);
this.searchWrite= searchWrite;
}
public final boolean searchWrite() {
return this.searchWrite;
}
@Override
protected void begin(final SubMonitor progress) {
super.begin(progress);
this.result.removeAll();
}
@Override
protected void process(final RProject project, final List<SourceUnit> sus,
final SubMonitor progress) throws BadLocationException {
if (sus != null) {
int remaining= sus.size();
for (final SourceUnit su : sus) {
progress.setWorkRemaining(remaining--);
process((RSourceUnit)su, progress.newChild(1));
}
}
}
protected void process(final RSourceUnit sourceUnit, final SubMonitor progress) throws BadLocationException {
progress.setWorkRemaining(10);
sourceUnit.connect(progress.newChild(1));
try {
RSourceUnit bestUnit= sourceUnit;
if (bestUnit.getUnderlyingUnit() != null && bestUnit.isSynchronized()) {
bestUnit= sourceUnit;
}
final RSourceUnitModelInfo modelInfo= (RSourceUnitModelInfo)sourceUnit.getModelInfo(RModel.R_TYPE_ID,
RModelManager.MODEL_FILE, progress.newChild(1) );
final SourceContent content= sourceUnit.getContent(progress.newChild(1));
final List<List<? extends RElementAccess>> allFrameAccess= new ArrayList<>();
for (final String frameId : this.definitionFrameIds) {
final RFrame frame;
if (frameId == null) {
frame= modelInfo.getTopFrame();
}
else {
frame= modelInfo.getReferencedFrames().get(frameId);
}
if (frame instanceof RSourceFrame) {
final List<? extends RElementAccess> allAccess= ((RSourceFrame)frame).getAllAccessOf(
this.mainName.getSegmentName(), true );
if (allAccess != null && allAccess.size() > 0) {
allFrameAccess.add(allAccess);
}
}
}
final String contentText= content.getText();
final TextLineInformation lineInformation= content.getLines();
final Map<Integer, LineElement<RSourceUnit>> lineElements= new HashMap<>();
for (final List<? extends RElementAccess> allAccess : allFrameAccess) {
for (RElementAccess access : allAccess) {
access= include(access);
if (access != null) {
final RAstNode nameNode= access.getNameNode();
final TextRegion nameRegion= RAsts.getElementNameRegion(nameNode);
final Integer lineNumber= Integer.valueOf(
lineInformation.getLineOfOffset(nameRegion.getStartOffset()) );
LineElement<RSourceUnit> lineElement= lineElements.get(lineNumber);
if (lineElement == null) {
final int lineOffset= lineInformation.getStartOffset(lineNumber);
lineElement= new LineElement<>(bestUnit, lineNumber, lineOffset,
getContent(contentText, lineOffset, lineOffset + lineInformation.getLength(lineNumber)) );
lineElements.put(lineNumber, lineElement);
}
this.result.addMatch(new RElementMatch(lineElement,
nameRegion.getStartOffset(), nameRegion.getLength(),
(access.isWriteAccess() && access.getNextSegment() == null) ));
}
}
}
progress.setWorkRemaining(1);
}
finally {
sourceUnit.disconnect(progress.newChild(1));
}
}
private RElementAccess include(RElementAccess access) {
access= searchMatch(access);
return (access != null && access.isMaster()
&& (!searchWrite() || access.isWriteAccess()) ) ?
access : null;
}
private String getContent(final String text, final int start, final int end) {
this.sb.setLength(0);
for (int idx= start; idx < end; idx++) {
final char c= text.charAt(idx);
if (Character.isWhitespace(c) || Character.isISOControl(c)) {
this.sb.append(' ');
} else {
this.sb.append(c);
}
}
return this.sb.toString();
}
}