Skip to content

Commit

Permalink
add options to choose cursor movement after code send
Browse files Browse the repository at this point in the history
  • Loading branch information
guoci committed May 28, 2023
1 parent 9825879 commit aee81f4
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.DocumentUtil;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.actions.PySmartExecuteSelectionAction.CursorMoveAfterExecute;
import com.jetbrains.python.psi.PyElementType;
import com.jetbrains.python.psi.PyElsePart;
import com.jetbrains.python.psi.PyExceptPart;
Expand All @@ -32,7 +33,7 @@

public class PyCellExecuteAction extends AnAction {

private static boolean inJupyterNotebookMode(final AnActionEvent e, final Editor editor) {
static boolean inJupyterNotebookMode(final AnActionEvent e, final Editor editor) {
// by checking for `JupyterTokenType.CODE_MARKER`
// but Pycharm's Jupyter mode is a closed sourced component, to workaround, check if it is not (`PyElementType` or `PsiWhiteSpace`)
final Document document = editor.getDocument();
Expand Down Expand Up @@ -73,12 +74,12 @@ static void moveCaretVertical(final Editor editor, final int numLines) {
new LogicalPosition(pos.line + numLines, pos.column)));
}

private static void submitTopLevelCodeBlock(final AnActionEvent e, final Editor editor) {
static void submitTopLevelCodeBlock(final AnActionEvent e, final Editor editor, CursorMoveAfterExecute cursorMoveAfterExecute) {
final Document document = editor.getDocument();
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject());
psiDocumentManager.commitDocument(document);
final PsiFile psiFile = psiDocumentManager.getPsiFile(document);

final int currentLogicalPos = editor.getCaretModel().getOffset();
for (; ; ) {
final LogicalPosition logicalPos = editor.getCaretModel().getLogicalPosition();
final int firstNonSpaceCharOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, logicalPos.line);
Expand All @@ -90,7 +91,9 @@ private static void submitTopLevelCodeBlock(final AnActionEvent e, final Editor
final PsiElement pe = psiFile.findElementAt(lineStartOffset);
// System.out.println("pe.getTextOffset() = " + pe.getTextOffset());
if (pe.getTextOffset() == lineStartOffset) {
PySmartExecuteSelectionAction.smartExecuteCode(e, editor);
PySmartExecuteSelectionAction.smartExecuteCode(e, editor, cursorMoveAfterExecute);
if(cursorMoveAfterExecute==CursorMoveAfterExecute.NO_MOVE)
editor.getCaretModel().moveToOffset(currentLogicalPos);
return;
}
}
Expand All @@ -102,7 +105,7 @@ private static void submitTopLevelCodeBlock(final AnActionEvent e, final Editor
}
}
}
private static void cellExecute(final AnActionEvent e, final Editor editor) {
static void cellExecute(final AnActionEvent e, final Editor editor) {
final Document document = editor.getDocument();
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject());
psiDocumentManager.commitDocument(document);
Expand Down Expand Up @@ -177,7 +180,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
if (inJupyterNotebookMode(e, editor))
cellExecute(e, editor);
else
submitTopLevelCodeBlock(e, editor);
submitTopLevelCodeBlock(e, editor, CursorMoveAfterExecute.TO_NEXT_CODE_REGION);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.jetbrains.python.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.jetbrains.python.actions.PySmartExecuteSelectionAction.CursorMoveAfterExecute;
import org.jetbrains.annotations.NotNull;

public class PyCellExecuteActionCursorNoMove extends AnAction {

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
final String selectionText = PySmartExecuteSelectionAction.getSelectionText(editor);
if (selectionText != null) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null);
}
else {
if (PyCellExecuteAction.inJupyterNotebookMode(e, editor))
PyCellExecuteAction.cellExecute(e, editor);
else
PyCellExecuteAction.submitTopLevelCodeBlock(e, editor, CursorMoveAfterExecute.NO_MOVE);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.jetbrains.python.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.jetbrains.python.actions.PySmartExecuteSelectionAction.CursorMoveAfterExecute;
import org.jetbrains.annotations.NotNull;

public class PyCellExecuteActionCursorToEnd extends AnAction {

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
final String selectionText = PySmartExecuteSelectionAction.getSelectionText(editor);
if (selectionText != null) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null);
}
else {
if (PyCellExecuteAction.inJupyterNotebookMode(e, editor))
PyCellExecuteAction.cellExecute(e, editor);
else
PyCellExecuteAction.submitTopLevelCodeBlock(e, editor, CursorMoveAfterExecute.TO_THE_END_OF_CODE_BLOCK);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ static void moveCaretDown(final Editor editor, final int numLinesToSubmit) {
// editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
// }
}
static void smartExecuteCode(final AnActionEvent e, final Editor editor) {

enum CursorMoveAfterExecute {
NO_MOVE, TO_THE_END_OF_CODE_BLOCK, TO_NEXT_CODE_REGION;
}
static void smartExecuteCode(final AnActionEvent e, final Editor editor, final CursorMoveAfterExecute cursorMoveAfterExecute) {
final Document document = editor.getDocument();
final PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(e.getProject());
psiDocumentManager.commitDocument(document);
Expand Down Expand Up @@ -163,16 +167,22 @@ static void smartExecuteCode(final AnActionEvent e, final Editor editor) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), codeToSend, null, true, true, false, null);
}
if (codeToSend != null) {
moveCaretDown(editor, numLinesToSubmit);
for(;;) { // skip comments and whitespace
final int currentOffset = DocumentUtil.getFirstNonSpaceCharOffset(document,
editor.getCaretModel().getLogicalPosition().line);
final PsiElement pe = psiFile.findElementAt(currentOffset);
if (pe != null && (pe.getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT
|| pe.getNode() instanceof PsiWhiteSpace))
moveCaretDown(editor, 1);
else
break;
if (cursorMoveAfterExecute == CursorMoveAfterExecute.TO_NEXT_CODE_REGION
|| cursorMoveAfterExecute == CursorMoveAfterExecute.TO_THE_END_OF_CODE_BLOCK) {
moveCaretDown(editor, numLinesToSubmit);
}
if (cursorMoveAfterExecute == CursorMoveAfterExecute.TO_NEXT_CODE_REGION) {
for (; ; ) { // skip comments and whitespace
final int currentOffset = DocumentUtil.getFirstNonSpaceCharOffset(document,
editor.getCaretModel().getLogicalPosition().line);
final PsiElement pe = psiFile.findElementAt(currentOffset);
if (pe != null && (pe.getNode().getElementType() == PyTokenTypes.END_OF_LINE_COMMENT
|| pe.getNode() instanceof PsiWhiteSpace)) {
moveCaretDown(editor, 1);
} else {
break;
}
}
}
} else {
syntaxErrorAction(e);
Expand Down Expand Up @@ -201,7 +211,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null);
}
else {
smartExecuteCode(e, editor);
smartExecuteCode(e, editor, CursorMoveAfterExecute.TO_NEXT_CODE_REGION);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.jetbrains.python.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.jetbrains.python.actions.PySmartExecuteSelectionAction.CursorMoveAfterExecute;
import org.jetbrains.annotations.NotNull;

public class PySmartExecuteSelectionActionCursorNoMove extends AnAction {

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
final String selectionText = PySmartExecuteSelectionAction.getSelectionText(editor);
if (selectionText != null) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null);
}
else {
PySmartExecuteSelectionAction.smartExecuteCode(e, editor, CursorMoveAfterExecute.NO_MOVE);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.jetbrains.python.actions;

import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.editor.Editor;
import com.jetbrains.python.actions.PySmartExecuteSelectionAction.CursorMoveAfterExecute;
import org.jetbrains.annotations.NotNull;

public class PySmartExecuteSelectionActionCursorToEnd extends AnAction {

@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
if (editor != null) {
final String selectionText = PySmartExecuteSelectionAction.getSelectionText(editor);
if (selectionText != null) {
PyExecuteInConsole.executeCodeInConsole(e.getProject(), selectionText, null, true, true, false, null);
}
else {
PySmartExecuteSelectionAction.smartExecuteCode(e, editor, CursorMoveAfterExecute.TO_THE_END_OF_CODE_BLOCK);
}
}
}
}
39 changes: 34 additions & 5 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.2.2</version>
<version>0.3.0</version>
<vendor email="[email protected]" url="https://github.com/JetBrains/intellij-community/pull/711">Guo Ci Teo</vendor>

<description><![CDATA[
Expand All @@ -22,14 +22,19 @@
<p>JetBrains feature request: <a href="https://youtrack.jetbrains.com/issue/PY-38919">https://youtrack.jetbrains.com/issue/PY-38919</a>.
</p>
<li><code>Execute cell in console</code></li>
<p><em>New feature for version 0.2.x</em></p>
<p>When editing Python code, execute a <em>top level</em> code block with "Execute cell in console". Cursor can be anywhere in the code block.</p>
<p>For IDEs with Jupyter notebook support, this executes a cell in the Python console.</p>
<p>keyboard shortcut: <code>Alt+Shift+E</code>,
action name: <code>Execute cell in console</code></p></p>
<p><code>Alt+Shift+E</code> conflicts with the default keyboard shortcut for <code>Execute
Selection
in Python Console</code>. Consider changing/removing their keybindings to resolve it.</p>
<li>Cursor movement after code is sent to the Python console</li>
<ul>
<li>do not move cursor</li>
<li>move to the end of the last code region sent</li>
<li>move to the next code region</li>
</ul>
</ul>
]]></description>

Expand All @@ -52,8 +57,8 @@
<actions>
<action id="SmartExecuteInPyConsoleAction"
class="com.jetbrains.python.actions.PySmartExecuteSelectionAction"
text="Smart execute selection in console"
description="Smart executes selected code fragment in Python/Django console">
text="Smart execute code in console, move to next code region"
description="Smart executes code fragment in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>

<keyboard-shortcut keymap="$default" first-keystroke="alt shift A"/>
Expand All @@ -62,15 +67,39 @@
<keyboard-shortcut keymap="Eclipse" first-keystroke="ctrl alt A" replace-all="true"/>
<keyboard-shortcut keymap="NetBeans 6.5" first-keystroke="ctrl alt A" replace-all="true"/>
</action>
<action id="SmartExecuteInPyConsoleActionCursorNoMove"
class="com.jetbrains.python.actions.PySmartExecuteSelectionActionCursorNoMove"
text="Smart execute code in console, cursor stays"
description="Smart executes code fragment in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>
</action>
<action id="SmartExecuteInPyConsoleActionCursorToEnd"
class="com.jetbrains.python.actions.PySmartExecuteSelectionActionCursorToEnd"
text="Smart execute code in console, cursor move to last line submitted"
description="Smart executes code fragment in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>
</action>
<action id="ExecuteCellInPyConsoleAction"
class="com.jetbrains.python.actions.PyCellExecuteAction"
text="Execute cell in console"
text="Execute cell in console, move to next code region"
description="Executes cell in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>

<keyboard-shortcut keymap="$default" first-keystroke="alt shift E"/>
<keyboard-shortcut keymap="Mac OS X" first-keystroke="control shift E" />
<keyboard-shortcut keymap="Mac OS X 10.5+" first-keystroke="control shift E" />
</action>
<action id="ExecuteCellInPyConsoleActionCursorNoMove"
class="com.jetbrains.python.actions.PyCellExecuteActionCursorNoMove"
text="Execute cell in console, cursor stays"
description="Executes cell in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>
</action>
<action id="ExecuteCellInPyConsoleActionCursorToEnd"
class="com.jetbrains.python.actions.PyCellExecuteActionCursorToEnd"
text="Execute cell in console, cursor move to last line submitted"
description="Executes cell in Python console">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="ExecuteInPyConsoleAction"/>
</action>
</actions>
</idea-plugin>

0 comments on commit aee81f4

Please sign in to comment.