diff --git a/README.md b/README.md index 0d50fc1..8393846 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,12 @@ This is plugin implementation of the following PyCharm [pull request](https://gi JetBrains feature request: https://youtrack.jetbrains.com/issue/PY-38919 +New feature for 0.2.x: + +When editing Python code, execute a top level code block with "Execute cell in console". + +For IDEs with Jupyter notebook support, this executes a cell in the Python console. + +keyboard shortcut: alt shift E. + ![demonstration](demo.gif "demonstration") diff --git a/src/main/java/com/jetbrains/python/actions/PyCellExecuteAction.java b/src/main/java/com/jetbrains/python/actions/PyCellExecuteAction.java index a9a2c52..8778fb4 100644 --- a/src/main/java/com/jetbrains/python/actions/PyCellExecuteAction.java +++ b/src/main/java/com/jetbrains/python/actions/PyCellExecuteAction.java @@ -32,6 +32,76 @@ public class PyCellExecuteAction extends AnAction { + private static boolean inJupyterNotebookMode(final AnActionEvent e, final Editor editor) { + // by checking for `JupyterTokenType.CODE_MARKER` + // but Jupyter is a closed sourced component, to workaround check if it is not `PyElementType` or `PsiWhiteSpace` + final Document document = editor.getDocument(); + final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject()); + psiDocumentManager.commitDocument(document); + final PsiFile psiFile = psiDocumentManager.getPsiFile(document); + + final LogicalPosition logicalPos = editor.getCaretModel().getLogicalPosition(); + final int line = logicalPos.line; + int start = 6666, end = 6666; + for (int i = 0; ; --i) { + final int cline = line + i; + int offset; + try { + offset = DocumentUtil.getFirstNonSpaceCharOffset(document, cline); + start = offset; + } catch (IndexOutOfBoundsException ex) { + break; + } + final PsiElement psiElement = psiFile.findElementAt(offset); + // System.out.println("i = " + i); + // System.out.println("cline = " + cline); + // System.out.println("psiElement = " + psiElement); + // System.out.println("psiElement.getNode() = " + psiElement.getNode()); + if (psiElement == null) + break; + final var elementType = psiElement.getNode().getElementType(); + // System.out.println("elementType = " + elementType); + if (!((elementType instanceof PyElementType) || (psiElement.getNode() instanceof PsiWhiteSpace))) + return true; + } + return false; + } + static void moveCaretVertical(final Editor editor, final int numLines) { + final LogicalPosition pos = editor.getCaretModel().getLogicalPosition(); + editor.getCaretModel().moveToOffset( + editor.logicalPositionToOffset( + new LogicalPosition(pos.line + numLines, pos.column))); + } + + private static void submitTopLevelCodeBlock(final AnActionEvent e, final Editor editor) { + final Document document = editor.getDocument(); + final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject()); + psiDocumentManager.commitDocument(document); + final PsiFile psiFile = psiDocumentManager.getPsiFile(document); + + for (; ; ) { + final LogicalPosition logicalPos = editor.getCaretModel().getLogicalPosition(); + final int firstNonSpaceCharOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, logicalPos.line); + // System.out.println("firstNonSpaceCharOffset = " + firstNonSpaceCharOffset); + final int lineStartOffset = DocumentUtil.getLineStartOffset(firstNonSpaceCharOffset, + document); +// System.out.println("lineStartOffset = " + lineStartOffset); + if (lineStartOffset == firstNonSpaceCharOffset) { + final PsiElement pe = psiFile.findElementAt(lineStartOffset); +// System.out.println("pe.getTextOffset() = " + pe.getTextOffset()); + if (pe.getTextOffset() == lineStartOffset) { + PySmartExecuteSelectionAction.smartExecuteCode(e, editor); + return; + } + } + try { + moveCaretVertical(editor, -1); + }catch(Exception ex){ +// ex.printStackTrace(); + throw ex; + } + } + } private static void cellExecute(final AnActionEvent e, final Editor editor) { final Document document = editor.getDocument(); final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject()); @@ -52,16 +122,18 @@ private static void cellExecute(final AnActionEvent e, final Editor editor) { break; } final PsiElement psiElement = psiFile.findElementAt(offset); + // System.out.println("i = " + i); + // System.out.println("cline = " + cline); + // System.out.println("psiElement = " + psiElement); + // System.out.println("psiElement.getNode() = " + psiElement.getNode()); + if (psiElement == null) + break; final var elementType = psiElement.getNode().getElementType(); -// System.out.println("i = " + i); -// System.out.println("cline = " + cline); -// System.out.println("psiElement = " + psiElement); -// System.out.println("psiElement.getNode() = " + psiElement.getNode()); -// System.out.println("elementType = " + elementType); + // System.out.println("elementType = " + elementType); if (!((elementType instanceof PyElementType) || (psiElement.getNode() instanceof PsiWhiteSpace))) break; } -// System.out.println("forward"); + // System.out.println("forward=================="); for (int i = 0; ; ++i) { final int cline = line + i; int offset; @@ -72,12 +144,14 @@ private static void cellExecute(final AnActionEvent e, final Editor editor) { break; } final PsiElement psiElement = psiFile.findElementAt(offset); + // System.out.println("i = " + i); + // System.out.println("cline = " + cline); + // System.out.println("psiElement = " + psiElement); + if (psiElement == null) + break; + // System.out.println("psiElement.getNode() = " + psiElement.getNode()); final var elementType = psiElement.getNode().getElementType(); -// System.out.println("i = " + i); -// System.out.println("cline = " + cline); -// System.out.println("psiElement = " + psiElement); -// System.out.println("psiElement.getNode() = " + psiElement.getNode()); -// System.out.println("elementType = " + elementType); + // System.out.println("elementType = " + elementType); if (!((elementType instanceof PyElementType) || (psiElement.getNode() instanceof PsiWhiteSpace))) break; } @@ -85,7 +159,7 @@ private static void cellExecute(final AnActionEvent e, final Editor editor) { start = DocumentUtil.getLineEndOffset(start, document); end = DocumentUtil.getLineEndOffset(end, document); String codeToSend = editor.getDocument().getCharsSequence().subSequence(start, end).toString(); -// System.out.println("codeToSend = " + codeToSend); + // System.out.println("codeToSend = " + codeToSend); PyExecuteInConsole.executeCodeInConsole(e.getProject(), codeToSend, null, true, true, false, null); } @@ -100,7 +174,10 @@ public void actionPerformed(@NotNull AnActionEvent e) { PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null); } else { - cellExecute(e, editor); + if (inJupyterNotebookMode(e, editor)) + cellExecute(e, editor); + else + submitTopLevelCodeBlock(e, editor); } } } diff --git a/src/main/java/com/jetbrains/python/actions/PySmartExecuteSelectionAction.java b/src/main/java/com/jetbrains/python/actions/PySmartExecuteSelectionAction.java index 6c9d533..989f3a3 100644 --- a/src/main/java/com/jetbrains/python/actions/PySmartExecuteSelectionAction.java +++ b/src/main/java/com/jetbrains/python/actions/PySmartExecuteSelectionAction.java @@ -104,7 +104,7 @@ static void moveCaretDown(final Editor editor, final int numLinesToSubmit) { // editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); // } } - private static void smartExecuteCode(final AnActionEvent e, final Editor editor) { + static void smartExecuteCode(final AnActionEvent e, final Editor editor) { final Document document = editor.getDocument(); final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject()); psiDocumentManager.commitDocument(document); diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 7bbb7ae..53e14f3 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -6,7 +6,7 @@ python-smart-execute Python Smart Execute - 0.1.12 + 0.2.0 Guo Ci Teo https://youtrack.jetbrains.com/issue/PY-38919. - For IDEs with Jupyter notebook support, there is also a execute cell command "Execute cell in console". + New feature for 0.2.x: + + When editing Python code, execute a top level code block with "Execute cell in console". + + For IDEs with Jupyter notebook support, this executes a cell in the Python console. keyboard shortcut: alt shift E. ]]>