blob: d25596a13f2a79c260fdc63b1cd5f955aa5caa31 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
package com.jetbrains.python.debugger;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PyDebugSupportUtils {
private PyDebugSupportUtils() {
}
// can expression be evaluated, or should be executed
public static boolean isExpression(final Project project, final String expression) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
final PsiFile file = PyElementGenerator.getInstance(project).createDummyFile(LanguageLevel.getDefault(), expression);
return file.getFirstChild() instanceof PyExpressionStatement && file.getFirstChild() == file.getLastChild();
}
});
}
@Nullable
public static TextRange getExpressionRangeAtOffset(final Project project, final Document document, final int offset) {
return ApplicationManager.getApplication().runReadAction(new Computable<TextRange>() {
@Nullable
public TextRange compute() {
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (psiFile != null) {
PsiElement element = psiFile.findElementAt(offset);
if (!(element instanceof PyExpression) || element instanceof PyLiteralExpression) {
element = PsiTreeUtil.getParentOfType(element, PyExpression.class);
}
if (element != null && element instanceof PyLiteralExpression) {
return null;
}
if (element != null && isSimpleEnough(element) && isExpression(project, document.getText(element.getTextRange()))) {
return element.getTextRange();
}
}
return null;
}
});
}
// is expression suitable to quick evaluate/display tooltip
private static boolean isSimpleEnough(final PsiElement element) {
return element instanceof PyLiteralExpression ||
element instanceof PyQualifiedExpression ||
element instanceof PyBinaryExpression ||
element instanceof PyPrefixExpression ||
element instanceof PySliceExpression ||
element instanceof PyNamedParameter;
}
// is expression a variable reference and can be evaluated
// todo: use patterns (?)
public static boolean canSaveToTemp(final Project project, final String expression) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
final PsiFile file = PyElementGenerator.getInstance(project).createDummyFile(LanguageLevel.getDefault(), expression);
final PsiElement root = file.getFirstChild();
return !isVariable(root) && (root instanceof PyExpressionStatement);
}
});
}
private static Boolean isVariable(PsiElement root) {
return root instanceof PyExpressionStatement &&
root.getFirstChild() instanceof PyReferenceExpression &&
root.getFirstChild() == root.getLastChild() &&
root.getFirstChild().getFirstChild() != null &&
root.getFirstChild().getFirstChild().getNode().getElementType() == PyTokenTypes.IDENTIFIER &&
root.getFirstChild().getFirstChild() == root.getFirstChild().getLastChild() &&
root.getFirstChild().getFirstChild().getFirstChild() == null;
}
@Nullable
private static String getLineText(@NotNull Document document, int line) {
if (line > 0 && line < document.getLineCount()) {
return document.getText(TextRange.create(document.getLineStartOffset(line), document.getLineEndOffset(line)));
}
return null;
}
public static boolean isContinuationLine(@NotNull Document document, int line) {
String text = getLineText(document, line);
if (text != null && text.trim().endsWith("\\")) {
return true;
}
return false;
}
}