@kolisachint/hoocode-tui 0.5.66 → 0.5.67

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.
@@ -3,7 +3,8 @@ import { decodePrintableKey, matchesKey } from "../keys.js";
3
3
  import { KillRing } from "../kill-ring.js";
4
4
  import { CURSOR_MARKER } from "../tui.js";
5
5
  import { UndoStack } from "../undo-stack.js";
6
- import { getSegmenter, isPunctuationChar, isWhitespaceChar, truncateToWidth, visibleWidth } from "../utils.js";
6
+ import { getSegmenter, isPunctuationChar, isWhitespaceChar, visibleWidth } from "../utils.js";
7
+ import { DEFAULT_FRAME_BORDER_CHARS, renderFrameEdge, } from "./frame.js";
7
8
  import { SelectList } from "./select-list.js";
8
9
  const baseSegmenter = getSegmenter();
9
10
  /** Regex matching paste markers like `[paste #1 +123 lines]` or `[paste #2 1234 chars]`. */
@@ -170,23 +171,7 @@ export function wordWrapLine(line, maxWidth, preSegmented) {
170
171
  }
171
172
  return chunks;
172
173
  }
173
- export const DEFAULT_EDITOR_BORDER_CHARS = {
174
- horizontal: "─",
175
- vertical: "│",
176
- topLeft: "┌",
177
- topRight: "┐",
178
- bottomLeft: "└",
179
- bottomRight: "┘",
180
- };
181
- /** Border cells kept between the label and the top-right corner, so it reads as inset rather than jammed. */
182
- const LABEL_RIGHT_INSET = 2;
183
- /**
184
- * Border cells required to the *left* of the label. Below this the label is
185
- * dropped rather than drawn: a label butting straight up against the scroll
186
- * indicator reads as one run-on string, and a border with no run of border in it
187
- * has stopped looking like a border.
188
- */
189
- const MIN_LABEL_LEAD_IN = 4;
174
+ export const DEFAULT_EDITOR_BORDER_CHARS = DEFAULT_FRAME_BORDER_CHARS;
190
175
  const SLASH_COMMAND_SELECT_LIST_LAYOUT = {
191
176
  minPrimaryColumnWidth: 12,
192
177
  maxPrimaryColumnWidth: 32,
@@ -385,45 +370,23 @@ export class Editor {
385
370
  * @param box - Whether to draw corners
386
371
  */
387
372
  renderBorder(edge, hidden, barWidth, box) {
388
- const chars = this.borderChars;
389
- let indicator = "";
390
- if (hidden > 0) {
391
- const arrow = edge === "top" ? "↑" : "↓";
392
- indicator = `${chars.horizontal.repeat(3)} ${arrow} ${hidden} more `;
393
- }
394
- const indicatorWidth = visibleWidth(indicator);
395
- // The label rides on the top border only, and yields to the scroll
396
- // indicator: the indicator says the text is longer than the box, which the
397
- // reader needs *now*, while the label says which session this is, which
398
- // they can also read in the footer.
399
- const label = edge === "top" ? this.topBorderLabel : undefined;
400
- const leadIn = label ? barWidth - indicatorWidth - visibleWidth(label.plain) - LABEL_RIGHT_INSET : -1;
401
- let bar;
402
- if (label && leadIn >= MIN_LABEL_LEAD_IN) {
403
- bar =
404
- this.borderColor(indicator + chars.horizontal.repeat(leadIn)) +
405
- label.styled +
406
- this.borderColor(chars.horizontal.repeat(LABEL_RIGHT_INSET));
407
- }
408
- else if (indicatorWidth > 0) {
409
- const remaining = barWidth - indicatorWidth;
410
- bar = this.borderColor(remaining >= 0 ? indicator + chars.horizontal.repeat(remaining) : truncateToWidth(indicator, barWidth));
411
- }
412
- else {
413
- bar = this.borderColor(chars.horizontal.repeat(barWidth));
414
- }
415
- if (!box)
416
- return bar;
417
- // Corners must stay aligned, so pad back any width lost to truncation.
418
- bar += this.borderColor(chars.horizontal.repeat(Math.max(0, barWidth - visibleWidth(bar))));
419
- const left = edge === "top" ? chars.topLeft : chars.bottomLeft;
420
- const right = edge === "top" ? chars.topRight : chars.bottomRight;
421
- return this.borderColor(left) + bar + this.borderColor(right);
373
+ return renderFrameEdge({
374
+ edge,
375
+ barWidth,
376
+ box,
377
+ chars: this.borderChars,
378
+ color: this.borderColor,
379
+ label: this.topBorderLabel,
380
+ hidden,
381
+ });
422
382
  }
423
383
  render(width) {
424
384
  // Box mode needs 2 columns for the side borders plus at least 1 content
425
385
  // column; below that it degrades to rule mode rather than overflowing.
426
386
  const box = this.border === "box" && width >= 4;
387
+ // `none` is for an editor nested in a frame that already rules it: the
388
+ // rows are the same, the two horizontals are simply not drawn.
389
+ const bare = this.border === "none";
427
390
  const borderWidth = box ? 1 : 0;
428
391
  const innerWidth = Math.max(1, width - borderWidth * 2);
429
392
  const maxPadding = Math.max(0, Math.floor((innerWidth - 1) / 2));
@@ -466,7 +429,8 @@ export class Editor {
466
429
  const leftPadding = " ".repeat(paddingX);
467
430
  const rightPadding = leftPadding;
468
431
  // Render top border (with scroll indicator if scrolled down)
469
- result.push(this.renderBorder("top", this.scrollOffset, barWidth, box));
432
+ if (!bare)
433
+ result.push(this.renderBorder("top", this.scrollOffset, barWidth, box));
470
434
  // Render each visible layout line
471
435
  // Emit hardware cursor marker only when focused and not showing autocomplete
472
436
  const emitCursorMarker = this.focused && !this.autocompleteState;
@@ -516,7 +480,8 @@ export class Editor {
516
480
  }
517
481
  // Render bottom border (with scroll indicator if more content below)
518
482
  const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);
519
- result.push(this.renderBorder("bottom", linesBelow, barWidth, box));
483
+ if (!bare)
484
+ result.push(this.renderBorder("bottom", linesBelow, barWidth, box));
520
485
  // Add autocomplete list if active
521
486
  if (this.autocompleteState && this.autocompleteList) {
522
487
  const autocompleteResult = this.autocompleteList.render(contentWidth);