Skip to content

Commit 700812f

Browse files
committed
updated the latest api changes to connection and color detection
1 parent deaf4d8 commit 700812f

7 files changed

Lines changed: 254 additions & 25 deletions

File tree

content/docs/readline/_index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ Think of it this way: Æsh is built **on top of** Æsh Readline. Æsh provides t
4343
- **Shell Features** - Redirect, alias, and pipeline support
4444
- **Remote Connectivity** - SSH, Telnet, and WebSocket terminal servers
4545
- **[Terminal Environment](terminal-environment)** - Centralized terminal detection (type, color depth, multiplexers)
46-
- **[Color Detection](color-detection)** - Automatic terminal theme and color depth detection
46+
- **[Color Detection](color-detection)** - Automatic terminal theme detection with batch queries and fallbacks
4747
- **[Terminal Colors](terminal-colors)** - RGB/HSL colors, theme-aware styling, and color depth adaptation
4848
- **[Device Attributes](device-attributes)** - DA1/DA2 terminal capability queries
4949
- **[Terminal Images](terminal-images)** - Sixel, Kitty, and iTerm2 inline image support

content/docs/readline/color-detection.md

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,24 @@ boolean has256 = depth.supports256Colors();
7676
boolean hasTrueColor = depth.supportsTrueColor();
7777

7878
// Actual RGB colors (may be null if not detectable)
79-
int[] bgRGB = cap.getBackgroundRGB(); // [r, g, b] or null
80-
int[] fgRGB = cap.getForegroundRGB(); // [r, g, b] or null
79+
int[] fgRGB = cap.getForegroundRGB(); // [r, g, b] or null
80+
int[] bgRGB = cap.getBackgroundRGB(); // [r, g, b] or null
81+
int[] cursorRGB = cap.getCursorRGB(); // [r, g, b] or null
82+
83+
// Palette colors (ANSI 16 colors, indices 0-15)
84+
if (cap.hasPaletteColors()) {
85+
Map<Integer, int[]> palette = cap.getPaletteColors();
86+
int[] red = cap.getPaletteColor(1); // Standard red
87+
int[] brightRed = cap.getPaletteColor(9); // Bright red
88+
}
8189
```
8290

91+
The `detect()` method queries:
92+
- Foreground color (OSC 10)
93+
- Background color (OSC 11)
94+
- Cursor color (OSC 12) - if supported
95+
- ANSI 16 palette colors (OSC 4, indices 0-15) - if supported
96+
8397
### Suggested Color Codes
8498

8599
Get ANSI color codes that work well with the detected theme:
@@ -257,6 +271,62 @@ int[] cursor = connection.queryCursorColor(500);
257271
String result = connection.queryOsc(oscCode, "?", 500, responseParser);
258272
```
259273

274+
#### Batch Color Queries
275+
276+
For better performance when querying multiple colors, use batch queries. This reduces latency from O(n × timeout) to O(timeout) by sending all queries at once:
277+
278+
```java
279+
import org.aesh.terminal.tty.TerminalColorDetector;
280+
import org.aesh.terminal.utils.ANSI;
281+
282+
// Query foreground, background, and cursor in one operation (~50-100ms vs ~600ms)
283+
Map<Integer, int[]> colors = TerminalColorDetector.queryColors(connection, 500);
284+
285+
int[] fg = colors.get(ANSI.OSC_FOREGROUND); // OSC 10
286+
int[] bg = colors.get(ANSI.OSC_BACKGROUND); // OSC 11
287+
int[] cursor = colors.get(ANSI.OSC_CURSOR_COLOR); // OSC 12
288+
289+
// Query multiple palette colors at once
290+
Map<Integer, int[]> palette = TerminalColorDetector.queryPaletteColors(
291+
connection, 500, 0, 1, 2, 3, 4, 5, 6, 7);
292+
293+
// Query all 16 ANSI colors
294+
Map<Integer, int[]> ansi16 = TerminalColorDetector.queryAnsi16Colors(connection, 500);
295+
```
296+
297+
#### Fallback When OSC Not Supported
298+
299+
Not all terminals support OSC queries. Use `queryColorsWithFallback()` for graceful degradation:
300+
301+
```java
302+
// Always returns colors - actual or estimated based on environment
303+
Map<Integer, int[]> colors = TerminalColorDetector.queryColorsWithFallback(connection, 500);
304+
305+
int[] bg = colors.get(ANSI.OSC_BACKGROUND);
306+
// bg is never null - will be estimated if OSC queries failed
307+
308+
// Check if it's a dark theme
309+
boolean isDark = TerminalColorDetector.isDarkColor(bg);
310+
```
311+
312+
You can also check support before querying:
313+
314+
```java
315+
// Check if OSC queries are supported
316+
if (TerminalColorDetector.isOscColorQuerySupported(connection)) {
317+
// OSC queries will work
318+
Map<Integer, int[]> colors = TerminalColorDetector.queryColors(connection, 500);
319+
} else {
320+
// Use environment-based detection
321+
TerminalTheme theme = TerminalColorDetector.detectThemeFromEnvironment();
322+
}
323+
324+
// Check palette query support specifically
325+
if (connection.supportsPaletteQuery()) {
326+
Map<Integer, int[]> palette = TerminalColorDetector.queryAnsi16Colors(connection, 500);
327+
}
328+
```
329+
260330
#### OSC Support Detection with Device Attributes
261331

262332
Use DA1 device attributes to determine if OSC queries are likely to work:

content/docs/readline/connection.md

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ connection.openNonBlocking();
3535

3636
Reads input in a separate thread, allowing the current thread to continue.
3737

38+
#### Checking Reading State
39+
40+
```java
41+
// Check if connection is actively reading
42+
if (connection.reading()) {
43+
// Handler-based queries work (setStdinHandler)
44+
} else {
45+
// Use synchronous methods like queryColorCapability()
46+
}
47+
```
48+
49+
The `reading()` method returns `true` after `openBlocking()` or `openNonBlocking()` is called
50+
and before `close()` is called. This is useful for determining which query methods to use:
51+
- When `reading()` is true: Handler-based methods like `queryTerminal()` work
52+
- When `reading()` is false: Use synchronous methods like `queryColorCapability()`
53+
3854
## Handlers
3955

4056
### Standard Input Handler
@@ -282,6 +298,39 @@ Known terminal limitations:
282298
- **Linux console**: No OSC query support
283299
- **Alacritty**: No OSC 52 (clipboard) support
284300

301+
### Batch OSC Queries
302+
303+
For better performance when querying multiple colors, use batch queries. This sends all queries at once and collects responses together, reducing latency from O(n × timeout) to O(timeout):
304+
305+
```java
306+
// Query foreground, background, and cursor colors in one operation
307+
// Takes ~50-100ms instead of ~300-400ms for individual queries
308+
Map<Integer, int[]> colors = connection.queryColors(500);
309+
310+
int[] fg = colors.get(ANSI.OSC_FOREGROUND); // OSC 10
311+
int[] bg = colors.get(ANSI.OSC_BACKGROUND); // OSC 11
312+
int[] cursor = colors.get(ANSI.OSC_CURSOR_COLOR); // OSC 12
313+
314+
// Query multiple palette colors at once
315+
Map<Integer, int[]> palette = connection.queryPaletteColors(500, 0, 1, 2, 3, 4, 5, 6, 7);
316+
317+
// Query all 16 ANSI colors
318+
Map<Integer, int[]> ansi16 = connection.queryAnsi16Colors(500);
319+
320+
// Generic batch query for any OSC codes
321+
Map<Integer, int[]> results = connection.queryBatchOsc(500, 10, 11, 12);
322+
```
323+
324+
For higher-level access with automatic fallbacks, use `TerminalColorDetector`:
325+
326+
```java
327+
import org.aesh.terminal.tty.TerminalColorDetector;
328+
329+
// Query with automatic fallback to environment-based detection
330+
Map<Integer, int[]> colors = TerminalColorDetector.queryColorsWithFallback(connection, 500);
331+
// Always returns colors - actual if OSC works, estimated if not
332+
```
333+
285334
## Device Attributes (DA1/DA2)
286335

287336
Device Attributes queries allow you to detect terminal capabilities that cannot be determined from terminfo alone.
@@ -407,7 +456,17 @@ if (depth.supportsTrueColor()) {
407456
// Use 256-color palette
408457
}
409458

410-
// Get full color capability info
411-
TerminalColorCapability cap = connection.getColorCapability();
412-
TerminalTheme theme = cap.getTheme();
459+
// Query terminal for full color capability (uses synchronous I/O)
460+
// This can be called BEFORE openBlocking/openNonBlocking
461+
TerminalColorCapability cap = connection.queryColorCapability(500);
462+
if (cap != null) {
463+
TerminalTheme theme = cap.getTheme();
464+
int[] fg = cap.getForegroundRGB();
465+
int[] bg = cap.getBackgroundRGB();
466+
int[] cursor = cap.getCursorRGB();
467+
Map<Integer, int[]> palette = cap.getPaletteColors();
468+
}
469+
470+
// Or use TerminalColorDetector for comprehensive detection with fallbacks
471+
TerminalColorCapability cap = TerminalColorDetector.detect(connection);
413472
```

content/docs/readline/connectivity.md

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ SSH (Secure Shell) provides encrypted, authenticated terminal access. This is th
5555
<dependency>
5656
<groupId>org.aesh</groupId>
5757
<artifactId>aesh-terminal-ssh</artifactId>
58-
<version>2.6</version>
58+
<version>3.1</version>
5959
</dependency>
6060
```
6161

6262
### Gradle Dependency
6363

6464
```groovy
65-
implementation 'org.aesh:aesh-terminal-ssh:2.6'
65+
implementation 'org.aesh:aesh-terminal-ssh:3.1'
6666
```
6767

6868
### Basic SSH Server
@@ -318,7 +318,7 @@ Telnet provides simple, unencrypted terminal access. **Use only for development
318318
<dependency>
319319
<groupId>org.aesh</groupId>
320320
<artifactId>aesh-terminal-telnet</artifactId>
321-
<version>2.6</version>
321+
<version>3.1</version>
322322
</dependency>
323323
```
324324

@@ -398,7 +398,7 @@ The terminal-http module provides:
398398
<dependency>
399399
<groupId>org.aesh</groupId>
400400
<artifactId>terminal-http</artifactId>
401-
<version>3.0</version>
401+
<version>3.1</version>
402402
</dependency>
403403
```
404404

@@ -751,33 +751,59 @@ All remote terminals provide a `Connection` object with the same interface:
751751

752752
```java
753753
public interface Connection {
754-
754+
755755
// Write to terminal
756756
void write(String text);
757757
void write(byte[] bytes);
758758
void write(int[] codepoints);
759-
759+
760760
// Close connection
761761
void close();
762-
762+
763763
// Terminal size
764764
Size size();
765765
void setSizeHandler(Consumer<Size> handler);
766-
766+
767767
// Signal handling
768768
void setSignalHandler(Consumer<Signal> handler);
769-
769+
770770
// Input handling
771771
void setStdinHandler(Consumer<int[]> handler);
772-
772+
773773
// Connection state
774-
boolean isOpen();
775-
774+
boolean reading(); // true when actively reading input
775+
776776
// Session information (SSH)
777777
Session getSession();
778778
}
779779
```
780780

781+
### Connection Reading State
782+
783+
The `reading()` method indicates whether the connection is actively reading input:
784+
785+
```java
786+
private void handleConnection(Connection connection) {
787+
// For remote connections, reading() is true once accepted
788+
if (connection.reading()) {
789+
// Handler-based queries work (setStdinHandler)
790+
connection.setStdinHandler(input -> {
791+
// Process input...
792+
});
793+
}
794+
795+
// Continue with readline...
796+
}
797+
```
798+
799+
For remote connections:
800+
- **SSH**: `reading()` returns `true` after the connection handler is invoked
801+
- **Telnet**: `reading()` returns `true` after binary mode negotiation completes
802+
- **WebSocket**: `reading()` returns `true` after `openBlocking()` or `openNonBlocking()` is called
803+
804+
When `close()` is called, `reading()` returns `false`.
805+
```
806+
781807
### Handling Terminal Resize
782808
783809
```java

content/docs/readline/getting-started.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ Add the following dependency to your Maven project:
1515
<dependency>
1616
<groupId>org.aesh</groupId>
1717
<artifactId>readline</artifactId>
18-
<version>2.6</version>
18+
<version>3.1</version>
1919
</dependency>
2020
```
2121

2222
For Gradle:
2323

2424
```groovy
2525
dependencies {
26-
implementation 'org.aesh:readline:2.6'
26+
implementation 'org.aesh:readline:3.1'
2727
}
2828
```
2929

content/docs/readline/installation.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Add the dependency to your `pom.xml`:
1313
<dependency>
1414
<groupId>org.aesh</groupId>
1515
<artifactId>readline</artifactId>
16-
<version>2.6</version>
16+
<version>3.1</version>
1717
</dependency>
1818
```
1919

@@ -23,7 +23,7 @@ Add the dependency to your `build.gradle`:
2323

2424
```groovy
2525
dependencies {
26-
implementation 'org.aesh:readline:2.6'
26+
implementation 'org.aesh:readline:3.1'
2727
}
2828
```
2929

@@ -47,7 +47,7 @@ mvn clean install
4747
<dependency>
4848
<groupId>org.aesh</groupId>
4949
<artifactId>terminal-ssh</artifactId>
50-
<version>2.6</version>
50+
<version>3.1</version>
5151
</dependency>
5252
```
5353

@@ -57,7 +57,7 @@ mvn clean install
5757
<dependency>
5858
<groupId>org.aesh</groupId>
5959
<artifactId>terminal-telnet</artifactId>
60-
<version>2.6</version>
60+
<version>3.1</version>
6161
</dependency>
6262
```
6363

@@ -67,7 +67,7 @@ mvn clean install
6767
<dependency>
6868
<groupId>org.aesh</groupId>
6969
<artifactId>terminal-http</artifactId>
70-
<version>2.6</version>
70+
<version>3.1</version>
7171
</dependency>
7272
```
7373

0 commit comments

Comments
 (0)