Skip to content

Commit 773e054

Browse files
committed
Improve dumb terminal detection
1 parent 6f32fdf commit 773e054

File tree

4 files changed

+51
-68
lines changed

4 files changed

+51
-68
lines changed

endermux-client/src/main/java/xyz/jpenilla/endermux/client/runtime/RemoteConsoleSession.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ private boolean acceptInputDumb() {
212212
if (this.connectedClient() == null || this.shutdownRequested.getAsBoolean()) {
213213
return false;
214214
}
215+
if (!this.terminalContext.hasConsoleInput()) {
216+
this.sleepForInput();
217+
continue;
218+
}
215219
LOGGER.info("Disconnecting...");
216220
return true;
217221
}
@@ -224,6 +228,16 @@ private boolean acceptInputDumb() {
224228
}
225229
}
226230

231+
private void sleepForInput() {
232+
try {
233+
Thread.sleep(SOCKET_POLL_INTERVAL_MS);
234+
} catch (final InterruptedException e) {
235+
if (!this.shutdownRequested.getAsBoolean()) {
236+
LOGGER.debug("Interrupted while waiting for stdin input", e);
237+
}
238+
}
239+
}
240+
227241
private @Nullable String readInputLine(final BufferedReader reader) throws IOException {
228242
while (true) {
229243
if (this.shutdownRequested.getAsBoolean() || this.connectedClient() == null) {
@@ -232,13 +246,9 @@ private boolean acceptInputDumb() {
232246
if (reader.ready()) {
233247
return reader.readLine();
234248
}
235-
try {
236-
Thread.sleep(SOCKET_POLL_INTERVAL_MS);
237-
} catch (final InterruptedException e) {
238-
if (this.shutdownRequested.getAsBoolean()) {
239-
return null;
240-
}
241-
LOGGER.debug("Interrupted while waiting for stdin input", e);
249+
this.sleepForInput();
250+
if (this.shutdownRequested.getAsBoolean()) {
251+
return null;
242252
}
243253
}
244254
}

endermux-client/src/main/java/xyz/jpenilla/endermux/client/runtime/TerminalRuntimeContext.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,54 @@
1515
import xyz.jpenilla.endermux.client.parser.RemoteParser;
1616
import xyz.jpenilla.endermux.client.transport.SocketTransport;
1717
import xyz.jpenilla.endermux.jline.MinecraftCompletionMatcher;
18-
import xyz.jpenilla.endermux.jline.TerminalDetection;
18+
import xyz.jpenilla.endermux.jline.TerminalMode;
19+
import xyz.jpenilla.endermux.jline.TerminalModeDetection;
1920

2021
@NullMarked
2122
final class TerminalRuntimeContext implements AutoCloseable {
2223
private static final Logger LOGGER = LoggerFactory.getLogger(TerminalRuntimeContext.class);
23-
private final boolean dumbTerminal;
24+
private final TerminalMode mode;
25+
private final boolean consoleInputAvailable;
2426
private final @Nullable Terminal terminal;
2527

26-
private TerminalRuntimeContext(final boolean dumbTerminal, final @Nullable Terminal terminal) {
27-
this.dumbTerminal = dumbTerminal;
28+
private TerminalRuntimeContext(
29+
final TerminalMode mode,
30+
final boolean consoleInputAvailable,
31+
final @Nullable Terminal terminal
32+
) {
33+
this.mode = mode;
34+
this.consoleInputAvailable = consoleInputAvailable;
2835
this.terminal = terminal;
2936
}
3037

31-
static TerminalRuntimeContext create() throws IOException {
32-
final boolean dumb = TerminalDetection.isDumb();
33-
final @Nullable Terminal terminal;
34-
if (dumb) {
35-
terminal = null;
36-
} else {
37-
terminal = TerminalBuilder.builder()
38+
static TerminalRuntimeContext create() {
39+
final boolean consoleInputAvailable = TerminalModeDetection.hasConsoleInput();
40+
final TerminalMode detectedMode = TerminalModeDetection.mode();
41+
if (detectedMode == TerminalMode.DUMB) {
42+
TerminalOutput.setTerminal(null);
43+
return new TerminalRuntimeContext(TerminalMode.DUMB, consoleInputAvailable, null);
44+
}
45+
46+
try {
47+
final Terminal terminal = TerminalBuilder.builder()
3848
.system(true)
49+
.dumb(false)
3950
.build();
51+
TerminalOutput.setTerminal(terminal);
52+
return new TerminalRuntimeContext(TerminalMode.INTERACTIVE, consoleInputAvailable, terminal);
53+
} catch (final IOException | IllegalStateException e) {
54+
LOGGER.debug("Falling back to dumb mode after interactive terminal setup failure", e);
55+
TerminalOutput.setTerminal(null);
56+
return new TerminalRuntimeContext(TerminalMode.DUMB, consoleInputAvailable, null);
4057
}
41-
TerminalOutput.setTerminal(terminal);
42-
return new TerminalRuntimeContext(dumb, terminal);
4358
}
4459

4560
boolean isDumbTerminal() {
46-
return this.dumbTerminal;
61+
return this.mode == TerminalMode.DUMB;
62+
}
63+
64+
boolean hasConsoleInput() {
65+
return this.consoleInputAvailable;
4766
}
4867

4968
void registerInterruptHandler(final Runnable handler) {
@@ -55,7 +74,7 @@ void registerInterruptHandler(final Runnable handler) {
5574
}
5675

5776
@Nullable LineReader createLineReader(final SocketTransport socketClient, final Highlighter highlighter) {
58-
if (this.dumbTerminal) {
77+
if (this.mode == TerminalMode.DUMB) {
5978
return null;
6079
}
6180
return LineReaderBuilder.builder()

endermux-common/src/main/java/xyz/jpenilla/endermux/jline/TerminalMode.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,3 @@
1-
/*
2-
* This file is part of Better Fabric Console, licensed under the MIT License.
3-
*
4-
* Copyright (c) 2021-2024 Jason Penilla
5-
*
6-
* Permission is hereby granted, free of charge, to any person obtaining a copy
7-
* of this software and associated documentation files (the "Software"), to deal
8-
* in the Software without restriction, including without limitation the rights
9-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
* copies of the Software, and to permit persons to whom the Software is
11-
* furnished to do so, subject to the following conditions:
12-
*
13-
* The above copyright notice and this permission notice shall be included in all
14-
* copies or substantial portions of the Software.
15-
*
16-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-
* SOFTWARE.
23-
*/
241
package xyz.jpenilla.endermux.jline;
252

263
import org.jspecify.annotations.NullMarked;

endermux-common/src/main/java/xyz/jpenilla/endermux/jline/TerminalModeDetection.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,3 @@
1-
/*
2-
* This file is part of Better Fabric Console, licensed under the MIT License.
3-
*
4-
* Copyright (c) 2021-2024 Jason Penilla
5-
*
6-
* Permission is hereby granted, free of charge, to any person obtaining a copy
7-
* of this software and associated documentation files (the "Software"), to deal
8-
* in the Software without restriction, including without limitation the rights
9-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10-
* copies of the Software, and to permit persons to whom the Software is
11-
* furnished to do so, subject to the following conditions:
12-
*
13-
* The above copyright notice and this permission notice shall be included in all
14-
* copies or substantial portions of the Software.
15-
*
16-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22-
* SOFTWARE.
23-
*/
241
package xyz.jpenilla.endermux.jline;
252

263
import java.io.IOException;

0 commit comments

Comments
 (0)