PY-36696 Add caret movement for the Python Console

When a user calls `Previous Entry in Console History` action, move the caret to the end of the first line

IJ-CR-111281

GitOrigin-RevId: a351f264722b74c89692963ead0467250ac01a68
This commit is contained in:
Egor.Eliseev
2023-07-13 12:39:33 +03:00
committed by intellij-monorepo-bot
parent f5a614fdef
commit bd1b43401c
5 changed files with 88 additions and 8 deletions

View File

@@ -86,6 +86,7 @@ public class ConsoleHistoryController implements Disposable {
private boolean myMultiline;
private ModelHelper myHelper;
private long myLastSaveStamp;
private boolean isMoveCaretToTheFirstLine = false;
/**
* @deprecated use {@link #ConsoleHistoryController(ConsoleRootType, String, LanguageConsoleView)} or {@link #ConsoleHistoryController(ConsoleRootType, String, LanguageConsoleView, ConsoleHistoryModel)}
@@ -106,6 +107,12 @@ public class ConsoleHistoryController implements Disposable {
myConsole = console;
}
public ConsoleHistoryController(@NotNull ConsoleRootType rootType, @Nullable String persistenceId,
@NotNull LanguageConsoleView console, boolean moveCaretToTheFirstLine) {
this(rootType, persistenceId, console);
isMoveCaretToTheFirstLine = moveCaretToTheFirstLine;
}
@TestOnly
public void setModel(@NotNull ConsoleHistoryModel model){
myHelper = new ModelHelper(myHelper.myRootType, myHelper.myId, model);
@@ -302,6 +309,10 @@ public class ConsoleHistoryController implements Disposable {
Entry command = myNext ? getModel().getHistoryNext() : getModel().getHistoryPrev();
if (!myMultiline && command == null || !hasHistory && !myNext) return;
setConsoleText(command, !hasHistory, true);
if (isMoveCaretToTheFirstLine && myNext) {
EditorEx consoleEditor = myConsole.getConsoleEditor();
consoleEditor.getCaretModel().moveToOffset(consoleEditor.getDocument().getLineEndOffset(0));
}
}
@Override

View File

@@ -86,21 +86,26 @@ public final class LanguageConsoleBuilder {
}
@NotNull
public LanguageConsoleBuilder initActions(@NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType) {
public LanguageConsoleBuilder initActions(@NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType, boolean moveCaretToTheFirstLine) {
if (consoleView == null) {
this.executeActionHandler = executeActionHandler;
this.historyType = historyType;
}
else {
doInitAction(consoleView, executeActionHandler, historyType);
doInitAction(consoleView, executeActionHandler, historyType, moveCaretToTheFirstLine);
}
return this;
}
private void doInitAction(@NotNull LanguageConsoleView console, @NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType) {
@NotNull
public LanguageConsoleBuilder initActions(@NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType) {
return initActions(executeActionHandler, historyType, false);
}
private void doInitAction(@NotNull LanguageConsoleView console, @NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType, boolean moveCaretToTheFirstLine) {
ConsoleExecuteAction action = new ConsoleExecuteAction(console, executeActionHandler, executionEnabled);
action.registerCustomShortcutSet(action.getShortcutSet(), console.getConsoleEditor().getComponent());
new ConsoleHistoryController(new MyConsoleRootType(historyType), null, console).install();
new ConsoleHistoryController(new MyConsoleRootType(historyType), null, console, moveCaretToTheFirstLine).install();
}
/**
@@ -161,7 +166,7 @@ public final class LanguageConsoleBuilder {
}
if (executeActionHandler != null) {
assert historyType != null;
doInitAction(consoleView, executeActionHandler, historyType);
doInitAction(consoleView, executeActionHandler, historyType, false);
}
if (processInputStateKey != null) {

View File

@@ -1107,7 +1107,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner {
myConsoleExecuteActionHandler =
new PydevConsoleExecuteActionHandler(myConsoleView, myProcessHandler, myPydevConsoleCommunication);
myConsoleExecuteActionHandler.setEnabled(false);
new ConsoleHistoryController(PyConsoleRootType.Companion.getInstance(), "", myConsoleView).install();
new ConsoleHistoryController(PyConsoleRootType.Companion.getInstance(), "", myConsoleView, true).install();
return myConsoleExecuteActionHandler;
}

View File

@@ -7,7 +7,7 @@ import com.intellij.execution.ExecutionManager;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.console.LanguageConsoleBuilder;
import com.intellij.execution.console.*;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.process.ProcessHandler;
@@ -416,7 +416,7 @@ public class PyDebugRunner implements ProgramRunner<RunnerSettings> {
pythonConsoleView.setExecutionHandler(consoleExecuteActionHandler);
debugProcess.getSession().addSessionListener(consoleExecuteActionHandler);
new LanguageConsoleBuilder(pythonConsoleView).processHandler(processHandler).initActions(consoleExecuteActionHandler, "py");
new LanguageConsoleBuilder(pythonConsoleView).processHandler(processHandler).initActions(consoleExecuteActionHandler, "py", true);
debugConsoleCommunication.addCommunicationListener(new ConsoleCommunicationListener() {

View File

@@ -3,7 +3,13 @@ package com.jetbrains.env.debug;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.intellij.execution.console.ConsoleHistoryController;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.testFramework.EdtTestUtil;
import com.intellij.testFramework.TestActionEvent;
import com.intellij.xdebugger.impl.ui.tree.nodes.XDebuggerTreeNode;
import com.jetbrains.env.PyEnvTestCase;
import com.jetbrains.python.console.PyConsoleOptions;
@@ -367,4 +373,62 @@ public class PythonConsoleTest extends PyEnvTestCase {
}
});
}
@Test
public void testConsoleHistoryNavigation() {
runPythonTest(new PyConsoleTask("/debug") {
@Override
public void testing() {
addToHistory("a = 1");
addToHistory("""
def foo():
x = 1
y = 2
return x + y""");
runHistoryAction(true);
checkCaretPosition(true);
runHistoryAction(true);
checkCaretPosition(true);
runHistoryAction(false);
checkCaretPosition(false);
}
private void addToHistory(String command) {
WriteCommandAction.runWriteCommandAction(getProject(), () -> {
ConsoleHistoryController.getController(getConsoleView()).addToHistory(command);
});
}
private void runHistoryAction(boolean isNext) {
ConsoleHistoryController controller = ConsoleHistoryController.getController(getConsoleView());
EdtTestUtil.runInEdtAndWait(() -> {
AnAction action = isNext ? controller.getHistoryNext() : controller.getHistoryPrev();
action.actionPerformed(TestActionEvent.createTestEvent());
});
}
private void checkCaretPosition(boolean isNext) {
EditorEx consoleEditor = getConsoleView().getConsoleEditor();
ApplicationManager.getApplication().runReadAction(() -> {
int offset = consoleEditor.getCaretModel().getOffset();
int caretLine = consoleEditor.getDocument().getLineNumber(offset);
int linesCount = consoleEditor.getDocument().getLineCount();
if (linesCount > 1) {
if (isNext) {
assertEquals(0, caretLine);
}
else {
assertEquals(linesCount - 1, caretLine);
}
} else {
assertEquals(0, caretLine);
}
});
}
});
}
}