mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
typing in console was broken
This commit is contained in:
@@ -101,16 +101,15 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
|
||||
public static final Key<ConsoleViewImpl> CONSOLE_VIEW_IN_EDITOR_VIEW = Key.create("CONSOLE_VIEW_IN_EDITOR_VIEW");
|
||||
private static final Key<ConsoleViewContentType> CONTENT_TYPE = Key.create("ConsoleViewContentType");
|
||||
private static final Key<Boolean> USER_INPUT_SENT = Key.create("USER_INPUT_SENT");
|
||||
|
||||
private static boolean ourTypedHandlerInitialized;
|
||||
private final Alarm myFlushUserInputAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this);
|
||||
private final StringBuilder myUserInputText = new StringBuilder(); // guarded by LOCK
|
||||
private static final CharMatcher NEW_LINE_MATCHER = CharMatcher.anyOf("\n\r");
|
||||
|
||||
private static synchronized void initTypedHandler() {
|
||||
if (ourTypedHandlerInitialized) return;
|
||||
final EditorActionManager actionManager = EditorActionManager.getInstance();
|
||||
final TypedAction typedAction = actionManager.getTypedAction();
|
||||
TypedAction typedAction = EditorActionManager.getInstance().getTypedAction();
|
||||
typedAction.setupHandler(new MyTypedHandler(typedAction.getHandler()));
|
||||
ourTypedHandlerInitialized = true;
|
||||
}
|
||||
@@ -521,6 +520,8 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
void waitAllRequests() {
|
||||
myFlushAlarm.flush();
|
||||
myFlushUserInputAlarm.flush();
|
||||
myFlushAlarm.flush();
|
||||
myFlushUserInputAlarm.flush();
|
||||
}
|
||||
|
||||
protected void disposeEditor() {
|
||||
@@ -564,7 +565,6 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
myDeferredBuffer.print(text, contentType, info);
|
||||
|
||||
if (contentType == ConsoleViewContentType.USER_INPUT) {
|
||||
sendUserInput(text);
|
||||
requestFlushImmediately();
|
||||
}
|
||||
if (myEditor != null) {
|
||||
@@ -574,17 +574,29 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUserInput(@NotNull String text) {
|
||||
if (myState.isRunning()) {
|
||||
myUserInputText.append(text);
|
||||
if (NEW_LINE_MATCHER.indexIn(text) >= 0) {
|
||||
String textToSend = myUserInputText.toString();
|
||||
myUserInputText.setLength(0);
|
||||
private void sendUserInput(@NotNull CharSequence typedText) {
|
||||
if (myState.isRunning() && NEW_LINE_MATCHER.indexIn(typedText) >= 0) {
|
||||
StringBuilder textToSend = new StringBuilder();
|
||||
// compute text input from the console contents:
|
||||
// all range markers beginning from the caret offset backwards, marked as user input and not marked as already sent
|
||||
for (RangeMarker marker = findTokenMarker(myEditor.getCaretModel().getOffset());
|
||||
marker != null;
|
||||
marker = ((RangeMarkerImpl)marker).findRangeMarkerBefore()) {
|
||||
ConsoleViewContentType tokenType = getTokenType(marker);
|
||||
if (tokenType != null) {
|
||||
if (tokenType != ConsoleViewContentType.USER_INPUT || marker.getUserData(USER_INPUT_SENT) == Boolean.TRUE) {
|
||||
break;
|
||||
}
|
||||
marker.putUserData(USER_INPUT_SENT, true);
|
||||
textToSend.insert(0, marker.getDocument().getText(TextRange.create(marker)));
|
||||
}
|
||||
}
|
||||
if (textToSend.length() != 0) {
|
||||
myFlushUserInputAlarm.addRequest(() -> {
|
||||
if (myState.isRunning()) {
|
||||
try {
|
||||
// this may block forever, see IDEA-54340
|
||||
myState.sendUserInput(textToSend);
|
||||
myState.sendUserInput(textToSend.toString());
|
||||
}
|
||||
catch (IOException ignored) {
|
||||
}
|
||||
@@ -713,6 +725,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
if (shouldStickToEnd) {
|
||||
scrollToEnd();
|
||||
}
|
||||
sendUserInput(addedText);
|
||||
}
|
||||
|
||||
private void createTokenRangeMarker(@NotNull Document document,
|
||||
@@ -1111,7 +1124,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
return marker[0];
|
||||
}
|
||||
|
||||
private static ConsoleViewContentType getTokenType(RangeMarker m) {
|
||||
private static ConsoleViewContentType getTokenType(@Nullable RangeMarker m) {
|
||||
return m == null ? null : m.getUserData(CONTENT_TYPE);
|
||||
}
|
||||
|
||||
@@ -1498,6 +1511,7 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
}
|
||||
|
||||
moveScrollRemoveSelection(editor, newEndOffset);
|
||||
sendUserInput(text);
|
||||
}
|
||||
|
||||
private void replaceUserText(int start, int end, @NotNull String text) {
|
||||
@@ -1506,8 +1520,10 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
|
||||
final Document document = editor.getDocument();
|
||||
|
||||
document.replaceString(start, end, text);
|
||||
|
||||
int offset = start + text.length();
|
||||
moveScrollRemoveSelection(editor, offset);
|
||||
sendUserInput(text);
|
||||
}
|
||||
|
||||
private static void moveScrollRemoveSelection(@NotNull Editor editor, int offset) {
|
||||
|
||||
+34
-39
@@ -27,9 +27,9 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
|
||||
import com.intellij.openapi.editor.actionSystem.TypedAction;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream;
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
|
||||
@@ -42,13 +42,10 @@ import com.intellij.util.TimeoutUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -271,42 +268,9 @@ public class ConsoleViewImplTest extends LightPlatformTestCase {
|
||||
}
|
||||
|
||||
public void testUserInputIsSentToProcessAfterNewLinePressed() {
|
||||
byte[] buffer = new byte[10000];
|
||||
BufferExposingByteArrayOutputStream outputStream = new BufferExposingByteArrayOutputStream(buffer);
|
||||
BufferExposingByteArrayInputStream inputStream = new BufferExposingByteArrayInputStream(buffer);
|
||||
AtomicBoolean finished = new AtomicBoolean();
|
||||
Process testProcess = new Process() {
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
Process testProcess = AnsiEscapeDecoderTest.createTestProcess();
|
||||
BufferExposingByteArrayOutputStream outputStream = (BufferExposingByteArrayOutputStream)testProcess.getOutputStream();
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getErrorStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int waitFor() {
|
||||
while (!finished.get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int exitValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
finished.set(true);
|
||||
}
|
||||
};
|
||||
AnsiEscapeDecoderTest.withProcessHandlerFrom(testProcess, handler ->
|
||||
withCycleConsole(100, console -> {
|
||||
console.attachToProcess(handler);
|
||||
@@ -323,4 +287,35 @@ public class ConsoleViewImplTest extends LightPlatformTestCase {
|
||||
assertEquals("IK\n", outputStream.toString());
|
||||
}));
|
||||
}
|
||||
|
||||
public void testUserTypingIsSentToProcessAfterNewLinePressed() {
|
||||
Process testProcess = AnsiEscapeDecoderTest.createTestProcess();
|
||||
BufferExposingByteArrayOutputStream outputStream = (BufferExposingByteArrayOutputStream)testProcess.getOutputStream();
|
||||
|
||||
AnsiEscapeDecoderTest.withProcessHandlerFrom(testProcess, handler ->
|
||||
withCycleConsole(100, console -> {
|
||||
console.attachToProcess(handler);
|
||||
outputStream.reset();
|
||||
Editor editor = console.getEditor();
|
||||
typeIn(editor, 'X');
|
||||
console.waitAllRequests();
|
||||
assertEquals(0, outputStream.size());
|
||||
|
||||
typeIn(editor, 'Y');
|
||||
console.waitAllRequests();
|
||||
assertEquals(0, outputStream.size());
|
||||
|
||||
typeIn(editor, '\n');
|
||||
console.waitAllRequests();
|
||||
assertEquals(3, outputStream.size());
|
||||
assertEquals("XY\n", outputStream.toString());
|
||||
}));
|
||||
}
|
||||
|
||||
private static void typeIn(Editor editor, char c) {
|
||||
TypedAction action = EditorActionManager.getInstance().getTypedAction();
|
||||
DataContext dataContext = ((EditorEx)editor).getDataContext();
|
||||
|
||||
action.actionPerformed(editor, c, dataContext);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-5
@@ -100,12 +100,13 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
|
||||
};
|
||||
}
|
||||
|
||||
public void testPerformance() throws IOException {
|
||||
byte[] buffer = new byte[100000];
|
||||
@NotNull
|
||||
public static Process createTestProcess() {
|
||||
byte[] buffer = new byte[1000];
|
||||
BufferExposingByteArrayOutputStream outputStream = new BufferExposingByteArrayOutputStream(buffer);
|
||||
BufferExposingByteArrayInputStream inputStream = new BufferExposingByteArrayInputStream(buffer);
|
||||
AtomicBoolean finished = new AtomicBoolean();
|
||||
Process testProcess = new Process() {
|
||||
return new Process() {
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
@@ -137,6 +138,10 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
|
||||
finished.set(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void testPerformance() throws IOException {
|
||||
Process testProcess = createTestProcess();
|
||||
|
||||
withProcessHandlerFrom(testProcess, handler -> {
|
||||
PlatformTestUtil.startPerformanceTest("ansi color", 15000, ()->{
|
||||
@@ -148,14 +153,14 @@ public class AnsiEscapeDecoderTest extends PlatformTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public static void withProcessHandlerFrom(@NotNull Process testProcess, @NotNull Consumer<ProcessHandler> consumer) {
|
||||
public static void withProcessHandlerFrom(@NotNull Process testProcess, @NotNull Consumer<ProcessHandler> actionToTest) {
|
||||
KillableColoredProcessHandler handler = new KillableColoredProcessHandler(testProcess, "testProcess");
|
||||
handler.setShouldDestroyProcessRecursively(false);
|
||||
handler.startNotify();
|
||||
handler.notifyTextAvailable("Running stuff...\n", ProcessOutputTypes.STDOUT);
|
||||
|
||||
try {
|
||||
consumer.consume(handler);
|
||||
actionToTest.consume(handler);
|
||||
}
|
||||
finally {
|
||||
handler.doDestroyProcess();
|
||||
|
||||
Reference in New Issue
Block a user