diff --git a/python/BUILD.bazel b/python/BUILD.bazel index d925c9e099ba..a5217a9f0eed 100644 --- a/python/BUILD.bazel +++ b/python/BUILD.bazel @@ -355,6 +355,7 @@ jvm_library( "//python/python-uv/common", "//python/common", "//python/python-process-output:processOutput", + "//platform/xdebugger-impl/shared", ], exports = [ "//python/openapi:community", diff --git a/python/intellij.python.community.impl.iml b/python/intellij.python.community.impl.iml index 24f92f55a91e..1cb0b2c7a959 100644 --- a/python/intellij.python.community.impl.iml +++ b/python/intellij.python.community.impl.iml @@ -192,5 +192,6 @@ + \ No newline at end of file diff --git a/python/pluginCore/resources/META-INF/plugin.xml b/python/pluginCore/resources/META-INF/plugin.xml index 32fbea020086..012698bf5ceb 100644 --- a/python/pluginCore/resources/META-INF/plugin.xml +++ b/python/pluginCore/resources/META-INF/plugin.xml @@ -21,6 +21,7 @@ The Python plug-in provides smart editing for Python scripts. The feature set of + diff --git a/python/pluginResources/intellij.python.community.impl.xml b/python/pluginResources/intellij.python.community.impl.xml index 621c4f9ebcee..020202b4834d 100644 --- a/python/pluginResources/intellij.python.community.impl.xml +++ b/python/pluginResources/intellij.python.community.impl.xml @@ -195,7 +195,6 @@ - @@ -688,6 +687,9 @@ + + + diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java b/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java deleted file mode 100644 index 060a9eccf432..000000000000 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.java +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 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.TextRange; -import com.intellij.xdebugger.XSourcePosition; -import com.intellij.xdebugger.evaluation.XDebuggerEvaluator; -import com.jetbrains.python.console.PyConsoleIndentUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - - -public class PyDebuggerEvaluator extends XDebuggerEvaluator { - - private final Project myProject; - private final PyFrameAccessor myDebugProcess; - - public PyDebuggerEvaluator(@NotNull Project project, final @NotNull PyFrameAccessor debugProcess) { - myProject = project; - myDebugProcess = debugProcess; - } - - @Override - public void evaluate(@NotNull String expression, @NotNull XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition) { - doEvaluate(expression, callback, true); - } - - private PyDebugValue getNone() { - return new PyDebugValue("", "NoneType", null, "None", false, null, null, false, false, false, null, null, myDebugProcess); - } - - private void doEvaluate(final String expr, final XEvaluationCallback callback, final boolean doTrunc) { - ApplicationManager.getApplication().executeOnPooledThread(() -> { - String expression = expr.trim(); - if (expression.isEmpty()) { - callback.evaluated(getNone()); - return; - } - - final boolean isExpression = PyDebugSupportUtils.isExpression(myProject, expression); - try { - // todo: think on getting results from EXEC - final PyDebugValue value = myDebugProcess.evaluate(expression, !isExpression, doTrunc); - if (value.isErrorOnEval()) { - callback.errorOccurred("{" + value.getType() + "}" + value.getValue()); //NON-NLS - } - else { - callback.evaluated(value); - } - } - catch (PyDebuggerException e) { - callback.errorOccurred(e.getTracebackError()); - } - }); - } - - @Override - public @Nullable TextRange getExpressionRangeAtOffset(final Project project, - final Document document, - final int offset, - boolean sideEffectsAllowed) { - return PyDebugSupportUtils.getExpressionRangeAtOffset(project, document, offset); - } - - @Override - public @NotNull String formatTextForEvaluation(@NotNull String text) { - return PyConsoleIndentUtil.normalize(text); - } -} diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.kt b/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.kt new file mode 100644 index 000000000000..400b1cdbd4f6 --- /dev/null +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerEvaluator.kt @@ -0,0 +1,85 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.debugger + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.editor.Document +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.util.ThrowableComputable +import com.intellij.openapi.util.registry.Registry +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiReference +import com.intellij.xdebugger.XSourcePosition +import com.intellij.xdebugger.evaluation.XDebuggerEvaluator +import com.intellij.xdebugger.impl.evaluate.quick.XDebuggerDocumentOffsetEvaluator +import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType +import com.jetbrains.python.console.PyConsoleIndentUtil +import com.jetbrains.python.psi.PyCallExpression +import com.jetbrains.python.psi.PyExpression + +internal class PyDebuggerEvaluator(private val myProject: Project, private val myDebugProcess: PyFrameAccessor) : XDebuggerEvaluator(), XDebuggerDocumentOffsetEvaluator { + override fun evaluate(expression: String, callback: XEvaluationCallback, expressionPosition: XSourcePosition?): Unit = + doEvaluate(expression, callback, true) + + + private val none: PyDebugValue + get() = PyDebugValue("", "NoneType", null, "None", false, null, null, false, false, false, null, null, myDebugProcess) + + private fun doEvaluate(expr: String, callback: XEvaluationCallback, doTrunc: Boolean) { + ApplicationManager.getApplication().executeOnPooledThread(Runnable { + val expression = expr.trim { it <= ' ' } + if (expression.isEmpty()) { + callback.evaluated(this.none) + return@Runnable + } + + val isExpression = PyDebugSupportUtils.isExpression(myProject, expression) + try { + // todo: think on getting results from EXEC + val value = myDebugProcess.evaluate(expression, !isExpression, doTrunc) + if (value.isErrorOnEval) { + callback.errorOccurred("{" + value.getType() + "}" + value.value) //NON-NLS + } + else { + callback.evaluated(value) + } + } + catch (e: PyDebuggerException) { + callback.errorOccurred(e.getTracebackError()) + } + }) + } + + override fun getExpressionRangeAtOffset(project: Project?, document: Document?, offset: Int, sideEffectsAllowed: Boolean): TextRange? = + PyDebugSupportUtils.getExpressionRangeAtOffset(project, document, offset) + + override fun formatTextForEvaluation(text: String): String = PyConsoleIndentUtil.normalize(text) + + override fun evaluate(document: Document, offset: Int, hintType: ValueHintType, callback: XEvaluationCallback) { + if (!Registry.`is`("python.debugger.show.value.tooltip")) { + callback.errorOccurred("") + return + } + + val ref = ReadAction.compute(ThrowableComputable { + PsiDocumentManager.getInstance(myProject).getPsiFile(document)?.findReferenceAt(offset) + }) + if (ref == null) { + callback.errorOccurred("") + return + } + + val element = ref.getElement() + when(element) { + is PyExpression -> { + if (element.getParent() is PyCallExpression) { + callback.errorOccurred("") + } else { + doEvaluate(element.getText(), callback, false) + } + } + else -> callback.errorOccurred("") + } + } +} \ No newline at end of file