blob: 21a9bad4d6f72f5d7a59e6fecef135c2dd477a1e [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2015, 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.r.ui.sourceediting;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.IDebugTarget;
import org.eclipse.debug.core.model.IStackFrame;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.ltk.model.core.elements.IModelElement;
import org.eclipse.statet.r.console.core.RProcess;
import org.eclipse.statet.r.console.core.RProcessREnvironment;
import org.eclipse.statet.r.console.core.RWorkspace;
import org.eclipse.statet.r.core.RProject;
import org.eclipse.statet.r.core.RProjects;
import org.eclipse.statet.r.core.data.CombinedRElement;
import org.eclipse.statet.r.core.model.IRFrame;
import org.eclipse.statet.r.core.model.IRFrameInSource;
import org.eclipse.statet.r.core.model.IRModelInfo;
import org.eclipse.statet.r.core.model.IRSourceUnit;
import org.eclipse.statet.r.core.model.IRWorkspaceSourceUnit;
import org.eclipse.statet.r.core.model.RElementName;
import org.eclipse.statet.r.core.model.RModel;
import org.eclipse.statet.r.core.rsource.ast.RAstNode;
import org.eclipse.statet.r.ui.RUI;
public final class RFrameSearchPath implements Iterable<IRFrame> {
public static final int WORKSPACE_MODE= 1;
public static final int CONSOLE_MODE= 2;
public static final int ENGINE_MODE= 3;
private static final int LOCAL_ID= 0;
private static final int WORKSPACE_ID= 1;
private static final int RUNTIME_ID= 2;
public class RFrameIterator implements Iterator<IRFrame> {
private int listIter0;
private int listIter1= -1;
private IRFrame next;
@Override
public boolean hasNext() {
if (this.next != null) {
return true;
}
ITER_0 : while (this.listIter0 < RFrameSearchPath.this.frames.length) {
if (++this.listIter1 < RFrameSearchPath.this.frames[this.listIter0].size()) {
this.next= RFrameSearchPath.this.frames[this.listIter0].get(this.listIter1);
return true;
}
else {
this.listIter0++;
this.listIter1= -1;
continue ITER_0;
}
}
return false;
}
@Override
public IRFrame next() {
if (hasNext()) {
final IRFrame frame= this.next;
this.next= null;
return frame;
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
public int getEnvirGroup() {
return this.listIter0;
}
public int getRelevance() {
switch (getEnvirGroup()) {
case LOCAL_ID:
return Math.max(9 - this.listIter1, 3);
case WORKSPACE_ID:
return 1;
default:
return -5;
}
}
}
private final List<IRFrame>[] frames= new List[3];
private RElementName expliciteScope;
private boolean packageMode;
private Set<String> importedPackages;
private final Set<String> workspacePackages= new HashSet<>();
private RWorkspace runtimeWorkspace;
public RFrameSearchPath() {
this.frames[RUNTIME_ID]= new ArrayList<>();
}
public void init(final RAssistInvocationContext context, final RAstNode node,
final int mode, final RElementName expliciteScope) {
this.expliciteScope= (expliciteScope != null && RElementName.isPackageFacetScopeType(expliciteScope.getType())) ?
expliciteScope : null;
final IRFrameInSource envir= RModel.searchFrame(node);
if (envir != null && mode <= CONSOLE_MODE) {
this.frames[LOCAL_ID]= RModel.createDirectFrameList(envir, this.expliciteScope);
}
else {
this.frames[LOCAL_ID]= new ArrayList<>();
}
if (mode == WORKSPACE_MODE) {
final IRSourceUnit su= context.getSourceUnit();
if (su != null) {
if (this.expliciteScope == null && su instanceof IRWorkspaceSourceUnit) {
final RProject rProject= RProjects.getRProject(((IRWorkspaceSourceUnit) su)
.getResource().getProject() );
this.packageMode= (rProject != null && rProject.getPkgName() != null);
}
this.importedPackages= (this.expliciteScope != null) ?
ImCollections.newSet(this.expliciteScope.getSegmentName()) :
RModel.createImportedPackageList((IRModelInfo) context.getModelInfo());
try {
this.frames[WORKSPACE_ID]= RModel.createProjectFrameList(null,
su,
true, (this.expliciteScope == null),
this.importedPackages, this.workspacePackages );
}
catch (final CoreException e) {
// CANCELLED possible?
}
if (this.frames[WORKSPACE_ID] != null && !this.frames[WORKSPACE_ID].isEmpty()) {
this.frames[LOCAL_ID].add(this.frames[WORKSPACE_ID].remove(0));
}
}
}
if (this.frames[WORKSPACE_ID] == null) {
this.frames[WORKSPACE_ID]= new ArrayList<>();
}
this.runtimeWorkspace= getRuntimeWorkspace(context);
addRuntimeFrames(context, mode >= CONSOLE_MODE);
}
private RWorkspace getRuntimeWorkspace(final RAssistInvocationContext context) {
final RProcess tool= context.getTool();
return (tool != null) ? tool.getWorkspaceData() : null;
}
private void addRuntimeFrames(final RAssistInvocationContext context,
final boolean complete) {
if (this.runtimeWorkspace != null && this.runtimeWorkspace.hasRObjectDB()) {
if (complete) {
if (this.expliciteScope != null) {
final IRFrame frame= resolve(this.expliciteScope, context);
this.frames[WORKSPACE_ID].add(frame);
return;
}
addDebugFrame(context);
final List<? extends RProcessREnvironment> searchEnvs= this.runtimeWorkspace
.getRSearchEnvironments();
if (searchEnvs != null && !searchEnvs.isEmpty()) {
for (final RProcessREnvironment env : searchEnvs) {
final IRFrame frame= (IRFrame) env;
if (frame.getFrameType() == IRFrame.PROJECT) {
this.frames[LOCAL_ID].add(frame);
}
else {
this.frames[WORKSPACE_ID].add(frame);
}
}
}
}
else if (this.importedPackages != null) {
if (this.expliciteScope != null
&& !this.workspacePackages.contains(
this.expliciteScope.getSegmentName() )) {
final IRFrame frame= resolve(this.expliciteScope, context);
if (frame != null) {
this.frames[RUNTIME_ID].add(frame);
}
}
else if (this.packageMode) {
final List<? extends RProcessREnvironment> searchEnvs=
this.runtimeWorkspace.getRSearchEnvironments();
for (final String pkgName : this.importedPackages) {
if (!this.workspacePackages.contains(pkgName)) {
IRFrame frame;
frame= resolve(RElementName.create(RElementName.SCOPE_NS, pkgName),
context );
if (frame == null) { // timeout
frame= searchPackage(searchEnvs, pkgName);
}
if (frame != null) {
this.frames[RUNTIME_ID].add(frame);
}
}
}
}
else {
final List<? extends RProcessREnvironment> searchEnvs=
this.runtimeWorkspace.getRSearchEnvironments();
for (final String pkgName : this.importedPackages) {
if (!this.workspacePackages.contains(pkgName)) {
IRFrame frame;
frame= searchPackage(searchEnvs, pkgName);
if (frame == null) {
frame= resolve(RElementName.create(RElementName.SCOPE_NS, pkgName),
context );
}
if (frame != null) {
this.frames[RUNTIME_ID].add(frame);
}
}
}
}
}
}
}
private IRFrame searchPackage(final List<? extends RProcessREnvironment> searchEnvs,
final String pkgName) {
if (searchEnvs != null) {
for (final RProcessREnvironment env : searchEnvs) {
final IRFrame frame= (IRFrame) env;
if (frame.getFrameType() == IRFrame.PACKAGE
&& frame.getElementName().getSegmentName().equals(pkgName) ) {
return frame;
}
}
}
return null;
}
private IRFrame resolve(final RElementName name,
final RAssistInvocationContext context) {
CombinedRElement element= this.runtimeWorkspace.resolve(name,
RWorkspace.RESOLVE_INDICATE_NA );
if (element != null) {
return (!this.runtimeWorkspace.isNA(element)
&& element instanceof IRFrame) ?
(IRFrame) element : null;
}
element= context.getToolReferencesUtil().resolve(name, 0);
return (element instanceof IRFrame) ?
(IRFrame) element : null;
}
private void addDebugFrame(final RAssistInvocationContext context) {
final IDebugTarget debugTarget= context.getTool().getLaunch().getDebugTarget();
if (debugTarget == null) {
return;
}
try {
final IThread[] threads= debugTarget.getThreads();
if (threads.length > 0) {
final IStackFrame top= threads[0].getTopStackFrame();
if (top != null) {
final CombinedRElement envir= (CombinedRElement) top.getAdapter(IModelElement.class);
if (envir instanceof IRFrame) {
final IRFrame frame= (IRFrame) envir;
if (frame.getFrameType() != IRFrame.PACKAGE) {
this.frames[LOCAL_ID].add(frame);
}
}
}
}
}
catch (final DebugException e) {
if (e.getStatus().getCode() == DebugException.NOT_SUPPORTED
|| e.getStatus().getSeverity() == IStatus.CANCEL) {
return;
}
StatusManager.getManager().handle(new Status(IStatus.ERROR, RUI.BUNDLE_ID, -1,
"An error occurred when collecting environments for content assist.",
e ));
}
}
@Override
public RFrameIterator iterator() {
return new RFrameIterator();
}
// public RFrameIterator iterator(final RElementName name) {
// if (name == null) {
// return new RFrameIterator();
// }
// if (name.getType() == RElementName.SCOPE_NS_INT) {
// this.runtimeWorkspace.getProcess().getQueue().add
// }
// }
public void clear() {
this.frames[LOCAL_ID]= null;
this.frames[WORKSPACE_ID]= null;
this.frames[RUNTIME_ID].clear();
this.expliciteScope= null;
this.importedPackages= null;
this.workspacePackages.clear();
this.runtimeWorkspace= null;
}
}