Package org.jetbrains.plugins.clojure.debugger

Source Code of org.jetbrains.plugins.clojure.debugger.ClojurePositionManager

package org.jetbrains.plugins.clojure.debugger;

import com.intellij.debugger.NoDataException;
import com.intellij.debugger.PositionManager;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.CompoundPositionManager;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import com.intellij.util.Query;
import com.intellij.util.containers.HashSet;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.request.ClassPrepareRequest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.clojure.ClojureLanguage;
import org.jetbrains.plugins.clojure.psi.api.ClList;
import org.jetbrains.plugins.clojure.psi.api.ClojureFile;
import org.jetbrains.plugins.clojure.psi.api.defs.ClDef;
import org.jetbrains.plugins.clojure.psi.api.ns.ClNs;
import org.jetbrains.plugins.clojure.psi.api.symbols.ClSymbol;
import org.jetbrains.plugins.clojure.psi.stubs.ClojureShortNamesCache;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* Created by IntelliJ IDEA.
* User: peter
* Date: Jan 16, 2009
* Time: 4:17:46 PM
* Copyright 2007, 2008, 2009 Red Shark Technology
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class ClojurePositionManager implements PositionManager {
  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.PositionManagerImpl");

  private final DebugProcess myDebugProcess;

  public ClojurePositionManager(DebugProcess debugProcess) {
    myDebugProcess = debugProcess;
  }

  public DebugProcess getDebugProcess() {
    return myDebugProcess;
  }

  @NotNull
  public List<Location> locationsOfLine(ReferenceType type, SourcePosition position) throws NoDataException {
    try {
        int line = position.getLine() + 1;
      List<Location> locations = getDebugProcess().getVirtualMachineProxy().versionHigher("1.4")
          ? type.locationsOfLine(DebugProcessImpl.JAVA_STRATUM, null, line)
          : type.locationsOfLine(line);
      if (locations == null || locations.isEmpty()) throw new NoDataException();
      return locations;
    }
    catch (AbsentInformationException e) {
      throw new NoDataException();
    }
  }

  public ClassPrepareRequest createPrepareRequest(final ClassPrepareRequestor requestor, final SourcePosition position)
      throws NoDataException {
    final PsiFile file = position.getFile();
    if (!(file instanceof ClojureFile)) throw new NoDataException();

    final String query = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
      public String compute() {
        final ClojureFile clojureFile = (ClojureFile) file;
        PsiElement element = clojureFile.findElementAt(position.getOffset());

        String nsName = getNameSpaceName(element);
        final String nsPrefix = nsName != null ? nsName + "$" : "user$";

        final ClDef def = PsiTreeUtil.getParentOfType(element, ClDef.class);
        final String name = def == null ? null : def.getName();

        return (nsPrefix + (name != null ? name : "")).replace('-', '_') + "*";
      }
    });

    ClassPrepareRequestor waitRequestor = new MyClassPrepareRequestor(position, requestor);
    final ClassPrepareRequest prepareRequest = myDebugProcess.getRequestsManager().createClassPrepareRequest(waitRequestor, query);
    prepareRequest.addSourceNameFilter(file.getName());
    return prepareRequest;
  }

  private String getNameSpaceName(final PsiElement _element) {
    final Ref<String> stringRef = new Ref<String>(null);
    ApplicationManager.getApplication().runReadAction(new Runnable() {
      public void run() {
        PsiElement element = _element;
        while (!(element.getParent() instanceof ClojureFile)) {
          element = element.getParent();
        }
        final PsiElement parent = element.getParent();
        if (parent instanceof ClojureFile) {
          while (element != null) {
            if (element instanceof ClList) {
              ClList list = (ClList) element;
              final ClSymbol first = list.getFirstSymbol();
              if (first != null && first.getText().equals("ns")) {
                final ClSymbol snd = PsiTreeUtil.getNextSiblingOfType(first, ClSymbol.class);
                if (snd != null) {
                  stringRef.set(snd.getText());
                  return;
                }
              }
            }
            element = element.getPrevSibling();
          }
        }
      }
    });
    return stringRef.get();
  }

  @NotNull
  public List<ReferenceType> getAllClasses(final SourcePosition position) throws NoDataException {
    PsiFile file = position.getFile();
    if (!(file instanceof ClojureFile)) throw new NoDataException();
    final List<ReferenceType> list = myDebugProcess.getVirtualMachineProxy().allClasses();
    final ArrayList<ReferenceType> result = new ArrayList<ReferenceType>();
    final String fileName = position.getFile().getName();
    for (ReferenceType type : list) {
      try {
        final String name = type.sourceName();
        if (fileName.equals(name)) {
          result.add(type);
        }
      } catch (AbsentInformationException e) {
        //do nothing
      }
    }
    return result;
  }


  public SourcePosition getSourcePosition(final Location location) throws NoDataException {
    if (location == null) throw new NoDataException();

    PsiFile psiFile = getPsiFileByLocation(getDebugProcess().getProject(), location);
    if (!(psiFile instanceof ClojureFile)) throw new NoDataException();

    int lineNumber = location.lineNumber();
    if (lineNumber < 1) throw new NoDataException();
    return SourcePosition.createFromLine(psiFile, lineNumber - 1);
  }

  @Nullable
  private PsiFile getPsiFileByLocation(final Project project, final Location location) {
    final Ref<PsiFile> result = new Ref<PsiFile>(null);
    ApplicationManager.getApplication().runReadAction(new Runnable() {
      public void run() {
        if (location == null) return;
        final ReferenceType refType = location.declaringType();
        if (refType == null) return;

        String fileName = null;
        try {
          fileName = location.sourceName();
        } catch (AbsentInformationException ignore) {}

        final String originalQName = refType.name().replace('/', '.');
        final GlobalSearchScope searchScope = myDebugProcess.getSearchScope();
        int dollar = originalQName.indexOf('$');
        final String qName = dollar >= 0 ? originalQName.substring(0, dollar) : originalQName;
        final ClNs[] nses = ClojureShortNamesCache.getInstance(project).getNsByQualifiedName(qName, searchScope);
        if (nses.length == 1) {
          final PsiFile containingFile = nses[0].getContainingFile();
          if (fileName == null || containingFile.getName().equals(fileName)) {
            result.set(containingFile);
            return;
          }
        }


        DirectoryIndex directoryIndex = DirectoryIndex.getInstance(project);
        int dotIndex = qName.lastIndexOf(".");
        String packageName = dotIndex >= 0 ? qName.substring(0, dotIndex) : "";
        Query<VirtualFile> query = directoryIndex.getDirectoriesByPackageName(packageName, true);
        if (fileName == null) {
          fileName = dotIndex >= 0 ? qName.substring(dotIndex + 1) : qName;
          fileName += ".clj";
        }


        final String finalFileName = fileName;
        query.forEach(new Processor<VirtualFile>() {
          public boolean process(VirtualFile vDir) {
            VirtualFile vFile = vDir.findChild(finalFileName);
            if (vFile != null) {
              PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
              if (psiFile instanceof ClojureFile) {
                result.set(psiFile);
                return false;
              }
            }
            return true;
          }
        });
      }
    });

    return result.get();
  }

  private static class MyClassPrepareRequestor implements ClassPrepareRequestor {
    private final SourcePosition position;
    private final ClassPrepareRequestor requestor;

    public MyClassPrepareRequestor(SourcePosition position, ClassPrepareRequestor requestor) {
      this.position = position;
      this.requestor = requestor;
    }

    public void processClassPrepare(DebugProcess debuggerProcess, ReferenceType referenceType) {
      final CompoundPositionManager positionManager = ((DebugProcessImpl) debuggerProcess).getPositionManager();
      if (positionManager.locationsOfLine(referenceType, position).size() > 0) {
        requestor.processClassPrepare(debuggerProcess, referenceType);
      } else {
        final List<ReferenceType> positionClasses = positionManager.getAllClasses(position);
        if (positionClasses.contains(referenceType)) {
          requestor.processClassPrepare(debuggerProcess, referenceType);
        }
      }
    }
  }

}
TOP

Related Classes of org.jetbrains.plugins.clojure.debugger.ClojurePositionManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.