Skip to content

Commit

Permalink
add feature to execute top level code block when editing Python sourc…
Browse files Browse the repository at this point in the history
…e code
  • Loading branch information
guoci committed May 21, 2023
1 parent 4c9e3f7 commit 7e895ee
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 16 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: <code>alt shift E</code>.

![demonstration](demo.gif "demonstration")
103 changes: 90 additions & 13 deletions src/main/java/com/jetbrains/python/actions/PyCellExecuteAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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;
Expand All @@ -72,20 +144,22 @@ 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;
}
{
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);
}
Expand All @@ -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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<idea-plugin>
<id>python-smart-execute</id>
<name>Python Smart Execute</name>
<version>0.1.12</version>
<version>0.2.0</version>
<vendor email="[email protected]" url="https://github.com/JetBrains/intellij-community/pull/711">Guo Ci Teo</vendor>

<description><![CDATA[
Expand All @@ -18,7 +18,11 @@
JetBrains feature request: <a href="https://youtrack.jetbrains.com/issue/PY-38919">https://youtrack.jetbrains.com/issue/PY-38919</a>.
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: <code>alt shift E</code>.
]]></description>
Expand Down

0 comments on commit 7e895ee

Please sign in to comment.