(direction: 1 | -1)
| 458 | } |
| 459 | |
| 460 | private navigateHistory(direction: 1 | -1): void { |
| 461 | this.lastAction = null; |
| 462 | if (this.history.length === 0) return; |
| 463 | |
| 464 | // When entering browse, capture host state up front — before the filter |
| 465 | // runs — so the host's filter can read the browse-entry mode rather than a |
| 466 | // mode that changes as entries are recalled. The captured value is only |
| 467 | // committed to hostHistoryDraft once a matching entry is actually found. |
| 468 | const entering = this.historyIndex === -1; |
| 469 | const pendingHostDraft = entering ? this.onHistoryDraftSave?.() : undefined; |
| 470 | |
| 471 | // Find the next index that passes the filter. Up(-1) increases index, |
| 472 | // Down(1) decreases. The draft (-1) is always reachable; stepping past |
| 473 | // either end is a no-op. |
| 474 | let newIndex = this.historyIndex; |
| 475 | let found = false; |
| 476 | while (true) { |
| 477 | newIndex = newIndex - direction; |
| 478 | if (newIndex === -1) { |
| 479 | found = true; |
| 480 | break; |
| 481 | } |
| 482 | if (newIndex < -1 || newIndex >= this.history.length) { |
| 483 | found = false; |
| 484 | break; |
| 485 | } |
| 486 | const candidate = this.history[newIndex]; |
| 487 | if (!this.historyFilter || (candidate !== undefined && this.historyFilter(candidate))) { |
| 488 | found = true; |
| 489 | break; |
| 490 | } |
| 491 | } |
| 492 | if (!found) return; |
| 493 | |
| 494 | // Capture state when first entering history browsing mode |
| 495 | if (entering && newIndex >= 0) { |
| 496 | this.pushUndoSnapshot(); |
| 497 | this.historyDraft = structuredClone(this.state); |
| 498 | this.hostHistoryDraft = pendingHostDraft; |
| 499 | } |
| 500 | |
| 501 | this.historyIndex = newIndex; |
| 502 | |
| 503 | if (this.historyIndex === -1) { |
| 504 | const draft = this.historyDraft; |
| 505 | this.historyDraft = null; |
| 506 | if (draft) { |
| 507 | this.state = draft; |
| 508 | this.preferredVisualCol = null; |
| 509 | this.snappedFromCursorCol = null; |
| 510 | this.scrollOffset = 0; |
| 511 | if (this.hostHistoryDraft !== undefined) { |
| 512 | this.onHistoryDraftRestore?.(this.hostHistoryDraft); |
| 513 | this.hostHistoryDraft = undefined; |
| 514 | } |
| 515 | if (this.onChange) this.onChange(this.getText()); |
| 516 | } else { |
| 517 | this.setTextInternal(""); |
no test coverage detected