/*=============================================================================# # Copyright (c) 2014-2016 Stephan Wahlbrink (WalWare.de) and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html # # Contributors: # Stephan Wahlbrink - initial API and implementation #=============================================================================*/ package de.walware.statet.r.internal.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.jface.text.IRegion; import de.walware.ecommons.ltk.core.SourceContent; import de.walware.ecommons.ltk.core.model.ISourceUnit; import de.walware.ecommons.text.core.ILineInformation; import de.walware.ecommons.workbench.search.ui.LineElement; import de.walware.statet.r.core.IRProject; import de.walware.statet.r.core.model.IRFrame; import de.walware.statet.r.core.model.IRFrameInSource; import de.walware.statet.r.core.model.IRModelInfo; import de.walware.statet.r.core.model.IRModelManager; import de.walware.statet.r.core.model.IRSourceUnit; import de.walware.statet.r.core.model.RElementAccess; import de.walware.statet.r.core.model.RElementName; import de.walware.statet.r.core.model.RModel; import de.walware.statet.r.core.refactoring.RElementSearchProcessor; import de.walware.statet.r.core.rsource.ast.RAst; import de.walware.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 IRSourceUnit 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 IRProject project, final List<ISourceUnit> sus, final SubMonitor progress) throws BadLocationException { if (sus != null) { int remaining= sus.size(); for (final ISourceUnit su : sus) { progress.setWorkRemaining(remaining--); process((IRSourceUnit) su, progress.newChild(1)); } } } protected void process(final IRSourceUnit sourceUnit, final SubMonitor progress) throws BadLocationException { progress.setWorkRemaining(10); sourceUnit.connect(progress.newChild(1)); try { IRSourceUnit bestUnit= sourceUnit; if (bestUnit.getUnderlyingUnit() != null && bestUnit.isSynchronized()) { bestUnit= sourceUnit; } final IRModelInfo modelInfo= (IRModelInfo) sourceUnit.getModelInfo(RModel.R_TYPE_ID, IRModelManager.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 IRFrame frame; if (frameId == null) { frame= modelInfo.getTopFrame(); } else { frame= modelInfo.getReferencedFrames().get(frameId); } if (frame instanceof IRFrameInSource) { final List<? extends RElementAccess> allAccess= ((IRFrameInSource) frame).getAllAccessOf( this.mainName.getSegmentName(), true ); if (allAccess != null && allAccess.size() > 0) { allFrameAccess.add(allAccess); } } } final String contentText= content.getText(); final ILineInformation lineInformation= content.getLines(); final Map<Integer, LineElement<IRSourceUnit>> 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 IRegion nameRegion= RAst.getElementNameRegion(nameNode); final Integer lineNumber= Integer.valueOf( lineInformation.getLineOfOffset(nameRegion.getOffset()) ); LineElement<IRSourceUnit> lineElement= lineElements.get(lineNumber); if (lineElement == null) { final int lineOffset= lineInformation.getLineOffset(lineNumber); lineElement= new LineElement<>(bestUnit, lineNumber, lineOffset, getContent(contentText, lineOffset, lineOffset + lineInformation.getLineLength(lineNumber)) ); lineElements.put(lineNumber, lineElement); } this.result.addMatch(new RElementMatch(lineElement, nameRegion.getOffset(), 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(); } }