anveesa 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/package.json +1 -1
- package/src/lib.rs +63 -18
package/Cargo.lock
CHANGED
package/Cargo.toml
CHANGED
package/package.json
CHANGED
package/src/lib.rs
CHANGED
|
@@ -143,15 +143,22 @@ async fn run_interactive(options: AskOptions) -> Result<()> {
|
|
|
143
143
|
|
|
144
144
|
loop {
|
|
145
145
|
print_input_separator(is_tty, width);
|
|
146
|
-
let line
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
let (line, ctrl_v_image) =
|
|
147
|
+
match read_prompt_line(&label, width, &mut paste_count, images_available) {
|
|
148
|
+
Ok(PromptRead::Line(line, img)) => (line, img),
|
|
149
|
+
Ok(PromptRead::Interrupted) => continue,
|
|
150
|
+
Ok(PromptRead::Eof) => {
|
|
151
|
+
println!();
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
Err(error) => return Err(error).context("failed to read interactive prompt"),
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Ctrl+V image takes precedence over a previously pending image.
|
|
158
|
+
if let Some(img) = ctrl_v_image {
|
|
159
|
+
last_image_fp = Some(image_fingerprint(&img));
|
|
160
|
+
pending_image = Some(img);
|
|
161
|
+
}
|
|
155
162
|
|
|
156
163
|
let prompt = line.trim().to_string();
|
|
157
164
|
if prompt.is_empty() {
|
|
@@ -1313,7 +1320,7 @@ fn print_session_header(
|
|
|
1313
1320
|
}
|
|
1314
1321
|
|
|
1315
1322
|
enum PromptRead {
|
|
1316
|
-
Line(String),
|
|
1323
|
+
Line(String, Option<ImageAttachment>),
|
|
1317
1324
|
Interrupted,
|
|
1318
1325
|
Eof,
|
|
1319
1326
|
}
|
|
@@ -1466,13 +1473,28 @@ impl RawPromptMode {
|
|
|
1466
1473
|
}
|
|
1467
1474
|
}
|
|
1468
1475
|
|
|
1469
|
-
fn read_prompt_line(
|
|
1476
|
+
fn read_prompt_line(
|
|
1477
|
+
label: &str,
|
|
1478
|
+
width: usize,
|
|
1479
|
+
paste_count: &mut usize,
|
|
1480
|
+
images_available: bool,
|
|
1481
|
+
) -> Result<PromptRead> {
|
|
1470
1482
|
let _raw_mode = RawPromptMode::enter()?;
|
|
1471
1483
|
let mut input = io::stdin().lock();
|
|
1472
1484
|
let mut buffer = PromptBuffer::default();
|
|
1473
1485
|
let mut display_rows = 1usize;
|
|
1486
|
+
let mut ctrl_v_image: Option<ImageAttachment> = None;
|
|
1487
|
+
|
|
1488
|
+
// Compose the visible prompt label, optionally prefixed with an image indicator.
|
|
1489
|
+
let effective_label = |img: &Option<ImageAttachment>| -> String {
|
|
1490
|
+
if img.is_some() {
|
|
1491
|
+
format!("\x1b[2m[📎]\x1b[0m {label}")
|
|
1492
|
+
} else {
|
|
1493
|
+
label.to_string()
|
|
1494
|
+
}
|
|
1495
|
+
};
|
|
1474
1496
|
|
|
1475
|
-
print!("{
|
|
1497
|
+
print!("{}", effective_label(&ctrl_v_image));
|
|
1476
1498
|
io::stdout().flush().context("failed to write prompt")?;
|
|
1477
1499
|
|
|
1478
1500
|
loop {
|
|
@@ -1484,9 +1506,11 @@ fn read_prompt_line(label: &str, width: usize, paste_count: &mut usize) -> Resul
|
|
|
1484
1506
|
match byte[0] {
|
|
1485
1507
|
b'\r' | b'\n' => {
|
|
1486
1508
|
println!();
|
|
1487
|
-
return Ok(PromptRead::Line(buffer.full));
|
|
1509
|
+
return Ok(PromptRead::Line(buffer.full, ctrl_v_image));
|
|
1488
1510
|
}
|
|
1489
1511
|
3 => {
|
|
1512
|
+
// Ctrl+C — discard any pasted image too
|
|
1513
|
+
ctrl_v_image = None;
|
|
1490
1514
|
println!("^C");
|
|
1491
1515
|
return Ok(PromptRead::Interrupted);
|
|
1492
1516
|
}
|
|
@@ -1494,30 +1518,51 @@ fn read_prompt_line(label: &str, width: usize, paste_count: &mut usize) -> Resul
|
|
|
1494
1518
|
8 | 127 => {
|
|
1495
1519
|
// Backspace
|
|
1496
1520
|
buffer.pop_last();
|
|
1497
|
-
|
|
1521
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1522
|
+
display_rows = redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1498
1523
|
}
|
|
1499
1524
|
21 => {
|
|
1500
1525
|
// Ctrl+U / Cmd+Delete — erase entire line
|
|
1501
1526
|
buffer.clear_all();
|
|
1502
|
-
|
|
1527
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1528
|
+
display_rows = redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1529
|
+
}
|
|
1530
|
+
22 if images_available => {
|
|
1531
|
+
// Ctrl+V — paste image from clipboard
|
|
1532
|
+
match grab_clipboard_image() {
|
|
1533
|
+
Some(img) => {
|
|
1534
|
+
ctrl_v_image = Some(img);
|
|
1535
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1536
|
+
display_rows =
|
|
1537
|
+
redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1538
|
+
}
|
|
1539
|
+
None => {
|
|
1540
|
+
// No image in clipboard — ring the bell
|
|
1541
|
+
print!("\x07");
|
|
1542
|
+
let _ = io::stdout().flush();
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1503
1545
|
}
|
|
1504
1546
|
23 => {
|
|
1505
1547
|
// Ctrl+W / Option+Delete — erase last word
|
|
1506
1548
|
buffer.pop_word();
|
|
1507
|
-
|
|
1549
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1550
|
+
display_rows = redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1508
1551
|
}
|
|
1509
1552
|
0x1b => {
|
|
1510
1553
|
let sequence = read_escape_sequence(&mut input)?;
|
|
1511
1554
|
if sequence == b"[200~" {
|
|
1512
1555
|
let paste = normalize_pasted_text(read_bracketed_paste(&mut input)?);
|
|
1513
1556
|
push_paste(&mut buffer, paste, paste_count);
|
|
1514
|
-
|
|
1557
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1558
|
+
display_rows = redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1515
1559
|
}
|
|
1516
1560
|
}
|
|
1517
1561
|
byte if byte >= 0x20 && byte != 0x7f => {
|
|
1518
1562
|
if let Some(ch) = read_utf8_char(byte, &mut input)? {
|
|
1519
1563
|
buffer.push_text(ch.encode_utf8(&mut [0; 4]));
|
|
1520
|
-
|
|
1564
|
+
let lbl = effective_label(&ctrl_v_image);
|
|
1565
|
+
display_rows = redraw_prompt_line(&lbl, &buffer.display, display_rows, width)?;
|
|
1521
1566
|
}
|
|
1522
1567
|
}
|
|
1523
1568
|
_ => {}
|