Skip to content

Commit 667c679

Browse files
committed
Added more docs for operators, options, selectors, ++
1 parent 1921409 commit 667c679

7 files changed

Lines changed: 1320 additions & 94 deletions

File tree

content/docs/aesh/advanced-topics.md

Lines changed: 83 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -9,92 +9,9 @@ This section covers advanced Æsh features including piping, redirection, aliase
99

1010
## Piping and Redirection
1111

12-
Æsh supports Unix-style command operators for piping output between commands and redirecting to files.
12+
Æsh supports Unix-style command operators for piping output between commands, redirecting to files, and conditional execution (`&&`, `||`, `;`).
1313

14-
### Supported Operators
15-
16-
| Operator | Symbol | Description |
17-
|----------|--------|-------------|
18-
| Pipe | `\|` | Pass output of one command to input of another |
19-
| Redirect Out | `>` | Write output to file (overwrite) |
20-
| Redirect Append | `>>` | Append output to file |
21-
| Redirect In | `<` | Read input from file |
22-
| AND | `&&` | Execute next command if current succeeds |
23-
| OR | `\|\|` | Execute next command if current fails |
24-
| Sequence | `;` | Execute next command unconditionally |
25-
26-
### Enabling Operators
27-
28-
Operators are enabled by default. To configure:
29-
30-
```java
31-
Settings settings = SettingsBuilder.builder()
32-
.enableOperatorParser(true) // Enable operator parsing
33-
.setPipe(true) // Enable pipe operator
34-
.setRedirection(true) // Enable redirection operators
35-
.build();
36-
```
37-
38-
### Implementing Pipeable Commands
39-
40-
Commands that receive piped input should read from `getInputLine()`:
41-
42-
```java
43-
@CommandDefinition(name = "grep", description = "Filter lines matching pattern")
44-
public class GrepCommand implements Command<CommandInvocation> {
45-
46-
@Argument(description = "Pattern to match")
47-
private String pattern;
48-
49-
@Override
50-
public CommandResult execute(CommandInvocation invocation) throws InterruptedException {
51-
String line;
52-
while ((line = invocation.getInputLine()) != null) {
53-
if (line.contains(pattern)) {
54-
invocation.println(line);
55-
}
56-
}
57-
return CommandResult.SUCCESS;
58-
}
59-
}
60-
```
61-
62-
### Example: Command Pipeline
63-
64-
```bash
65-
# List files, filter for .java, count lines
66-
ls | grep ".java" | wc -l
67-
68-
# Process file and save output
69-
cat data.txt | transform | sort > output.txt
70-
71-
# Conditional execution
72-
build && test && deploy
73-
74-
# Execute regardless of result
75-
cleanup ; exit
76-
```
77-
78-
### Checking the Current Operator
79-
80-
Commands can check which operator is in effect:
81-
82-
```java
83-
@Override
84-
public CommandResult execute(CommandInvocation invocation) {
85-
Operator operator = invocation.getOperator();
86-
87-
if (operator == Operator.PIPE) {
88-
// Output will be piped to another command
89-
// Avoid formatting, output raw data
90-
} else {
91-
// Output is going to terminal
92-
// Use formatting and colors
93-
}
94-
95-
return CommandResult.SUCCESS;
96-
}
97-
```
14+
See [Operators](/docs/aesh/operators) for full documentation including all operator types, examples, and how to write operator-aware commands.
9815

9916
## Command Aliases
10017

@@ -573,31 +490,103 @@ Settings settings = SettingsBuilder.builder()
573490
# Set an environment variable
574491
export MY_VAR=value
575492

576-
# Use in commands
493+
# Use in commands (variable references are expanded)
577494
echo $MY_VAR
578495

579-
# List exports
496+
# Chain variables
497+
export BASE=/opt/app
498+
export CONFIG=$BASE/config
499+
500+
# List all exports
580501
export
581502

582503
# Remove export
583504
unset MY_VAR
584505
```
585506

586-
### Accessing Exports Programmatically
507+
### Accessing Exports in Commands
508+
509+
Commands can read exported variables through `AeshContext`:
587510

588511
```java
589512
@Override
590513
public CommandResult execute(CommandInvocation invocation) {
591-
// Access exported variables through configuration
592-
CommandInvocationConfiguration config = invocation.getConfiguration();
593-
594-
// Environment-aware processing
595-
// ...
596-
514+
AeshContext ctx = invocation.getConfiguration().getAeshContext();
515+
516+
// Read a specific variable
517+
String dbHost = ctx.exportedVariable("DB_HOST");
518+
519+
// List all exported variable names
520+
Set<String> names = ctx.exportedVariableNames();
521+
597522
return CommandResult.SUCCESS;
598523
}
599524
```
600525

526+
### Listening for Export Changes
527+
528+
The `ExportChangeListener` interface lets your application react when users set or change exported variables. This is useful for reconfiguring services, updating prompts, or logging configuration changes.
529+
530+
```java
531+
import org.aesh.command.export.ExportChangeListener;
532+
533+
ExportChangeListener listener = (name, value) -> {
534+
System.out.println("Variable changed: " + name + "=" + value);
535+
// Reconfigure services, update state, etc.
536+
};
537+
```
538+
539+
Register the listener through `SettingsBuilder`:
540+
541+
```java
542+
Settings settings = SettingsBuilder.builder()
543+
.enableExport(true)
544+
.exportFile(new File(System.getProperty("user.home"), ".myapp_exports"))
545+
.exportListener(listener)
546+
.build();
547+
```
548+
549+
The listener fires whenever `export NAME=value` is executed successfully. It receives the variable name and its resolved value (with any `$VAR` references expanded).
550+
551+
#### Example: Dynamic Configuration
552+
553+
```java
554+
ExportChangeListener configListener = (name, value) -> {
555+
switch (name) {
556+
case "LOG_LEVEL":
557+
Logger.getGlobal().setLevel(Level.parse(value));
558+
break;
559+
case "OUTPUT_FORMAT":
560+
outputFormatter.setFormat(value);
561+
break;
562+
}
563+
};
564+
565+
Settings settings = SettingsBuilder.builder()
566+
.enableExport(true)
567+
.exportListener(configListener)
568+
.build();
569+
```
570+
571+
```bash
572+
# User changes log level at runtime
573+
$ export LOG_LEVEL=FINE
574+
# Listener fires, log level is updated immediately
575+
```
576+
577+
### System Environment Integration
578+
579+
By default, exports are isolated to the Æsh session. To include the host system's environment variables (read-only) alongside session exports:
580+
581+
```java
582+
SettingsBuilder.builder()
583+
.enableExport(true)
584+
.exportUsesSystemEnvironment(true)
585+
.build();
586+
```
587+
588+
With this enabled, `$HOME`, `$PATH`, and other system variables are accessible in addition to user-defined exports.
589+
601590
## Input Validation
602591

603592
### Command-Level Validation

content/docs/aesh/graphics.md

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
date: '2026-01-11T15:00:00+01:00'
3+
draft: false
4+
title: 'Terminal Graphics'
5+
weight: 22
6+
---
7+
8+
The Graphics API provides primitives for drawing shapes, lines, and text at arbitrary positions in the terminal. It uses ANSI cursor addressing to place content at specific coordinates, with support for colors and the alternate screen buffer.
9+
10+
## Graphics Interface
11+
12+
```java
13+
public interface Graphics {
14+
void flush();
15+
void clear();
16+
void clearAndShowCursor();
17+
18+
TerminalColor getColor();
19+
void setColor(TerminalColor color);
20+
21+
TerminalTextStyle getTextStyle();
22+
void setTextStyle(TerminalTextStyle textStyle);
23+
24+
void drawRect(int x, int y, int width, int height);
25+
void fillRect(int x, int y, int width, int height);
26+
void drawLine(int x1, int y1, int x2, int y2);
27+
void drawCircle(int x, int y, int radius);
28+
void drawString(String str, int x, int y);
29+
}
30+
```
31+
32+
| Method | Description |
33+
|--------|-------------|
34+
| `drawRect(x, y, w, h)` | Draw a rectangle outline at (x, y) with the given width and height |
35+
| `fillRect(x, y, w, h)` | Fill a rectangle with the current background color |
36+
| `drawLine(x1, y1, x2, y2)` | Draw a line between two points |
37+
| `drawCircle(x, y, radius)` | Draw a circle centered at (x, y) |
38+
| `drawString(str, x, y)` | Draw text at position (x, y) |
39+
| `setColor(color)` | Set foreground and background colors for subsequent drawing |
40+
| `clear()` | Clear the entire screen |
41+
| `clearAndShowCursor()` | Clear the screen and restore the cursor |
42+
| `flush()` | Flush pending output to the terminal |
43+
44+
Coordinates are column (x) and row (y), with (0, 0) at the top-left corner of the terminal.
45+
46+
## Setup
47+
48+
Create a `GraphicsConfiguration` from a terminal `Connection`, then obtain a `Graphics` instance:
49+
50+
```java
51+
import org.aesh.graphics.AeshGraphicsConfiguration;
52+
import org.aesh.graphics.Graphics;
53+
import org.aesh.graphics.GraphicsConfiguration;
54+
55+
GraphicsConfiguration gc = new AeshGraphicsConfiguration(connection);
56+
Graphics g = gc.getGraphics();
57+
```
58+
59+
The `GraphicsConfiguration` also provides `getBounds()` to query the terminal size, which is useful for positioning elements relative to the terminal dimensions.
60+
61+
## Example Command
62+
63+
```java
64+
@CommandDefinition(name = "draw", description = "Draw shapes")
65+
public class DrawCommand implements Command<CommandInvocation> {
66+
67+
private final GraphicsConfiguration gc;
68+
69+
public DrawCommand(Connection connection) {
70+
this.gc = new AeshGraphicsConfiguration(connection);
71+
}
72+
73+
@Override
74+
public CommandResult execute(CommandInvocation invocation) {
75+
// Switch to alternate buffer to preserve scroll history
76+
invocation.getShell().enableAlternateBuffer();
77+
78+
Graphics g = gc.getGraphics();
79+
80+
// Blue rectangle
81+
g.setColor(new TerminalColor(Color.BLUE, Color.DEFAULT));
82+
g.drawRect(5, 2, 30, 8);
83+
g.flush();
84+
85+
// Red filled area
86+
g.setColor(new TerminalColor(Color.DEFAULT, Color.RED));
87+
g.fillRect(40, 3, 15, 6);
88+
g.flush();
89+
90+
// Cyan text
91+
g.setColor(new TerminalColor(Color.CYAN, Color.DEFAULT));
92+
g.drawString("Hello from Aesh Graphics!", 10, 12);
93+
g.flush();
94+
95+
// Green circle
96+
g.setColor(new TerminalColor(Color.GREEN, Color.DEFAULT));
97+
g.drawCircle(60, 8, 5);
98+
g.flush();
99+
100+
// Wait for 'q' to exit
101+
try {
102+
while (!invocation.input().equals(Key.q)) {
103+
// wait
104+
}
105+
} catch (InterruptedException ignored) {
106+
}
107+
108+
// Restore terminal
109+
g.clearAndShowCursor();
110+
invocation.getShell().enableMainBuffer();
111+
return CommandResult.SUCCESS;
112+
}
113+
}
114+
```
115+
116+
Register the command with the terminal connection:
117+
118+
```java
119+
TerminalConnection connection = new TerminalConnection(
120+
Charset.defaultCharset(), System.in, System.out, null);
121+
122+
CommandRegistry registry = AeshCommandRegistryBuilder.builder()
123+
.command(new DrawCommand(connection))
124+
.create();
125+
```
126+
127+
## Colors
128+
129+
Use `TerminalColor` to set foreground and background colors:
130+
131+
```java
132+
import org.aesh.terminal.formatting.Color;
133+
import org.aesh.terminal.formatting.TerminalColor;
134+
135+
// Foreground only
136+
g.setColor(new TerminalColor(Color.RED, Color.DEFAULT));
137+
138+
// Both foreground and background
139+
g.setColor(new TerminalColor(Color.WHITE, Color.BLUE));
140+
```
141+
142+
Available colors: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, `WHITE`, `DEFAULT`.
143+
144+
Color changes apply to all subsequent drawing operations until `setColor()` is called again.
145+
146+
## Alternate Screen Buffer
147+
148+
For full-screen graphics, use the alternate screen buffer. This preserves the user's terminal history and restores it when your command finishes:
149+
150+
```java
151+
// Enter alternate buffer
152+
invocation.getShell().enableAlternateBuffer();
153+
154+
// ... draw graphics ...
155+
156+
// Return to main buffer (restores previous content)
157+
invocation.getShell().enableMainBuffer();
158+
```
159+
160+
## Animation
161+
162+
Combine `clear()`, drawing, `flush()`, and `Thread.sleep()` for simple animations:
163+
164+
```java
165+
g.setColor(new TerminalColor(Color.DEFAULT, Color.GREEN));
166+
for (int x = 0; x < 80; x++) {
167+
g.clear();
168+
g.fillRect(x, 10, 10, 5);
169+
g.flush();
170+
Thread.sleep(50);
171+
}
172+
```
173+
174+
## Bounds Checking
175+
176+
The graphics implementation clips drawing to the terminal bounds. Use `GraphicsConfiguration.getBounds()` to adapt your layout to the terminal size:
177+
178+
```java
179+
Size bounds = gc.getBounds();
180+
int centerX = bounds.getWidth() / 2;
181+
int centerY = bounds.getHeight() / 2;
182+
g.drawString("Centered", centerX - 4, centerY);
183+
```

0 commit comments

Comments
 (0)