nexrall-code 0.5.173 → 0.5.175

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.
Files changed (2) hide show
  1. package/dist/index.js +249 -79
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -153361,7 +153361,17 @@ function renderInputSlices(line, cursorPos) {
153361
153361
  }
153362
153362
 
153363
153363
  // src/ui/vimMode.ts
153364
- var initialVim = (mode = "insert") => ({ mode, count: "", op: "", reg: { text: "", linewise: false }, undo: [] });
153364
+ var initialVim = (mode = "insert") => ({
153365
+ mode,
153366
+ count: "",
153367
+ op: "",
153368
+ reg: { text: "", linewise: false },
153369
+ undo: [],
153370
+ visual: null,
153371
+ anchor: 0,
153372
+ last: [],
153373
+ pend: []
153374
+ });
153365
153375
  var MAX_UNDO = 100;
153366
153376
  var isSpace2 = (c) => /\s/.test(c);
153367
153377
  function nextWordStart(text, pos) {
@@ -153387,32 +153397,89 @@ function clampNormal(text, pos) {
153387
153397
  return ls;
153388
153398
  return p >= le ? prevGraphemeBoundary(text, le) : p;
153389
153399
  }
153400
+ function visualRange(text, vim, cursor) {
153401
+ if (!vim.visual)
153402
+ return null;
153403
+ const a = clampNormal(text, vim.anchor), b = clampNormal(text, cursor);
153404
+ const lo = Math.min(a, b), hi = Math.max(a, b);
153405
+ if (vim.visual === "line") {
153406
+ const from = lineStart(text, lo);
153407
+ const le = lineEnd(text, hi);
153408
+ return { from, to: le < text.length ? le + 1 : le, linewise: true };
153409
+ }
153410
+ return { from: lo, to: nextGraphemeBoundary(text, hi) };
153411
+ }
153412
+ function tokenToKey(tok) {
153413
+ if (tok === "<Esc>")
153414
+ return { char: "", key: { escape: true } };
153415
+ if (tok === "<BS>")
153416
+ return { char: "", key: { backspace: true } };
153417
+ return { char: tok, key: {} };
153418
+ }
153419
+ function replayKeys(text, cursor, vim, keys, n) {
153420
+ let t2 = text, c = cursor, v = vim;
153421
+ for (let i2 = 0; i2 < n; i2++) {
153422
+ for (const tok of keys) {
153423
+ const { char, key } = tokenToKey(tok);
153424
+ const r2 = handleVimKey(t2, c, v, char, key);
153425
+ t2 = r2.text;
153426
+ c = r2.cursor;
153427
+ v = r2.vim;
153428
+ if (!r2.handled && v.mode === "insert") {
153429
+ if (key.backspace) {
153430
+ const p = prevGraphemeBoundary(t2, c);
153431
+ t2 = t2.slice(0, p) + t2.slice(c);
153432
+ c = p;
153433
+ } else if (char) {
153434
+ t2 = t2.slice(0, c) + char + t2.slice(c);
153435
+ c += char.length;
153436
+ }
153437
+ }
153438
+ }
153439
+ }
153440
+ return { text: t2, cursor: c, vim: v };
153441
+ }
153390
153442
  function handleVimKey(text, cursor, vim, char, key) {
153391
153443
  const pass = (v = vim) => ({ text, cursor, vim: v, handled: false });
153392
153444
  const done = (t2, c, v) => ({ text: t2, cursor: c, vim: v, handled: true });
153445
+ const push2 = (v, tok) => ({ ...v, pend: [...v.pend, tok] });
153446
+ const commit = (v) => ({ ...v, last: v.pend, pend: [] });
153447
+ const noChange = (v) => ({ ...v, pend: [] });
153393
153448
  if (vim.mode === "insert") {
153394
153449
  if (key.escape) {
153395
153450
  const c = cursor > 0 ? prevGraphemeBoundary(text, cursor) : 0;
153396
- return done(text, clampNormal(text, c), { ...vim, mode: "normal", count: "", op: "" });
153451
+ const closed = {
153452
+ ...vim,
153453
+ mode: "normal",
153454
+ count: "",
153455
+ op: "",
153456
+ last: vim.pend.length ? [...vim.pend, "<Esc>"] : vim.last,
153457
+ pend: []
153458
+ };
153459
+ return done(text, clampNormal(text, c), closed);
153397
153460
  }
153398
- return pass();
153461
+ const typed = !key.ctrl && !key.meta && !key.return && !key.tab && !key.escape && !key.delete && (key.backspace || char.length > 0 && char.length <= 2);
153462
+ const v = typed ? push2(vim, key.backspace ? "<BS>" : char) : vim;
153463
+ return pass(v);
153399
153464
  }
153400
153465
  if (key.escape) {
153466
+ if (vim.visual)
153467
+ return done(text, clampNormal(text, cursor), { ...vim, visual: null, count: "", op: "", pend: [] });
153401
153468
  if (!vim.count && !vim.op)
153402
153469
  return pass();
153403
- return done(text, clampNormal(text, cursor), { ...vim, count: "", op: "" });
153470
+ return done(text, clampNormal(text, cursor), { ...vim, count: "", op: "", pend: [] });
153404
153471
  }
153405
153472
  if (key.ctrl || key.meta)
153406
153473
  return pass();
153407
153474
  if (key.return || key.tab || key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.delete)
153408
153475
  return pass();
153409
153476
  if (key.backspace)
153410
- return done(text, clampNormal(text, prevGraphemeBoundary(text, cursor)), { ...vim, count: "", op: "" });
153477
+ return done(text, clampNormal(text, prevGraphemeBoundary(text, cursor)), noChange({ ...vim, count: "", op: "" }));
153411
153478
  if (!char || char.length > 2)
153412
153479
  return pass();
153413
153480
  const pos = clampNormal(text, cursor);
153414
153481
  if (/^[1-9]$/.test(char) || char === "0" && vim.count)
153415
- return done(text, pos, { ...vim, count: vim.count + char });
153482
+ return done(text, pos, push2({ ...vim, count: vim.count + char }, char));
153416
153483
  const n = vim.count ? Math.min(parseInt(vim.count, 10), 999) : 1;
153417
153484
  const clear = { ...vim, count: "", op: "" };
153418
153485
  const pushUndo = (v) => ({ ...v, undo: [...v.undo, { text, cursor: pos }].slice(-MAX_UNDO) });
@@ -153449,9 +153516,69 @@ function handleVimKey(text, cursor, vim, char, key) {
153449
153516
  return null;
153450
153517
  }
153451
153518
  };
153519
+ const vertical = (dir) => {
153520
+ let p = pos;
153521
+ for (let i2 = 0; i2 < n && p !== null; i2++) {
153522
+ const nx = moveVertical({ text, cursor: p }, dir);
153523
+ if (nx === null) {
153524
+ if (i2 === 0)
153525
+ return null;
153526
+ break;
153527
+ }
153528
+ p = nx;
153529
+ }
153530
+ return p === null ? null : clampNormal(text, p);
153531
+ };
153532
+ const cut = (from, to, linewise) => {
153533
+ let nt = text.slice(0, from) + text.slice(to);
153534
+ let nc = from;
153535
+ if (linewise && nt.length && to >= text.length && from > 0) {
153536
+ nt = nt.slice(0, from - 1);
153537
+ nc = lineStart(nt, from - 1);
153538
+ }
153539
+ return { text: nt, cursor: clampNormal(nt, nc) };
153540
+ };
153541
+ if (vim.visual) {
153542
+ const mv = motion(char);
153543
+ if (mv !== null)
153544
+ return done(text, clampNormal(text, mv), noChange(clear));
153545
+ if (char === "j" || char === "k") {
153546
+ const p = vertical(char === "j" ? 1 : -1);
153547
+ if (p === null)
153548
+ return pass(noChange(clear));
153549
+ return done(text, p, noChange(clear));
153550
+ }
153551
+ if (char === "v" || char === "V") {
153552
+ const want = char === "v" ? "char" : "line";
153553
+ return done(text, pos, { ...clear, visual: vim.visual === want ? null : want, pend: [] });
153554
+ }
153555
+ const sel = visualRange(text, vim, pos);
153556
+ const removed = text.slice(sel.from, sel.to);
153557
+ const reg = { text: removed, linewise: !!sel.linewise };
153558
+ if (char === "y")
153559
+ return done(text, clampNormal(text, sel.from), noChange({ ...clear, visual: null, reg }));
153560
+ if (char === "d" || char === "x" || char === "c") {
153561
+ const base = pushUndo({ ...clear, visual: null, reg });
153562
+ const { text: nt, cursor: nc } = cut(sel.from, sel.to, !!sel.linewise);
153563
+ if (char === "c") {
153564
+ const keep = sel.linewise && removed.endsWith("\n") ? "\n" : "";
153565
+ const wt = text.slice(0, sel.from) + keep + text.slice(sel.to);
153566
+ return done(wt, sel.from, { ...base, mode: "insert" });
153567
+ }
153568
+ return done(nt, nc, noChange(base));
153569
+ }
153570
+ if ((char === "p" || char === "P") && vim.reg.text) {
153571
+ const base = pushUndo({ ...clear, visual: null });
153572
+ const body = vim.reg.linewise ? vim.reg.text.replace(/\n$/, "") : vim.reg.text;
153573
+ const nt = text.slice(0, sel.from) + body + text.slice(sel.to);
153574
+ return done(nt, clampNormal(nt, sel.from + Math.max(0, body.length - 1)), noChange(base));
153575
+ }
153576
+ return done(text, pos, noChange(clear));
153577
+ }
153452
153578
  if (vim.op) {
153453
153579
  const op = vim.op;
153454
153580
  let r2 = null;
153581
+ let seq = "";
153455
153582
  if (char === op) {
153456
153583
  let end = pos;
153457
153584
  for (let i2 = 0; i2 < n; i2++) {
@@ -153461,153 +153588,158 @@ function handleVimKey(text, cursor, vim, char, key) {
153461
153588
  break;
153462
153589
  }
153463
153590
  r2 = { from: lineStart(text, pos), to: end, linewise: true };
153591
+ seq = char;
153464
153592
  } else if (char === "w" && op === "c") {
153465
153593
  const e2 = repeat((p) => wordLastChar(text, p));
153466
153594
  r2 = { from: pos, to: nextGraphemeBoundary(text, e2) };
153595
+ seq = char;
153467
153596
  } else {
153468
153597
  const m3 = motion(char);
153469
153598
  if (m3 !== null) {
153470
153599
  const inclusive = char === "e";
153471
- const to2 = m3;
153472
- r2 = to2 >= pos ? { from: pos, to: inclusive ? nextGraphemeBoundary(text, to2) : to2 } : { from: to2, to: pos };
153600
+ const to = m3;
153601
+ r2 = to >= pos ? { from: pos, to: inclusive ? nextGraphemeBoundary(text, to) : to } : { from: to, to: pos };
153602
+ seq = char;
153473
153603
  }
153474
153604
  }
153605
+ const recorded = vim.count ? push2(push2(vim, vim.count), seq) : push2(vim, seq);
153475
153606
  if (!r2)
153476
- return done(text, pos, clear);
153477
- let { from, to } = r2;
153478
- if (from === to)
153479
- return done(text, pos, clear);
153480
- const removed = text.slice(from, to);
153481
- const reg = { text: removed, linewise: !!r2.linewise };
153607
+ return done(text, pos, noChange(clear));
153608
+ if (r2.from === r2.to)
153609
+ return done(text, pos, noChange(clear));
153610
+ const removed2 = text.slice(r2.from, r2.to);
153611
+ const opend = { ...clear, visual: null, reg: { text: removed2, linewise: !!r2.linewise }, pend: recorded.pend };
153482
153612
  if (op === "y")
153483
- return done(text, from === pos ? pos : clampNormal(text, from), { ...clear, reg });
153484
- let nt = text.slice(0, from) + text.slice(to);
153485
- let nc = from;
153486
- if (r2.linewise && op === "d" && nt.length && to >= text.length && from > 0) {
153487
- nt = nt.slice(0, from - 1);
153488
- nc = lineStart(nt, from - 1);
153489
- }
153490
- if (r2.linewise && op === "c") {
153491
- const keep = removed.endsWith("\n") ? "\n" : "";
153492
- nt = text.slice(0, from) + keep + text.slice(to);
153493
- nc = from;
153613
+ return done(text, r2.from === pos ? pos : clampNormal(text, r2.from), noChange(opend));
153614
+ const { text: nt, cursor: nc } = cut(r2.from, r2.to, !!r2.linewise);
153615
+ if (op === "c") {
153616
+ const keep = r2.linewise && removed2.endsWith("\n") ? "\n" : "";
153617
+ const wt = text.slice(0, r2.from) + keep + text.slice(r2.to);
153618
+ return done(wt, r2.from, { ...pushUndo(opend), mode: "insert" });
153494
153619
  }
153495
- const base = pushUndo({ ...clear, reg });
153496
- if (op === "c")
153497
- return done(nt, nc, { ...base, mode: "insert" });
153498
- return done(nt, clampNormal(nt, nc), base);
153620
+ return done(nt, nc, noChange(commit(pushUndo(opend))));
153499
153621
  }
153500
153622
  const m2 = motion(char);
153501
153623
  if (m2 !== null)
153502
- return done(text, clampNormal(text, m2), clear);
153624
+ return done(text, clampNormal(text, m2), noChange(clear));
153503
153625
  if (char === "j" || char === "k") {
153504
- const dir = char === "j" ? 1 : -1;
153505
- let p = pos;
153506
- for (let i2 = 0; i2 < n && p !== null; i2++) {
153507
- const nx = moveVertical({ text, cursor: p }, dir);
153508
- if (nx === null) {
153509
- if (i2 === 0)
153510
- return pass(clear);
153511
- break;
153512
- }
153513
- p = nx;
153514
- }
153515
- return done(text, clampNormal(text, p ?? pos), clear);
153626
+ const p = vertical(char === "j" ? 1 : -1);
153627
+ if (p === null)
153628
+ return pass(noChange(clear));
153629
+ return done(text, p, noChange(clear));
153516
153630
  }
153517
153631
  switch (char) {
153518
153632
  case "d":
153519
153633
  case "c":
153520
153634
  case "y":
153521
- return done(text, pos, { ...vim, op: char, count: vim.count });
153635
+ return done(text, pos, push2({ ...vim, op: char, count: vim.count }, char));
153636
+ case ".": {
153637
+ if (!vim.last.length)
153638
+ return done(text, pos, noChange(clear));
153639
+ const rep = replayKeys(text, pos, { ...clear, last: vim.last, pend: [] }, vim.last, n);
153640
+ return done(rep.text, clampNormal(rep.text, rep.cursor), { ...rep.vim, last: vim.last, pend: [] });
153641
+ }
153642
+ case "v":
153643
+ case "V":
153644
+ return done(text, pos, noChange({ ...clear, visual: char === "v" ? "char" : "line", anchor: pos }));
153522
153645
  case "i":
153523
- return done(text, pos, { ...pushUndo(clear), mode: "insert" });
153646
+ return done(text, pos, push2({ ...pushUndo(clear), mode: "insert" }, char));
153524
153647
  case "a":
153525
- return done(text, text.length && lineEnd(text, pos) > pos ? nextGraphemeBoundary(text, pos) : pos, { ...pushUndo(clear), mode: "insert" });
153648
+ return done(text, text.length && lineEnd(text, pos) > pos ? nextGraphemeBoundary(text, pos) : pos, push2({ ...pushUndo(clear), mode: "insert" }, char));
153526
153649
  case "I": {
153527
153650
  let p = lineStart(text, pos);
153528
153651
  const e2 = lineEnd(text, pos);
153529
153652
  while (p < e2 && isSpace2(text[p]))
153530
153653
  p++;
153531
- return done(text, p, { ...pushUndo(clear), mode: "insert" });
153654
+ return done(text, p, push2({ ...pushUndo(clear), mode: "insert" }, char));
153532
153655
  }
153533
153656
  case "A":
153534
- return done(text, lineEnd(text, pos), { ...pushUndo(clear), mode: "insert" });
153657
+ return done(text, lineEnd(text, pos), push2({ ...pushUndo(clear), mode: "insert" }, char));
153535
153658
  case "o": {
153536
153659
  const e2 = lineEnd(text, pos);
153537
- return done(text.slice(0, e2) + "\n" + text.slice(e2), e2 + 1, { ...pushUndo(clear), mode: "insert" });
153660
+ return done(text.slice(0, e2) + "\n" + text.slice(e2), e2 + 1, push2({ ...pushUndo(clear), mode: "insert" }, char));
153538
153661
  }
153539
153662
  case "O": {
153540
153663
  const s2 = lineStart(text, pos);
153541
- return done(text.slice(0, s2) + "\n" + text.slice(s2), s2, { ...pushUndo(clear), mode: "insert" });
153664
+ return done(text.slice(0, s2) + "\n" + text.slice(s2), s2, push2({ ...pushUndo(clear), mode: "insert" }, char));
153542
153665
  }
153543
153666
  case "x": {
153544
153667
  const e2 = lineEnd(text, pos);
153545
153668
  if (pos >= e2)
153546
- return done(text, pos, clear);
153669
+ return done(text, pos, noChange(clear));
153547
153670
  let to = pos;
153548
153671
  for (let i2 = 0; i2 < n && to < e2; i2++)
153549
153672
  to = nextGraphemeBoundary(text, to);
153550
153673
  const nt = text.slice(0, pos) + text.slice(to);
153551
- return done(nt, clampNormal(nt, pos), { ...pushUndo(clear), reg: { text: text.slice(pos, to), linewise: false } });
153674
+ return done(nt, clampNormal(nt, pos), commit(push2({ ...pushUndo(clear), reg: { text: text.slice(pos, to), linewise: false } }, char)));
153552
153675
  }
153553
153676
  case "X": {
153554
153677
  const s2 = lineStart(text, pos);
153555
153678
  if (pos <= s2)
153556
- return done(text, pos, clear);
153679
+ return done(text, pos, noChange(clear));
153557
153680
  let from = pos;
153558
153681
  for (let i2 = 0; i2 < n && from > s2; i2++)
153559
153682
  from = prevGraphemeBoundary(text, from);
153560
153683
  const nt = text.slice(0, from) + text.slice(pos);
153561
- return done(nt, clampNormal(nt, from), { ...pushUndo(clear), reg: { text: text.slice(from, pos), linewise: false } });
153684
+ return done(nt, clampNormal(nt, from), commit(push2({ ...pushUndo(clear), reg: { text: text.slice(from, pos), linewise: false } }, char)));
153562
153685
  }
153563
153686
  case "D":
153564
153687
  case "C": {
153565
153688
  const e2 = lineEnd(text, pos);
153566
153689
  const nt = text.slice(0, pos) + text.slice(e2);
153567
- const v = { ...pushUndo(clear), reg: { text: text.slice(pos, e2), linewise: false } };
153568
- return char === "C" ? done(nt, pos, { ...v, mode: "insert" }) : done(nt, clampNormal(nt, pos), v);
153690
+ const v = push2({ ...pushUndo(clear), reg: { text: text.slice(pos, e2), linewise: false } }, char);
153691
+ return char === "C" ? done(nt, pos, { ...v, mode: "insert" }) : done(nt, clampNormal(nt, pos), commit(v));
153569
153692
  }
153570
153693
  case "p":
153571
153694
  case "P": {
153572
153695
  if (!vim.reg.text)
153573
- return done(text, pos, clear);
153574
- const v = pushUndo(clear);
153696
+ return done(text, pos, noChange(clear));
153697
+ const v = push2(pushUndo(clear), char);
153575
153698
  if (vim.reg.linewise) {
153576
153699
  const body = vim.reg.text.replace(/\n$/, "");
153577
153700
  if (char === "p") {
153578
153701
  const e2 = lineEnd(text, pos);
153579
153702
  const nt3 = text.slice(0, e2) + "\n" + body + text.slice(e2);
153580
- return done(nt3, clampNormal(nt3, e2 + 1), v);
153703
+ return done(nt3, clampNormal(nt3, e2 + 1), commit(v));
153581
153704
  }
153582
153705
  const s2 = lineStart(text, pos);
153583
153706
  const nt2 = text.slice(0, s2) + body + "\n" + text.slice(s2);
153584
- return done(nt2, clampNormal(nt2, s2), v);
153707
+ return done(nt2, clampNormal(nt2, s2), commit(v));
153585
153708
  }
153586
153709
  const at = char === "p" && text.length && lineEnd(text, pos) > pos ? nextGraphemeBoundary(text, pos) : pos;
153587
153710
  const nt = text.slice(0, at) + vim.reg.text + text.slice(at);
153588
- return done(nt, clampNormal(nt, at + vim.reg.text.length - 1), v);
153711
+ return done(nt, clampNormal(nt, at + vim.reg.text.length - 1), commit(v));
153589
153712
  }
153590
153713
  case "u": {
153591
153714
  const last = vim.undo[vim.undo.length - 1];
153592
153715
  if (!last)
153593
- return done(text, pos, clear);
153594
- return done(last.text, clampNormal(last.text, last.cursor), { ...clear, undo: vim.undo.slice(0, -1) });
153716
+ return done(text, pos, noChange(clear));
153717
+ return done(last.text, clampNormal(last.text, last.cursor), noChange({ ...clear, undo: vim.undo.slice(0, -1) }));
153595
153718
  }
153596
153719
  default:
153597
- return done(text, pos, clear);
153720
+ return done(text, pos, noChange(clear));
153598
153721
  }
153599
153722
  }
153723
+ var INSERT_ENTRY = /* @__PURE__ */ new Set(["i", "a", "I", "A", "o", "O", "C"]);
153600
153724
  function handleVimChunk(text, cursor, vim, chunk, key) {
153601
153725
  const chars = [...chunk];
153602
153726
  const plain = !key.escape && !key.ctrl && !key.meta && !key.return && !key.tab && !key.backspace && !key.delete;
153603
- if (vim.mode !== "normal" || !plain || chars.length < 2 || chars.length > 4)
153727
+ if (vim.mode !== "normal" || !plain || chars.length < 2)
153728
+ return handleVimKey(text, cursor, vim, chunk, key);
153729
+ const insertRun = INSERT_ENTRY.has(chars[0]) && chars.slice(1).every((c2) => c2 >= " " && c2 !== "\x7F");
153730
+ if (chars.length > 4 && !insertRun)
153604
153731
  return handleVimKey(text, cursor, vim, chunk, key);
153605
153732
  let t2 = text, c = cursor, v = vim;
153606
153733
  for (const ch of chars) {
153607
- const r2 = handleVimKey(t2, c, v, ch, {});
153734
+ const esc = ch === "\x1B";
153735
+ const r2 = handleVimKey(t2, c, v, esc ? "" : ch, esc ? { escape: true } : {});
153608
153736
  t2 = r2.text;
153609
153737
  c = r2.cursor;
153610
153738
  v = r2.vim;
153739
+ if (!r2.handled && v.mode === "insert" && !esc) {
153740
+ t2 = t2.slice(0, c) + ch + t2.slice(c);
153741
+ c += ch.length;
153742
+ }
153611
153743
  }
153612
153744
  return { text: t2, cursor: c, vim: v, handled: true };
153613
153745
  }
@@ -157292,21 +157424,25 @@ function rowsOccupied(text, columns = process.stdout.columns || 80) {
157292
157424
  function reserveBlockRows(previous, showing) {
157293
157425
  return Math.max(0, previous, showing);
157294
157426
  }
157295
- function fillerRowCount(rowsAlreadyPrinted, footerTextValue = "", columns = process.stdout.columns ?? 80, rows = process.stdout.rows) {
157427
+ function drainBlockRows(previous, printedRows) {
157428
+ return Math.max(0, previous - Math.max(0, printedRows));
157429
+ }
157430
+ var LIVE_BLOCK_MAX_ROWS = 5;
157431
+ function fillerRowCount(rowsAlreadyPrinted, footerTextValue = "", columns = process.stdout.columns ?? 80, rows = process.stdout.rows, reservedRows = 0, headroom = 2) {
157296
157432
  if (!rows)
157297
157433
  return 0;
157298
157434
  const chromeRows = bottomChromeRows({ footerText: footerTextValue, columns });
157299
- const filler = rows - rowsAlreadyPrinted - chromeRows - 2;
157435
+ const filler = rows - rowsAlreadyPrinted - reservedRows - chromeRows - headroom;
157300
157436
  const MIN_WORTHWHILE_FILLER = 3;
157301
157437
  return filler < MIN_WORTHWHILE_FILLER ? 0 : filler;
157302
157438
  }
157303
- function padToBottom(rowsAlreadyPrinted, footerText2 = "") {
157439
+ function padToBottom(rowsAlreadyPrinted, footerText2 = "", sink = (text) => console.log(text)) {
157304
157440
  if (!process.stdout.isTTY)
157305
157441
  return false;
157306
157442
  const filler = fillerRowCount(rowsAlreadyPrinted, footerText2);
157307
157443
  if (filler <= 0)
157308
157444
  return false;
157309
- console.log("\n".repeat(filler - 1));
157445
+ sink("\n".repeat(filler - 1));
157310
157446
  return true;
157311
157447
  }
157312
157448
  var rowCounter = null;
@@ -168577,6 +168713,7 @@ var App2 = ({ onReady }) => {
168577
168713
  const cursorRef = (0, import_react36.useRef)(0);
168578
168714
  const vimRef = (0, import_react36.useRef)(initialVim("insert"));
168579
168715
  const [vimMode, setVimMode] = (0, import_react36.useState)("insert");
168716
+ const [vimVisual, setVimVisual] = (0, import_react36.useState)(false);
168580
168717
  const setCursorPos = (0, import_react36.useCallback)((next) => {
168581
168718
  const value = typeof next === "function" ? next(cursorRef.current) : next;
168582
168719
  cursorRef.current = value;
@@ -168602,6 +168739,7 @@ var App2 = ({ onReady }) => {
168602
168739
  const menuDismissedRef = (0, import_react36.useRef)(null);
168603
168740
  const menuReserveRef = (0, import_react36.useRef)(0);
168604
168741
  const liveReserveRef = (0, import_react36.useRef)(0);
168742
+ const pendingPrintRowsRef = (0, import_react36.useRef)(0);
168605
168743
  const searchReserveRef = (0, import_react36.useRef)(0);
168606
168744
  const [, bumpMenu] = (0, import_react36.useState)(0);
168607
168745
  const [, setPaintTick] = (0, import_react36.useState)(0);
@@ -168693,7 +168831,16 @@ var App2 = ({ onReady }) => {
168693
168831
  if (opts?.isBanner)
168694
168832
  bannerChunkRef.current = bufferRef.current.length;
168695
168833
  bufferRef.current.append(text);
168696
- setItems((prev) => [...prev, { id: idCounter++, content: text, isBanner: opts?.isBanner }]);
168834
+ if (!opts?.isBanner && !opts?.isFiller && !liveRef.current) {
168835
+ const rows = rowsOccupied(text, process.stdout.columns || 80);
168836
+ const pending = pendingPrintRowsRef.current;
168837
+ const paid = Math.min(pending, rows);
168838
+ pendingPrintRowsRef.current = pending - paid;
168839
+ liveReserveRef.current = drainBlockRows(liveReserveRef.current, rows - paid);
168840
+ }
168841
+ setItems((prev) => {
168842
+ return [...prev, { id: idCounter++, content: text, isBanner: opts?.isBanner, isFiller: opts?.isFiller }];
168843
+ });
168697
168844
  }, []);
168698
168845
  const bannerRegeneratorRef = (0, import_react36.useRef)(null);
168699
168846
  const setBannerRegenerator = (0, import_react36.useCallback)((fn) => {
@@ -168986,6 +169133,8 @@ var App2 = ({ onReady }) => {
168986
169133
  if (r2.handled) {
168987
169134
  if (r2.vim.mode !== vimRef.current.mode)
168988
169135
  setVimMode(r2.vim.mode);
169136
+ if (!!r2.vim.visual !== !!vimRef.current.visual)
169137
+ setVimVisual(!!r2.vim.visual);
168989
169138
  vimRef.current = r2.vim;
168990
169139
  if (r2.text !== lineRef.current)
168991
169140
  setLine(r2.text);
@@ -169389,20 +169538,33 @@ var App2 = ({ onReady }) => {
169389
169538
  ctrlDArmedAtRef.current = null;
169390
169539
  setHintText(null);
169391
169540
  });
169392
- const repadBottomChrome = (0, import_react36.useCallback)(() => {
169541
+ const repadBottomChrome = (0, import_react36.useCallback)((pendingRows = 0) => {
169393
169542
  if (!process.stdout.isTTY)
169394
169543
  return;
169395
169544
  if (fullscreenRef.current)
169396
169545
  return;
169397
- liveReserveRef.current = 0;
169398
169546
  searchReserveRef.current = 0;
169547
+ pendingPrintRowsRef.current = Math.max(0, pendingRows);
169399
169548
  setItems((prev) => {
169549
+ const columns = process.stdout.columns || 80;
169400
169550
  const withoutOldFiller = prev.filter((it) => !it.isFiller);
169401
169551
  const printedRows = withoutOldFiller.reduce(
169402
- (sum, it) => sum + rowsOccupied(it.content, process.stdout.columns || 80),
169552
+ (sum, it) => sum + rowsOccupied(it.content, columns),
169403
169553
  0
169404
169554
  );
169405
- const filler = fillerRowCount(printedRows, footerRef.current ? footerText(footerRef.current) : "");
169555
+ const liveRows = liveRef.current ? rowsOccupied(liveRef.current, columns) : 0;
169556
+ const footer2 = footerRef.current ? footerText(footerRef.current) : "";
169557
+ const slack = fillerRowCount(printedRows, footer2, columns, void 0, liveRows, 1);
169558
+ const seed = Math.min(LIVE_BLOCK_MAX_ROWS, slack);
169559
+ liveReserveRef.current = seed;
169560
+ const filler = fillerRowCount(
169561
+ printedRows,
169562
+ footer2,
169563
+ columns,
169564
+ void 0,
169565
+ Math.max(liveRows, seed) + Math.max(0, pendingRows),
169566
+ 1
169567
+ );
169406
169568
  if (filler <= 0)
169407
169569
  return withoutOldFiller;
169408
169570
  return [...withoutOldFiller, { id: idCounter++, content: fillerContent(filler), isFiller: true }];
@@ -169442,12 +169604,12 @@ var App2 = ({ onReady }) => {
169442
169604
  repadBottomChrome();
169443
169605
  setStaticKey((k) => k + 1);
169444
169606
  }, [repadBottomChrome]);
169445
- const collapseStartupPadding = (0, import_react36.useCallback)(async () => {
169607
+ const collapseStartupPadding = (0, import_react36.useCallback)(async (opts) => {
169446
169608
  if (fullscreenRef.current)
169447
169609
  return;
169448
169610
  await inkInstance?.waitUntilRenderFlush();
169449
169611
  process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
169450
- repadBottomChrome();
169612
+ repadBottomChrome(opts?.pendingRows ?? 0);
169451
169613
  setStaticKey((k) => k + 1);
169452
169614
  }, [repadBottomChrome]);
169453
169615
  const setFullscreen = (0, import_react36.useCallback)(async (on) => {
@@ -169545,6 +169707,7 @@ var App2 = ({ onReady }) => {
169545
169707
  }, []);
169546
169708
  const slices = renderInputSlices(line, cursorPos);
169547
169709
  const shownPrompt = prompt2 ?? (isVimEnabled() && vimMode === "normal" ? paint.yellow("[N] ") : null);
169710
+ const vsel = isVimEnabled() && vimVisual ? visualRange(line, vimRef.current, cursorPos) : null;
169548
169711
  const colorsOn = colorEnabled();
169549
169712
  const inputRowRef = (0, import_react36.useRef)(null);
169550
169713
  const inputMetrics = use_box_metrics_default(inputRowRef);
@@ -169646,7 +169809,7 @@ var App2 = ({ onReady }) => {
169646
169809
  borderRight: false,
169647
169810
  borderDimColor: colorsOn
169648
169811
  }
169649
- ), /* @__PURE__ */ import_react36.default.createElement(Box_default, { ref: inputRowRef }, /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "hard" }, /* @__PURE__ */ import_react36.default.createElement(Text, null, promptFor(shownPrompt)), /* @__PURE__ */ import_react36.default.createElement(Text, null, slices.before), /* @__PURE__ */ import_react36.default.createElement(Text, { inverse: true }, slices.atCursor), /* @__PURE__ */ import_react36.default.createElement(Text, null, slices.after))), /* @__PURE__ */ import_react36.default.createElement(
169812
+ ), /* @__PURE__ */ import_react36.default.createElement(Box_default, { ref: inputRowRef }, /* @__PURE__ */ import_react36.default.createElement(Text, { wrap: "hard" }, /* @__PURE__ */ import_react36.default.createElement(Text, null, promptFor(shownPrompt)), vsel ? /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, /* @__PURE__ */ import_react36.default.createElement(Text, null, line.slice(0, vsel.from)), /* @__PURE__ */ import_react36.default.createElement(Text, { inverse: true }, line.slice(vsel.from, vsel.to)), /* @__PURE__ */ import_react36.default.createElement(Text, null, line.slice(vsel.to))) : /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, /* @__PURE__ */ import_react36.default.createElement(Text, null, slices.before), /* @__PURE__ */ import_react36.default.createElement(Text, { inverse: true }, slices.atCursor), /* @__PURE__ */ import_react36.default.createElement(Text, null, slices.after)))), /* @__PURE__ */ import_react36.default.createElement(
169650
169813
  Box_default,
169651
169814
  {
169652
169815
  borderStyle: "single",
@@ -173738,7 +173901,13 @@ ${text}` : "");
173738
173901
  let startupPadded = false;
173739
173902
  if (interactive) {
173740
173903
  await flushInkFrame();
173741
- startupPadded = padToBottom(stopRowCount(), footerText(currentFooter()));
173904
+ startupPadded = padToBottom(stopRowCount(), footerText(currentFooter()), (text) => {
173905
+ const inkHandle = getInkTerminal();
173906
+ if (inkHandle)
173907
+ inkHandle.print(text, { isFiller: true });
173908
+ else
173909
+ console.log(text);
173910
+ });
173742
173911
  }
173743
173912
  let agentRunning = false;
173744
173913
  const abortSignal = { aborted: false };
@@ -174386,7 +174555,8 @@ ${text}` : "");
174386
174555
  userInput = intent.text;
174387
174556
  if (startupPadded) {
174388
174557
  startupPadded = false;
174389
- await getInkTerminal().collapseStartupPadding();
174558
+ const pendingRows = !userInput.startsWith("/") && parseBang(userInput) === null ? 1 : 0;
174559
+ await getInkTerminal().collapseStartupPadding({ pendingRows });
174390
174560
  }
174391
174561
  if (userInput.startsWith("/")) {
174392
174562
  const parts = userInput.split(/\s+/);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexrall-code",
3
- "version": "0.5.173",
3
+ "version": "0.5.175",
4
4
  "description": "Nexrall Code — AI coding assistant for your terminal (headless agent for scripts, CI and automation)",
5
5
  "keywords": [
6
6
  "ai",