@youtyan/code-viewer 0.6.9 → 0.6.10

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/web/app.js CHANGED
@@ -8494,6 +8494,9 @@ ${frontmatter.yaml}
8494
8494
  let ANNOTATIONS = { version: 1, sessions: [] };
8495
8495
  let annotationFollow = deps.getAnnotationFollow();
8496
8496
  let activeAnnotationId = null;
8497
+ let refreshAnnotationsInFlight = null;
8498
+ let inlineAnnotationsMounted = false;
8499
+ let databaseAnnotationsMounted = false;
8497
8500
  let annotationPanelDismissed = false;
8498
8501
  let activeSessionId = new URLSearchParams(window.location.search).get(ANNOTATION_SESSION_PARAM);
8499
8502
  const annotationsChangedCallbacks = [];
@@ -8658,9 +8661,12 @@ ${frontmatter.yaml}
8658
8661
  return box;
8659
8662
  }
8660
8663
  function applyDatabaseAnnotations(session) {
8661
- document.querySelectorAll(".gdp-db-annotation-strip").forEach((el) => {
8662
- el.remove();
8663
- });
8664
+ if (databaseAnnotationsMounted) {
8665
+ document.querySelectorAll(".gdp-db-annotation-strip").forEach((el) => {
8666
+ el.remove();
8667
+ });
8668
+ databaseAnnotationsMounted = false;
8669
+ }
8664
8670
  if (!session || deps.getRoute().screen !== "database")
8665
8671
  return;
8666
8672
  const matches = session.entries.filter(databaseAnnotationMatchesRoute);
@@ -8676,6 +8682,7 @@ ${frontmatter.yaml}
8676
8682
  strip.appendChild(buildDatabaseAnnotationBlock(entry));
8677
8683
  }
8678
8684
  root.prepend(strip);
8685
+ databaseAnnotationsMounted = true;
8679
8686
  }
8680
8687
  function inlineAnnotationTargetRow(entry) {
8681
8688
  if (!entry.line)
@@ -8734,13 +8741,19 @@ ${frontmatter.yaml}
8734
8741
  return tr;
8735
8742
  }
8736
8743
  function applyInlineAnnotations() {
8737
- document.querySelectorAll(".gdp-annotation-row").forEach((row) => {
8738
- row.remove();
8739
- });
8740
8744
  const session = ANNOTATIONS.sessions.find((s2) => s2.id === activeSessionId);
8745
+ if (!session && !inlineAnnotationsMounted && !databaseAnnotationsMounted)
8746
+ return;
8747
+ if (inlineAnnotationsMounted) {
8748
+ document.querySelectorAll(".gdp-annotation-row").forEach((row) => {
8749
+ row.remove();
8750
+ });
8751
+ inlineAnnotationsMounted = false;
8752
+ }
8741
8753
  applyDatabaseAnnotations(session);
8742
8754
  if (!session)
8743
8755
  return;
8756
+ let mountedInlineRows = false;
8744
8757
  for (const entry of session.entries) {
8745
8758
  if (entry.target?.kind === "database")
8746
8759
  continue;
@@ -8758,7 +8771,9 @@ ${frontmatter.yaml}
8758
8771
  sibAnchor = sibAnchor.nextElementSibling;
8759
8772
  sibAnchor.after(buildInlineSpacerRow(entry, sibling.cells.length));
8760
8773
  }
8774
+ mountedInlineRows = true;
8761
8775
  }
8776
+ inlineAnnotationsMounted = mountedInlineRows;
8762
8777
  syncInlineAnnotationWidths();
8763
8778
  }
8764
8779
  function syncInlineAnnotationSpacerHeights() {
@@ -8883,7 +8898,17 @@ ${frontmatter.yaml}
8883
8898
  annotationCountEl.hidden = total === 0;
8884
8899
  annotationListCountEl.textContent = `${ANNOTATIONS.sessions.length} sessions / ${total} annotations`;
8885
8900
  }
8886
- async function refreshAnnotations() {
8901
+ function refreshAnnotations() {
8902
+ if (refreshAnnotationsInFlight)
8903
+ return refreshAnnotationsInFlight;
8904
+ const started = doRefreshAnnotations().finally(() => {
8905
+ if (refreshAnnotationsInFlight === started)
8906
+ refreshAnnotationsInFlight = null;
8907
+ });
8908
+ refreshAnnotationsInFlight = started;
8909
+ return started;
8910
+ }
8911
+ async function doRefreshAnnotations() {
8887
8912
  try {
8888
8913
  const res = await fetch("/_annotations");
8889
8914
  if (!res.ok)
@@ -16386,6 +16411,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16386
16411
  var ROW_HEIGHT = 28;
16387
16412
  var OVERSCAN = 20;
16388
16413
  var PAGE_SIZE = 200;
16414
+ var MAX_PAGE_CACHE_PAGES = 32;
16389
16415
  var FILTER_DEBOUNCE_MS = 300;
16390
16416
  var DEFAULT_COL_WIDTH = 180;
16391
16417
  var CELL_PREVIEW_MAX_CHARS = 4000;
@@ -16520,9 +16546,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16520
16546
  const filteredEmpty = document.createElement("div");
16521
16547
  filteredEmpty.className = "db-pane-empty";
16522
16548
  filteredEmpty.hidden = true;
16523
- const filteredEmptyIcon = document.createElement("div");
16524
- filteredEmptyIcon.className = "db-pane-empty-icon";
16525
- filteredEmptyIcon.innerHTML = iconSvg("octicon-search", SEARCH_16_PATH);
16526
16549
  const filteredEmptyTitle = document.createElement("div");
16527
16550
  filteredEmptyTitle.className = "db-pane-empty-title";
16528
16551
  const filteredEmptyHint = document.createElement("div");
@@ -16542,7 +16565,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16542
16565
  filteredEmptyAction.hidden = true;
16543
16566
  filteredEmptyAction.disabled = true;
16544
16567
  filteredEmptyActions.append(filteredEmptyReloadAction, filteredEmptyAction);
16545
- filteredEmpty.append(filteredEmptyIcon, filteredEmptyTitle, filteredEmptyHint, filteredEmptyActions);
16568
+ filteredEmpty.append(filteredEmptyTitle, filteredEmptyHint, filteredEmptyActions);
16546
16569
  const detailPanel = document.createElement("div");
16547
16570
  detailPanel.className = "db-grid-detail-panel";
16548
16571
  detailPanel.hidden = true;
@@ -16563,13 +16586,34 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16563
16586
  function setActiveCell(rowIndex, colIndex) {
16564
16587
  activeCellRowIndex = rowIndex;
16565
16588
  activeCellColIndex = colIndex;
16566
- for (const c2 of body.querySelectorAll(".db-grid-cell-active")) {
16567
- c2.classList.remove("db-grid-cell-active");
16589
+ if (activeCellElement?.isConnected) {
16590
+ activeCellElement.classList.remove("db-grid-cell-active");
16591
+ } else {
16592
+ for (const c2 of body.querySelectorAll(".db-grid-cell-active")) {
16593
+ c2.classList.remove("db-grid-cell-active");
16594
+ }
16568
16595
  }
16596
+ activeCellElement = null;
16569
16597
  if (rowIndex < 0 || colIndex < 0)
16570
16598
  return;
16571
16599
  const targetRow = body.children[rowIndex - renderStartRow];
16572
- targetRow?.children[colIndex + 1]?.classList.add("db-grid-cell-active");
16600
+ const targetCell = targetRow?.children[colIndex + 1];
16601
+ if (!targetCell)
16602
+ return;
16603
+ targetCell.classList.add("db-grid-cell-active");
16604
+ activeCellElement = targetCell;
16605
+ }
16606
+ function setSelectedRow(rowIndex, row) {
16607
+ selectedRowIndex = rowIndex;
16608
+ if (selectedRowElement?.isConnected) {
16609
+ selectedRowElement.classList.remove("selected");
16610
+ } else {
16611
+ body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
16612
+ r2.classList.remove("selected");
16613
+ });
16614
+ }
16615
+ selectedRowElement = row;
16616
+ row?.classList.add("selected");
16573
16617
  }
16574
16618
  function clearActiveCell() {
16575
16619
  setActiveCell(-1, -1);
@@ -16631,8 +16675,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16631
16675
  let isRefreshing = false;
16632
16676
  let filterTimer = null;
16633
16677
  let selectedRowIndex = -1;
16678
+ let selectedRowElement = null;
16634
16679
  let activeCellRowIndex = -1;
16635
16680
  let activeCellColIndex = -1;
16681
+ let activeCellElement = null;
16636
16682
  let renderStartRow = 0;
16637
16683
  const fkColumns = new Set;
16638
16684
  let editMode = false;
@@ -16815,6 +16861,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16815
16861
  }
16816
16862
  function resetSelectionAndDetail() {
16817
16863
  selectedRowIndex = -1;
16864
+ selectedRowElement = null;
16818
16865
  detailPanel.hidden = true;
16819
16866
  clearDetailContent();
16820
16867
  }
@@ -16910,6 +16957,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
16910
16957
  statusEl?.remove();
16911
16958
  statusEl = null;
16912
16959
  selectedRowIndex = -1;
16960
+ selectedRowElement = null;
16961
+ activeCellElement = null;
16913
16962
  closeExportMenu();
16914
16963
  hideRelatedPanel();
16915
16964
  detailPanel.hidden = true;
@@ -17433,7 +17482,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17433
17482
  renderViewport();
17434
17483
  }
17435
17484
  function ensurePage(pageStart) {
17436
- if (pageCache.has(pageStart))
17485
+ if (getCachedPage(pageStart) !== undefined)
17437
17486
  return Promise.resolve();
17438
17487
  const pending = pendingPages.get(pageStart);
17439
17488
  if (pending)
@@ -17444,7 +17493,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17444
17493
  const promise = callbacks.fetchPage(currentTable, pageStart, PAGE_SIZE, sort, filters, signal).then((data) => {
17445
17494
  if (gen !== loadGeneration)
17446
17495
  return;
17447
- pageCache.set(pageStart, data.rows);
17496
+ rememberPage(pageStart, data.rows);
17448
17497
  totalRows = data.totalRows;
17449
17498
  syncSpacer();
17450
17499
  updateStatus();
@@ -17464,6 +17513,24 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17464
17513
  pendingPages.set(pageStart, tracked);
17465
17514
  return tracked;
17466
17515
  }
17516
+ function rememberPage(pageStart, rows) {
17517
+ pageCache.delete(pageStart);
17518
+ pageCache.set(pageStart, rows);
17519
+ while (pageCache.size > MAX_PAGE_CACHE_PAGES) {
17520
+ const oldest = pageCache.keys().next().value;
17521
+ if (oldest === undefined)
17522
+ break;
17523
+ pageCache.delete(oldest);
17524
+ }
17525
+ }
17526
+ function getCachedPage(pageStart) {
17527
+ const rows = pageCache.get(pageStart);
17528
+ if (rows === undefined)
17529
+ return;
17530
+ pageCache.delete(pageStart);
17531
+ pageCache.set(pageStart, rows);
17532
+ return rows;
17533
+ }
17467
17534
  function buildEditableCell(colIndex, value, opts) {
17468
17535
  const cell = document.createElement("div");
17469
17536
  cell.className = "db-grid-cell db-grid-cell-edit";
@@ -17545,14 +17612,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17545
17612
  }
17546
17613
  function buildDataRow(i2) {
17547
17614
  const pageStart = Math.floor(i2 / PAGE_SIZE) * PAGE_SIZE;
17548
- const pageRows = pageCache.get(pageStart);
17615
+ const pageRows = getCachedPage(pageStart);
17549
17616
  const rowData = pageRows ? pageRows[i2 - pageStart] : null;
17550
17617
  const row = document.createElement("div");
17551
17618
  row.className = "db-grid-row";
17552
17619
  if (i2 % 2 === 1)
17553
17620
  row.classList.add("alt");
17554
- if (i2 === selectedRowIndex)
17621
+ if (i2 === selectedRowIndex) {
17555
17622
  row.classList.add("selected");
17623
+ selectedRowElement = row;
17624
+ }
17556
17625
  const rowIndex = i2;
17557
17626
  const rowNum = document.createElement("div");
17558
17627
  rowNum.className = "db-grid-cell db-grid-rownum";
@@ -17601,11 +17670,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17601
17670
  const fkClickable = fkColumns.has(cellColName) && (!embedded || !!callbacks.onForeignKeyCellClick);
17602
17671
  const isEditingThisCell = !ro && i2 === editingCellRow && c2 === editingCellCol;
17603
17672
  const activate = () => {
17604
- selectedRowIndex = rowIndex;
17605
- body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
17606
- r2.classList.remove("selected");
17607
- });
17608
- row.classList.add("selected");
17673
+ setSelectedRow(rowIndex, row);
17609
17674
  setActiveCell(rowIndex, cellColIndex);
17610
17675
  if (fkClickable) {
17611
17676
  if (embedded) {
@@ -17656,17 +17721,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17656
17721
  }
17657
17722
  if (!isEditingThisCell && i2 === activeCellRowIndex && c2 === activeCellColIndex) {
17658
17723
  cellEl.classList.add("db-grid-cell-active");
17724
+ activeCellElement = cellEl;
17659
17725
  }
17660
17726
  row.appendChild(cellEl);
17661
17727
  }
17662
17728
  return row;
17663
17729
  }
17664
17730
  row.addEventListener("click", () => {
17665
- selectedRowIndex = rowIndex;
17666
- body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
17667
- r2.classList.remove("selected");
17668
- });
17669
- row.classList.add("selected");
17731
+ setSelectedRow(rowIndex, row);
17670
17732
  });
17671
17733
  for (let c2 = 0;c2 < columnNames.length; c2++) {
17672
17734
  const cell = document.createElement("div");
@@ -17691,11 +17753,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17691
17753
  }
17692
17754
  cell.addEventListener("click", (e2) => {
17693
17755
  e2.stopPropagation();
17694
- selectedRowIndex = rowIndex;
17695
- body.querySelectorAll(".db-grid-row.selected").forEach((r2) => {
17696
- r2.classList.remove("selected");
17697
- });
17698
- row.classList.add("selected");
17756
+ setSelectedRow(rowIndex, row);
17699
17757
  setActiveCell(rowIndex, cellColIndex);
17700
17758
  if (fkClickable) {
17701
17759
  if (embedded) {
@@ -17709,6 +17767,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17709
17767
  });
17710
17768
  if (i2 === activeCellRowIndex && c2 === activeCellColIndex) {
17711
17769
  cell.classList.add("db-grid-cell-active");
17770
+ activeCellElement = cell;
17712
17771
  }
17713
17772
  row.appendChild(cell);
17714
17773
  }
@@ -17780,6 +17839,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17780
17839
  };
17781
17840
  }
17782
17841
  body.innerHTML = "";
17842
+ selectedRowElement = null;
17843
+ activeCellElement = null;
17783
17844
  body.style.transform = `translateY(${startRow * ROW_HEIGHT}px)`;
17784
17845
  for (let i2 = startRow;i2 < endRow; i2++) {
17785
17846
  body.appendChild(i2 < totalRows ? buildDataRow(i2) : buildDraftRow(i2 - totalRows));
@@ -17861,7 +17922,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
17861
17922
  columns = initialData.columns;
17862
17923
  columnNames = columns.map((c2) => c2.name);
17863
17924
  totalRows = initialData.totalRows;
17864
- pageCache.set(0, initialData.rows);
17925
+ rememberPage(0, initialData.rows);
17865
17926
  } else {
17866
17927
  columns = [];
17867
17928
  columnNames = [];
@@ -21620,7 +21681,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21620
21681
  const card = document.querySelector(diffCardSelector(path));
21621
21682
  if (!card?.classList.contains("pending"))
21622
21683
  return;
21623
- const f2 = STATE.files.find((x) => x.path === path);
21684
+ const f2 = card._file || STATE.files.find((x) => x.path === path);
21624
21685
  if (!f2)
21625
21686
  return;
21626
21687
  enqueueLoad(f2, card, 5);
@@ -21692,7 +21753,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21692
21753
  };
21693
21754
  window.addEventListener("scrollend", onEnd, { once: true });
21694
21755
  if (card.classList.contains("pending")) {
21695
- const f2 = STATE.files.find((x) => x.path === path);
21756
+ const f2 = card._file || STATE.files.find((x) => x.path === path);
21696
21757
  if (f2)
21697
21758
  enqueueLoad(f2, card, 10);
21698
21759
  }
@@ -21761,7 +21822,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21761
21822
  const card = entry.target;
21762
21823
  if (card.classList.contains("loaded") || card.classList.contains("loading"))
21763
21824
  continue;
21764
- const f2 = STATE.files.find((x) => x.path === card.dataset.path);
21825
+ const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
21765
21826
  if (f2)
21766
21827
  enqueueLoad(f2, card, 0);
21767
21828
  }
@@ -21829,7 +21890,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21829
21890
  delete card.dataset.manualMode;
21830
21891
  card.style.minHeight = `${file.estimated_height_px || 80}px`;
21831
21892
  card._diffData = null;
21832
- card._file = null;
21893
+ card._file = file;
21833
21894
  }
21834
21895
  function renderShell(meta, changedPaths) {
21835
21896
  const newFiles = meta.files || [];
@@ -21995,6 +22056,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21995
22056
  card.dataset.key = f2.key || f2.path;
21996
22057
  card.dataset.sizeClass = f2.size_class || "small";
21997
22058
  card.dataset.status = f2.status || "M";
22059
+ card._file = f2;
21998
22060
  card.classList.toggle("viewed", STATE.viewedFiles.has(f2.path));
21999
22061
  if (f2.estimated_height_px) {
22000
22062
  card.style.minHeight = `${f2.estimated_height_px}px`;
@@ -22018,7 +22080,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22018
22080
  const card = entry.target;
22019
22081
  if (card.classList.contains("loaded") || card.classList.contains("loading"))
22020
22082
  return;
22021
- const f2 = STATE.files.find((x) => x.path === card.dataset.path);
22083
+ const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
22022
22084
  if (!f2)
22023
22085
  return;
22024
22086
  enqueueLoad(f2, card, 0);
@@ -22034,7 +22096,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22034
22096
  const rect = card.getBoundingClientRect();
22035
22097
  if (rect.top > viewportBottom)
22036
22098
  return;
22037
- const f2 = STATE.files.find((x) => x.path === card.dataset.path);
22099
+ const f2 = card._file || STATE.files.find((x) => x.path === card.dataset.path);
22038
22100
  if (f2)
22039
22101
  enqueueLoad(f2, card, 0);
22040
22102
  });
@@ -22182,11 +22244,15 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22182
22244
  card.classList.add("pending");
22183
22245
  if (indicator)
22184
22246
  indicator.hidden = true;
22185
- const fresh = STATE.files.find((x) => x.path === card.dataset.path);
22247
+ const fresh = card._file || STATE.files.find((x) => x.path === card.dataset.path);
22186
22248
  if (fresh && card.isConnected)
22187
22249
  enqueueLoad(fresh, card, 0);
22188
22250
  };
22189
- return trackLoad(fetch(url).then((r2) => r2.json())).then(async (data) => {
22251
+ return trackLoad(fetch(url).then(async (r2) => {
22252
+ if (!r2.ok)
22253
+ throw new Error(await r2.text());
22254
+ return r2.json();
22255
+ })).then(async (data) => {
22190
22256
  if (String(myReq) !== card.dataset.reqId)
22191
22257
  return;
22192
22258
  if (myGen !== getServerGeneration()) {
@@ -22227,7 +22293,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22227
22293
  return false;
22228
22294
  if (card.classList.contains("loaded"))
22229
22295
  return true;
22230
- const file = STATE.files.find((x) => x.path === path);
22296
+ const file = card._file || STATE.files.find((x) => x.path === path);
22231
22297
  if (!file)
22232
22298
  return false;
22233
22299
  await loadFile(file, card, undefined, { immediate: true });
@@ -22253,17 +22319,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22253
22319
  matching: "lines",
22254
22320
  outputFormat: layout,
22255
22321
  synchronisedScroll: true,
22256
- highlight: !!(STATE.syntaxHighlight && file.highlight && hljsRef),
22322
+ highlight: false,
22257
22323
  fileListToggle: false,
22258
22324
  fileContentToggle: false
22259
22325
  }, hljsRef);
22260
22326
  ui.draw();
22261
22327
  if (STATE.ignoreWs)
22262
22328
  suppressWhitespaceOnlyInlineHighlights(body);
22263
- if (STATE.syntaxHighlight && file.highlight && hljsRef && typeof ui.highlightCode === "function") {
22264
- ui.highlightCode();
22265
- highlightPlaintextSpans(card, file);
22266
- }
22267
22329
  enhanceMediaCard(file, card);
22268
22330
  syncSideScrollCard(card);
22269
22331
  appendStatSquaresToHeader(card, file);
@@ -22592,10 +22654,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22592
22654
  const spans = card.querySelectorAll("tr.gdp-inserted-ctx .d2h-code-line-ctn:not([data-gdp-hl])");
22593
22655
  highlightDiffSpans(file, spans);
22594
22656
  }
22595
- function highlightPlaintextSpans(card, file) {
22596
- const spans = card.querySelectorAll(".d2h-code-line-ctn.hljs.plaintext:not([data-gdp-hl])");
22597
- highlightDiffSpans(file, spans);
22598
- }
22599
22657
  function highlightDiffSpans(file, spans, deadline) {
22600
22658
  if (file.size_class === "huge")
22601
22659
  return true;
@@ -22626,8 +22684,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22626
22684
  return true;
22627
22685
  }
22628
22686
  function scheduleIdleHighlight(card, file) {
22629
- if (file.highlight)
22630
- return;
22631
22687
  if (file.size_class === "huge")
22632
22688
  return;
22633
22689
  if (!STATE.syntaxHighlight)
@@ -22683,14 +22739,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22683
22739
  for (const w of cards) {
22684
22740
  const r2 = w.getBoundingClientRect();
22685
22741
  if (r2.top <= scanY && r2.bottom > scanY) {
22686
- const text2 = w.dataset.path || "";
22687
- let best = null, bestLen = 0;
22688
- STATE.files.forEach((f2) => {
22689
- if ((text2 === f2.path || text2.endsWith(f2.path)) && f2.path.length > bestLen) {
22690
- best = f2.path;
22691
- bestLen = f2.path.length;
22692
- }
22693
- });
22742
+ const best = w.dataset.path || "";
22694
22743
  if (best) {
22695
22744
  markActive(best);
22696
22745
  const recentlyTouched = performance.now() - (window.__gdpSidebarTouchedAt || 0) < 1500;
@@ -23275,6 +23324,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23275
23324
  let generation = 0;
23276
23325
  let selectionGeneration = 0;
23277
23326
  let selectedSha = "";
23327
+ let activeHistoryRow = null;
23278
23328
  let query = "";
23279
23329
  let mode = "history";
23280
23330
  let routeRef = "HEAD";
@@ -23387,6 +23437,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23387
23437
  return absolute;
23388
23438
  return `${relative} (${absolute})`;
23389
23439
  }
23440
+ function historyItemSelector(sha) {
23441
+ const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(sha) : sha.replace(/["\\]/g, "\\$&");
23442
+ return `.history-item[data-sha="${escaped}"]`;
23443
+ }
23390
23444
  function fetchPage(skip, requestGeneration) {
23391
23445
  const params = new URLSearchParams;
23392
23446
  params.set("ref", ref);
@@ -23440,6 +23494,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23440
23494
  html.push(commitRow(commit));
23441
23495
  }
23442
23496
  list2.innerHTML = html.join("");
23497
+ activeHistoryRow = list2.querySelector(".history-item.active");
23443
23498
  syncRefreshStatusText();
23444
23499
  }
23445
23500
  function syncRefreshButton(button) {
@@ -23527,9 +23582,15 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23527
23582
  info.hidden = false;
23528
23583
  }
23529
23584
  function updateActiveRow() {
23530
- list2.querySelectorAll(".history-item").forEach((row) => {
23531
- row.classList.toggle("active", row.dataset.sha === selectedSha);
23532
- });
23585
+ if (activeHistoryRow && (!("isConnected" in activeHistoryRow) || activeHistoryRow.isConnected)) {
23586
+ activeHistoryRow.classList.remove("active");
23587
+ } else {
23588
+ list2.querySelectorAll(".history-item.active").forEach((row) => {
23589
+ row.classList.remove("active");
23590
+ });
23591
+ }
23592
+ activeHistoryRow = selectedSha ? list2.querySelector(historyItemSelector(selectedSha)) : null;
23593
+ activeHistoryRow?.classList.add("active");
23533
23594
  }
23534
23595
  function isEditableTarget(target) {
23535
23596
  return typeof Element === "function" && target instanceof Element && !!target.closest('input, textarea, select, button, [contenteditable="true"]');
@@ -23720,8 +23781,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23720
23781
  scrollToSelected();
23721
23782
  }
23722
23783
  function scrollToSelected() {
23723
- const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(selectedSha) : selectedSha.replace(/["\\]/g, "\\$&");
23724
- list2.querySelector(`.history-item[data-sha="${escaped}"]`)?.scrollIntoView({ block: "center" });
23784
+ list2.querySelector(historyItemSelector(selectedSha))?.scrollIntoView({ block: "center" });
23725
23785
  }
23726
23786
  let entering = Promise.resolve();
23727
23787
  function enterHistory(options = {}) {
@@ -23797,6 +23857,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
23797
23857
  generation++;
23798
23858
  loading = false;
23799
23859
  inFlight = null;
23860
+ if (filterTimer) {
23861
+ clearTimeout(filterTimer);
23862
+ filterTimer = undefined;
23863
+ }
23800
23864
  selectionGeneration++;
23801
23865
  selectedSha = "";
23802
23866
  setBanner("");
@@ -31385,11 +31449,106 @@ code-viewer query agent-help`
31385
31449
  const match2 = computeFuzzyMatch(query, path);
31386
31450
  return match2 ? { score: match2.score, ranges: match2.ranges } : null;
31387
31451
  }
31388
- function rankFuzzyPaths(query, items) {
31389
- return items.map((item) => {
31452
+ function rankFuzzyPaths(query, items, limit) {
31453
+ const bounded = Number.isInteger(limit) && limit !== undefined && limit > 0 ? Math.floor(limit) : 0;
31454
+ const compare = (a2, b2) => b2.tier - a2.tier || b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
31455
+ if (!bounded) {
31456
+ return items.map((item) => {
31457
+ const match2 = computeFuzzyMatch(query, item.path);
31458
+ return match2 ? { item, score: match2.score, ranges: match2.ranges, tier: match2.tier } : null;
31459
+ }).filter((item) => item !== null).sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
31460
+ }
31461
+ const top = [];
31462
+ for (const item of items) {
31390
31463
  const match2 = computeFuzzyMatch(query, item.path);
31391
- return match2 ? { item, score: match2.score, ranges: match2.ranges, tier: match2.tier } : null;
31392
- }).filter((item) => item !== null).sort((a2, b2) => b2.tier - a2.tier || b2.score - a2.score || a2.item.path.localeCompare(b2.item.path)).map(({ item, score, ranges }) => ({ item, score, ranges }));
31464
+ if (!match2)
31465
+ continue;
31466
+ const ranked = {
31467
+ item,
31468
+ score: match2.score,
31469
+ ranges: match2.ranges,
31470
+ tier: match2.tier
31471
+ };
31472
+ pushBoundedTop(top, ranked, bounded, compare);
31473
+ }
31474
+ return top.sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
31475
+ }
31476
+ function pushBoundedTop(heap, item, limit, compareBestFirst) {
31477
+ const isWorse = (a2, b2) => compareBestFirst(a2, b2) > 0;
31478
+ const siftUp = (index) => {
31479
+ while (index > 0) {
31480
+ const parent = Math.floor((index - 1) / 2);
31481
+ if (!isWorse(heap[index], heap[parent]))
31482
+ break;
31483
+ [heap[index], heap[parent]] = [heap[parent], heap[index]];
31484
+ index = parent;
31485
+ }
31486
+ };
31487
+ const siftDown = (index) => {
31488
+ while (true) {
31489
+ const left = index * 2 + 1;
31490
+ const right = left + 1;
31491
+ let worst = index;
31492
+ if (left < heap.length && isWorse(heap[left], heap[worst]))
31493
+ worst = left;
31494
+ if (right < heap.length && isWorse(heap[right], heap[worst]))
31495
+ worst = right;
31496
+ if (worst === index)
31497
+ break;
31498
+ [heap[index], heap[worst]] = [heap[worst], heap[index]];
31499
+ index = worst;
31500
+ }
31501
+ };
31502
+ if (heap.length < limit) {
31503
+ heap.push(item);
31504
+ siftUp(heap.length - 1);
31505
+ return;
31506
+ }
31507
+ if (compareBestFirst(item, heap[0]) >= 0)
31508
+ return;
31509
+ heap[0] = item;
31510
+ siftDown(0);
31511
+ }
31512
+ function rankGlobPathMatches(query, items, limit) {
31513
+ const matchPath = createGlobPathMatcher(query);
31514
+ if (!matchPath)
31515
+ return [];
31516
+ const bounded = Number.isInteger(limit) && limit !== undefined && limit > 0 ? Math.floor(limit) : 0;
31517
+ const compare = (a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
31518
+ if (!bounded) {
31519
+ return items.map((item) => {
31520
+ const match2 = matchPath(item.path);
31521
+ return match2 ? {
31522
+ item,
31523
+ score: match2.score,
31524
+ ranges: match2.ranges,
31525
+ mode: "glob"
31526
+ } : null;
31527
+ }).filter((item) => item !== null).sort(compare);
31528
+ }
31529
+ const top = [];
31530
+ for (const item of items) {
31531
+ const match2 = matchPath(item.path);
31532
+ if (!match2)
31533
+ continue;
31534
+ const ranked = {
31535
+ item,
31536
+ score: match2.score,
31537
+ ranges: match2.ranges,
31538
+ mode: "glob"
31539
+ };
31540
+ pushBoundedTop(top, ranked, bounded, compare);
31541
+ }
31542
+ return top.sort(compare);
31543
+ }
31544
+ function rankPathMatches(query, items, limit) {
31545
+ if (isGlobPathQuery(query)) {
31546
+ return rankGlobPathMatches(query, items, limit);
31547
+ }
31548
+ return rankFuzzyPaths(query, items, limit).map((item) => ({
31549
+ ...item,
31550
+ mode: "fuzzy"
31551
+ }));
31393
31552
  }
31394
31553
  function isGlobPathQuery(query) {
31395
31554
  return /[*?]/.test(query.trim());
@@ -31434,48 +31593,39 @@ code-viewer query agent-help`
31434
31593
  }
31435
31594
  }
31436
31595
  function globMatchPath(query, path) {
31596
+ return createGlobPathMatcher(query)?.(path) ?? null;
31597
+ }
31598
+ function createGlobPathMatcher(query) {
31437
31599
  const regex = globToRegExp(query);
31438
- const baseStart = basenameStart(path);
31439
- const basename = path.slice(baseStart);
31440
- if (!regex || !regex.test(path) && (query.includes("/") || !regex.test(basename)))
31600
+ if (!regex)
31441
31601
  return null;
31442
31602
  const literal = query.replace(/[*?[\]]+/g, " ").trim().split(/\s+/).filter(Boolean);
31443
- const ranges = [];
31444
- const lowerPath = path.toLowerCase();
31445
- for (const part of literal) {
31446
- const start = lowerPath.indexOf(part.toLowerCase());
31447
- if (start >= 0)
31448
- ranges.push({ start, end: start + part.length });
31449
- }
31450
- ranges.sort((a2, b2) => a2.start - b2.start || a2.end - b2.end);
31451
- const mergedRanges = [];
31452
- for (const range of ranges) {
31453
- const last = mergedRanges[mergedRanges.length - 1];
31454
- if (last && last.end >= range.start) {
31455
- last.end = Math.max(last.end, range.end);
31456
- } else {
31457
- mergedRanges.push({ ...range });
31603
+ const suffix = query.replace(/^\*+/, "").toLowerCase();
31604
+ return (path) => {
31605
+ const baseStart = basenameStart(path);
31606
+ const basename = path.slice(baseStart);
31607
+ if (!regex.test(path) && (query.includes("/") || !regex.test(basename)))
31608
+ return null;
31609
+ const ranges = [];
31610
+ const lowerPath = path.toLowerCase();
31611
+ for (const part of literal) {
31612
+ const start = lowerPath.indexOf(part.toLowerCase());
31613
+ if (start >= 0)
31614
+ ranges.push({ start, end: start + part.length });
31615
+ }
31616
+ ranges.sort((a2, b2) => a2.start - b2.start || a2.end - b2.end);
31617
+ const mergedRanges = [];
31618
+ for (const range of ranges) {
31619
+ const last = mergedRanges[mergedRanges.length - 1];
31620
+ if (last && last.end >= range.start) {
31621
+ last.end = Math.max(last.end, range.end);
31622
+ } else {
31623
+ mergedRanges.push({ ...range });
31624
+ }
31458
31625
  }
31459
- }
31460
- const score = 1000 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(query.replace(/^\*+/, "").toLowerCase()) ? 50 : 0);
31461
- return { score, ranges: mergedRanges };
31462
- }
31463
- function rankPathMatches(query, items) {
31464
- if (isGlobPathQuery(query)) {
31465
- return items.map((item) => {
31466
- const match2 = globMatchPath(query, item.path);
31467
- return match2 ? {
31468
- item,
31469
- score: match2.score,
31470
- ranges: match2.ranges,
31471
- mode: "glob"
31472
- } : null;
31473
- }).filter((item) => item !== null).sort((a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path));
31474
- }
31475
- return rankFuzzyPaths(query, items).map((item) => ({
31476
- ...item,
31477
- mode: "fuzzy"
31478
- }));
31626
+ const score = 1000 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(suffix) ? 50 : 0);
31627
+ return { score, ranges: mergedRanges };
31628
+ };
31479
31629
  }
31480
31630
 
31481
31631
  // web-src/core/search-palette.ts
@@ -31773,7 +31923,7 @@ code-viewer query agent-help`
31773
31923
  const response = await repoPaletteFiles(ref);
31774
31924
  if (PALETTE !== state || state.input.value !== query)
31775
31925
  return;
31776
- state.items = limitPaletteResults(rankPathMatches(query, response.files)).map((match2) => ({
31926
+ state.items = limitPaletteResults(rankPathMatches(query, response.files, PALETTE_RESULT_LIMIT)).map((match2) => ({
31777
31927
  kind: "file",
31778
31928
  path: match2.item.path,
31779
31929
  displayPath: match2.item.path,
@@ -31855,6 +32005,8 @@ code-viewer query agent-help`
31855
32005
  const query = state.input.value;
31856
32006
  if (state.mode === "file") {
31857
32007
  updateFilePalette(state, query).catch(() => {
32008
+ if (PALETTE !== state || state.input.value !== query)
32009
+ return;
31858
32010
  state.status.textContent = "Search failed";
31859
32011
  });
31860
32012
  } else {
@@ -31998,12 +32150,13 @@ code-viewer query agent-help`
31998
32150
  let sourceShikiLoadPromise = null;
31999
32151
  let PREFERRED_SOURCE_TAB = null;
32000
32152
  let SOURCE_CURSOR = null;
32153
+ let SOURCE_CURSOR_ROWS = [];
32001
32154
  const SOURCE_CURSOR_TOTALS = new Map;
32002
32155
  function sourceLineScrollAmount() {
32003
- const virtualRow = Array.from(document.querySelectorAll("#content .gdp-source-virtual-row")).find((item) => item.offsetParent !== null);
32156
+ const virtualRow = document.querySelector("#content .gdp-source-virtual:not([hidden]) .gdp-source-virtual-row");
32004
32157
  if (virtualRow)
32005
32158
  return virtualRow.getBoundingClientRect().height || VIRTUAL_SOURCE_ROW_HEIGHT;
32006
- const sourceRow = Array.from(document.querySelectorAll("#content .gdp-source-table tr")).find((item) => item.offsetParent !== null);
32159
+ const sourceRow = document.querySelector("#content .gdp-source-table:not([hidden]) tr");
32007
32160
  if (sourceRow)
32008
32161
  return sourceRow.getBoundingClientRect().height || 20;
32009
32162
  const preview = document.querySelector("#content .gdp-markdown-preview:not([hidden])");
@@ -32020,10 +32173,32 @@ code-viewer query agent-help`
32020
32173
  return !!SOURCE_CURSOR && sourceTargetsEqual(SOURCE_CURSOR.target, target) && SOURCE_CURSOR.line === line;
32021
32174
  }
32022
32175
  function syncSourceCursorRows(target) {
32023
- document.querySelectorAll("#content [data-line]").forEach((row) => {
32024
- const line = Number(row.dataset.line || "0");
32025
- row.classList.toggle("gdp-source-cursor", sourceCursorMatches(target, line));
32026
- });
32176
+ if (SOURCE_CURSOR_ROWS.length === 0 || SOURCE_CURSOR_ROWS.every((row) => !row.isConnected)) {
32177
+ SOURCE_CURSOR_ROWS = Array.from(document.querySelectorAll("#content .gdp-source-table tr.gdp-source-cursor, #content .gdp-source-virtual-row.gdp-source-cursor"));
32178
+ }
32179
+ for (const row of SOURCE_CURSOR_ROWS) {
32180
+ row.classList.remove("gdp-source-cursor");
32181
+ }
32182
+ SOURCE_CURSOR_ROWS = [];
32183
+ if (!SOURCE_CURSOR || !sourceTargetsEqual(SOURCE_CURSOR.target, target))
32184
+ return;
32185
+ const line = String(SOURCE_CURSOR.line);
32186
+ const table2 = document.querySelector("#content .gdp-source-table");
32187
+ const tableRow = table2?.rows[SOURCE_CURSOR.line - 1];
32188
+ if (tableRow?.dataset.line === line) {
32189
+ tableRow.classList.add("gdp-source-cursor");
32190
+ SOURCE_CURSOR_ROWS.push(tableRow);
32191
+ }
32192
+ const windowEl = document.querySelector("#content .gdp-source-virtual-window");
32193
+ if (windowEl) {
32194
+ const firstLine = Number(windowEl.firstElementChild?.dataset.line || "0");
32195
+ const offset = SOURCE_CURSOR.line - firstLine;
32196
+ const row = offset >= 0 ? windowEl.children[offset] : null;
32197
+ if (row?.dataset.line === line) {
32198
+ row.classList.add("gdp-source-cursor");
32199
+ SOURCE_CURSOR_ROWS.push(row);
32200
+ }
32201
+ }
32027
32202
  }
32028
32203
  function visibleSourceLineFallback() {
32029
32204
  const scroller = findMainScrollTarget();
@@ -35546,7 +35721,7 @@ code-viewer query agent-help`
35546
35721
  }
35547
35722
  let SERVER_GENERATION = 0;
35548
35723
  function trackLoad(promise) {
35549
- return NETWORK_ACTIVITY.track(promise);
35724
+ return promise;
35550
35725
  }
35551
35726
  function escapeHtml3(s2) {
35552
35727
  return String(s2 == null ? "" : s2).replace(/[&<>"']/g, (c2) => ({