@youtyan/code-viewer 0.5.4 → 0.6.0
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/README.md +389 -13
- package/dist/code-viewer.js +15568 -9512
- package/package.json +1 -1
- package/skills/code-viewer-query/SKILL.md +159 -14
- package/skills/code-viewer-snapshot/SKILL.md +59 -2
- package/web/app.js +830 -169
- package/web/index.html +1 -1
- package/web/style.css +118 -26
package/web/app.js
CHANGED
|
@@ -400,7 +400,8 @@
|
|
|
400
400
|
{ action: "start-g-sequence", key: "g", scope: "main" },
|
|
401
401
|
{ action: "layout-unified", key: "u" },
|
|
402
402
|
{ action: "layout-split", key: "s" },
|
|
403
|
-
{ action: "toggle-theme", key: "t" }
|
|
403
|
+
{ action: "toggle-theme", key: "t" },
|
|
404
|
+
{ action: "open-help", key: "?", shift: true }
|
|
404
405
|
];
|
|
405
406
|
function resolveKeymapAction(event, context) {
|
|
406
407
|
const key = event.key.toLowerCase();
|
|
@@ -9637,14 +9638,10 @@ ${frontmatter.yaml}
|
|
|
9637
9638
|
calculatingDiff: "Computing diff…",
|
|
9638
9639
|
diffError: "Failed to compute diff",
|
|
9639
9640
|
noChanges: "No changes detected.",
|
|
9640
|
-
before: "Before",
|
|
9641
9641
|
loading: "Loading…",
|
|
9642
9642
|
loadError: "Failed to load",
|
|
9643
9643
|
saveNote: "Save",
|
|
9644
9644
|
noteInputPlaceholder: "Enter a note",
|
|
9645
|
-
inserted: "Added",
|
|
9646
|
-
updated: "Updated",
|
|
9647
|
-
deleted: "Deleted",
|
|
9648
9645
|
tableCount: (n2) => `${n2} tables`,
|
|
9649
9646
|
rowCount: (n2) => ` (${n2})`,
|
|
9650
9647
|
listTitle: (n2) => `Snapshots (${n2})`,
|
|
@@ -9926,14 +9923,10 @@ ${frontmatter.yaml}
|
|
|
9926
9923
|
calculatingDiff: "差分を計算中...",
|
|
9927
9924
|
diffError: "差分の計算に失敗しました",
|
|
9928
9925
|
noChanges: "変更は検出されませんでした。",
|
|
9929
|
-
before: "更新前",
|
|
9930
9926
|
loading: "読み込み中...",
|
|
9931
9927
|
loadError: "読み込みに失敗しました",
|
|
9932
9928
|
saveNote: "保存",
|
|
9933
9929
|
noteInputPlaceholder: "メモを入力",
|
|
9934
|
-
inserted: "追加",
|
|
9935
|
-
updated: "更新",
|
|
9936
|
-
deleted: "削除",
|
|
9937
9930
|
tableCount: (n2) => `${n2}テーブル`,
|
|
9938
9931
|
rowCount: (n2) => ` (${n2}件)`,
|
|
9939
9932
|
listTitle: (n2) => `スナップショット (${n2}件)`,
|
|
@@ -14551,10 +14544,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
14551
14544
|
const getJson = (path) => trackLoad(fetch(path));
|
|
14552
14545
|
const changeTypeLabel = (type) => {
|
|
14553
14546
|
if (type === "inserted")
|
|
14554
|
-
return
|
|
14555
|
-
|
|
14556
|
-
return text2().snapshot.updated;
|
|
14557
|
-
return text2().snapshot.deleted;
|
|
14547
|
+
return "+";
|
|
14548
|
+
return "−";
|
|
14558
14549
|
};
|
|
14559
14550
|
const snapshotLabel = (s2) => {
|
|
14560
14551
|
const date = new Date(s2.createdAt).toLocaleString();
|
|
@@ -15360,11 +15351,19 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15360
15351
|
allCols.add(k);
|
|
15361
15352
|
}
|
|
15362
15353
|
const columns = [...allCols];
|
|
15363
|
-
const
|
|
15364
|
-
|
|
15354
|
+
const colHeaderWrap = document.createElement("div");
|
|
15355
|
+
colHeaderWrap.className = "db-snapshot-diff-col-header-wrap";
|
|
15356
|
+
const colHeaderTable = document.createElement("table");
|
|
15357
|
+
colHeaderTable.className = "db-snap-diff-grid";
|
|
15358
|
+
const colHeaderColgroup = document.createElement("colgroup");
|
|
15359
|
+
for (let i2 = 0;i2 < columns.length + 1; i2++) {
|
|
15360
|
+
colHeaderColgroup.appendChild(document.createElement("col"));
|
|
15361
|
+
}
|
|
15362
|
+
colHeaderTable.appendChild(colHeaderColgroup);
|
|
15365
15363
|
const thead = document.createElement("thead");
|
|
15366
15364
|
const headRow = document.createElement("tr");
|
|
15367
15365
|
const thType = document.createElement("th");
|
|
15366
|
+
thType.className = "snap-diff-type-cell";
|
|
15368
15367
|
thType.textContent = "";
|
|
15369
15368
|
headRow.appendChild(thType);
|
|
15370
15369
|
for (const col of columns) {
|
|
@@ -15373,16 +15372,25 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15373
15372
|
headRow.appendChild(th);
|
|
15374
15373
|
}
|
|
15375
15374
|
thead.appendChild(headRow);
|
|
15376
|
-
|
|
15375
|
+
colHeaderTable.appendChild(thead);
|
|
15376
|
+
colHeaderWrap.appendChild(colHeaderTable);
|
|
15377
|
+
const rowsViewport = document.createElement("div");
|
|
15378
|
+
rowsViewport.className = "db-snapshot-diff-rows-viewport";
|
|
15379
|
+
const bodyTable = document.createElement("table");
|
|
15380
|
+
bodyTable.className = "db-snap-diff-grid";
|
|
15381
|
+
const bodyColgroup = document.createElement("colgroup");
|
|
15382
|
+
for (let i2 = 0;i2 < columns.length + 1; i2++) {
|
|
15383
|
+
bodyColgroup.appendChild(document.createElement("col"));
|
|
15384
|
+
}
|
|
15385
|
+
bodyTable.appendChild(bodyColgroup);
|
|
15377
15386
|
const tbody = document.createElement("tbody");
|
|
15378
15387
|
for (const row of rows) {
|
|
15379
15388
|
if (row.changeType === "updated" && row.beforeValues && row.afterValues) {
|
|
15380
15389
|
const trBefore = document.createElement("tr");
|
|
15381
|
-
trBefore.className = "snap-diff-del";
|
|
15390
|
+
trBefore.className = "snap-diff-del snap-diff-record-start";
|
|
15382
15391
|
const tdTypeBefore = document.createElement("td");
|
|
15383
15392
|
tdTypeBefore.className = "snap-diff-type-cell";
|
|
15384
|
-
tdTypeBefore.textContent =
|
|
15385
|
-
tdTypeBefore.rowSpan = 2;
|
|
15393
|
+
tdTypeBefore.textContent = "−";
|
|
15386
15394
|
trBefore.appendChild(tdTypeBefore);
|
|
15387
15395
|
for (const col of columns) {
|
|
15388
15396
|
const td = document.createElement("td");
|
|
@@ -15395,7 +15403,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15395
15403
|
}
|
|
15396
15404
|
tbody.appendChild(trBefore);
|
|
15397
15405
|
const trAfter = document.createElement("tr");
|
|
15398
|
-
trAfter.className = "snap-diff-add";
|
|
15406
|
+
trAfter.className = "snap-diff-add snap-diff-record-end";
|
|
15407
|
+
const tdTypeAfter = document.createElement("td");
|
|
15408
|
+
tdTypeAfter.className = "snap-diff-type-cell";
|
|
15409
|
+
tdTypeAfter.textContent = "+";
|
|
15410
|
+
trAfter.appendChild(tdTypeAfter);
|
|
15399
15411
|
for (const col of columns) {
|
|
15400
15412
|
const td = document.createElement("td");
|
|
15401
15413
|
const bs = row.beforeValues[col] == null ? "NULL" : String(row.beforeValues[col]);
|
|
@@ -15408,7 +15420,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15408
15420
|
tbody.appendChild(trAfter);
|
|
15409
15421
|
} else {
|
|
15410
15422
|
const tr = document.createElement("tr");
|
|
15411
|
-
|
|
15423
|
+
const sideClass = row.changeType === "inserted" ? "snap-diff-add" : "snap-diff-del";
|
|
15424
|
+
tr.className = `${sideClass} snap-diff-record-start snap-diff-record-end`;
|
|
15412
15425
|
const tdType = document.createElement("td");
|
|
15413
15426
|
tdType.className = "snap-diff-type-cell";
|
|
15414
15427
|
tdType.textContent = changeTypeLabel(row.changeType);
|
|
@@ -15416,6 +15429,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15416
15429
|
const values = row.changeType === "inserted" ? row.afterValues : row.beforeValues;
|
|
15417
15430
|
for (const col of columns) {
|
|
15418
15431
|
const td = document.createElement("td");
|
|
15432
|
+
td.classList.add("snap-diff-changed-cell");
|
|
15419
15433
|
const v = values?.[col];
|
|
15420
15434
|
td.textContent = v == null ? "NULL" : String(v);
|
|
15421
15435
|
tr.appendChild(td);
|
|
@@ -15423,8 +15437,32 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
15423
15437
|
tbody.appendChild(tr);
|
|
15424
15438
|
}
|
|
15425
15439
|
}
|
|
15426
|
-
|
|
15427
|
-
|
|
15440
|
+
bodyTable.appendChild(tbody);
|
|
15441
|
+
rowsViewport.appendChild(bodyTable);
|
|
15442
|
+
container.append(colHeaderWrap, rowsViewport);
|
|
15443
|
+
rowsViewport.addEventListener("scroll", () => {
|
|
15444
|
+
colHeaderWrap.scrollLeft = rowsViewport.scrollLeft;
|
|
15445
|
+
});
|
|
15446
|
+
const syncColumnWidths = () => {
|
|
15447
|
+
if (disposed)
|
|
15448
|
+
return;
|
|
15449
|
+
const firstRow = tbody.querySelector("tr");
|
|
15450
|
+
if (!firstRow)
|
|
15451
|
+
return;
|
|
15452
|
+
const cells = firstRow.children;
|
|
15453
|
+
const bodyCols = bodyColgroup.children;
|
|
15454
|
+
const headerCols = colHeaderColgroup.children;
|
|
15455
|
+
for (let i2 = 0;i2 < cells.length; i2++) {
|
|
15456
|
+
const w = cells[i2].offsetWidth;
|
|
15457
|
+
if (bodyCols[i2])
|
|
15458
|
+
bodyCols[i2].style.width = `${w}px`;
|
|
15459
|
+
if (headerCols[i2])
|
|
15460
|
+
headerCols[i2].style.width = `${w}px`;
|
|
15461
|
+
}
|
|
15462
|
+
};
|
|
15463
|
+
requestAnimationFrame(syncColumnWidths);
|
|
15464
|
+
const ro = new ResizeObserver(syncColumnWidths);
|
|
15465
|
+
ro.observe(bodyTable);
|
|
15428
15466
|
if (total > rows.length) {
|
|
15429
15467
|
const more = document.createElement("div");
|
|
15430
15468
|
more.className = "db-snapshot-diff-more";
|
|
@@ -20198,6 +20236,20 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20198
20236
|
const b2 = Math.max(1, Math.floor(Math.max(start, end)));
|
|
20199
20237
|
return a2 === b2 ? `@${path}#${a2}` : `@${path}#${a2}-${b2}`;
|
|
20200
20238
|
}
|
|
20239
|
+
function fileReferenceWithCodeClipboardText(path, start, end, lines, lang) {
|
|
20240
|
+
const ref = fileReferenceClipboardText(path, start, end);
|
|
20241
|
+
if (!ref)
|
|
20242
|
+
return "";
|
|
20243
|
+
if (!lines || lines.length === 0)
|
|
20244
|
+
return ref;
|
|
20245
|
+
const fence2 = (lang || "").trim();
|
|
20246
|
+
return `${ref}
|
|
20247
|
+
|
|
20248
|
+
\`\`\`${fence2}
|
|
20249
|
+
${lines.join(`
|
|
20250
|
+
`)}
|
|
20251
|
+
\`\`\``;
|
|
20252
|
+
}
|
|
20201
20253
|
|
|
20202
20254
|
// web-src/core/ws-highlight.ts
|
|
20203
20255
|
function isWhitespaceOnlyInlineHighlight(text2) {
|
|
@@ -20228,6 +20280,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20228
20280
|
function shouldRenderDiffSidebar(listSame, domIntact) {
|
|
20229
20281
|
return !listSame || !domIntact;
|
|
20230
20282
|
}
|
|
20283
|
+
function findDirectDiffCardByKey(target, key) {
|
|
20284
|
+
for (const child of Array.from(target.children)) {
|
|
20285
|
+
if (!child.classList.contains("gdp-file-shell"))
|
|
20286
|
+
continue;
|
|
20287
|
+
const card = child;
|
|
20288
|
+
if (card.dataset.key === key)
|
|
20289
|
+
return card;
|
|
20290
|
+
}
|
|
20291
|
+
return null;
|
|
20292
|
+
}
|
|
20231
20293
|
function createDiffView(deps) {
|
|
20232
20294
|
const {
|
|
20233
20295
|
$,
|
|
@@ -20443,11 +20505,17 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20443
20505
|
let CLIENT_REQ_SEQ = 0;
|
|
20444
20506
|
const LOAD_QUEUE = [];
|
|
20445
20507
|
let ACTIVE_LOADS = 0;
|
|
20508
|
+
let LOAD_EPOCH = 0;
|
|
20446
20509
|
const MAX_PARALLEL = 2;
|
|
20447
20510
|
let lazyObserver = null;
|
|
20448
20511
|
let scrollSpyInstalled = false;
|
|
20449
20512
|
let prevListSignature = "";
|
|
20450
20513
|
let prevCardSignatures = new Map;
|
|
20514
|
+
function resetLoadScheduling() {
|
|
20515
|
+
LOAD_EPOCH++;
|
|
20516
|
+
LOAD_QUEUE.length = 0;
|
|
20517
|
+
ACTIVE_LOADS = 0;
|
|
20518
|
+
}
|
|
20451
20519
|
function fileKey(f2) {
|
|
20452
20520
|
return f2.key || f2.path;
|
|
20453
20521
|
}
|
|
@@ -20497,11 +20565,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20497
20565
|
}
|
|
20498
20566
|
}
|
|
20499
20567
|
function invalidateLoadedCard(card, file, changedPaths) {
|
|
20500
|
-
if (!card.classList.contains("loaded"))
|
|
20568
|
+
if (!card.classList.contains("loaded") && !card.classList.contains("loading"))
|
|
20501
20569
|
return false;
|
|
20502
20570
|
if (changedPaths && !changedPaths.has(file.path))
|
|
20503
20571
|
return false;
|
|
20504
|
-
card.
|
|
20572
|
+
card.dataset.reqId = String(++CLIENT_REQ_SEQ);
|
|
20573
|
+
card.classList.remove("loaded", "loading", "error");
|
|
20505
20574
|
card.classList.add("pending");
|
|
20506
20575
|
card._diffData = null;
|
|
20507
20576
|
const body = card.querySelector(".gdp-shell-body");
|
|
@@ -20531,6 +20600,25 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20531
20600
|
}
|
|
20532
20601
|
}
|
|
20533
20602
|
}
|
|
20603
|
+
function resetReusableCard(card, file) {
|
|
20604
|
+
card.classList.remove("loaded", "loading", "error", "manual-load");
|
|
20605
|
+
card.classList.add("pending");
|
|
20606
|
+
card.replaceChildren();
|
|
20607
|
+
const tmp = createPlaceholder(file);
|
|
20608
|
+
while (tmp.firstChild)
|
|
20609
|
+
card.appendChild(tmp.firstChild);
|
|
20610
|
+
card.dataset.path = file.path;
|
|
20611
|
+
card.dataset.key = fileKey(file);
|
|
20612
|
+
card.dataset.sizeClass = file.size_class || "small";
|
|
20613
|
+
card.dataset.status = file.status || "M";
|
|
20614
|
+
card.dataset.reqId = String(++CLIENT_REQ_SEQ);
|
|
20615
|
+
delete card.dataset.manualRendered;
|
|
20616
|
+
delete card.dataset.manualLoad;
|
|
20617
|
+
delete card.dataset.manualMode;
|
|
20618
|
+
card.style.minHeight = `${file.estimated_height_px || 80}px`;
|
|
20619
|
+
card._diffData = null;
|
|
20620
|
+
card._file = null;
|
|
20621
|
+
}
|
|
20534
20622
|
function renderShell(meta, changedPaths) {
|
|
20535
20623
|
const newFiles = meta.files || [];
|
|
20536
20624
|
const newListSig = computeListSignature(newFiles);
|
|
@@ -20559,7 +20647,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20559
20647
|
empty.classList.remove("hidden");
|
|
20560
20648
|
target.replaceChildren();
|
|
20561
20649
|
}
|
|
20562
|
-
|
|
20650
|
+
resetLoadScheduling();
|
|
20563
20651
|
return {
|
|
20564
20652
|
structureChanged: sidebarNeedsRender,
|
|
20565
20653
|
invalidatedCards: 0,
|
|
@@ -20571,39 +20659,33 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20571
20659
|
for (const f2 of newFiles) {
|
|
20572
20660
|
newCardSigs.set(fileKey(f2), computeCardSignature(f2));
|
|
20573
20661
|
}
|
|
20662
|
+
const pathsUnknown = !changedPaths;
|
|
20663
|
+
const contentMayNeedReload = !listSame || pathsUnknown || (changedPaths ? newFiles.some((file) => {
|
|
20664
|
+
const key = fileKey(file);
|
|
20665
|
+
return prevCardSignatures.get(key) !== newCardSigs.get(key) || changedPaths.has(file.path);
|
|
20666
|
+
}) : false);
|
|
20667
|
+
if (contentMayNeedReload)
|
|
20668
|
+
resetLoadScheduling();
|
|
20574
20669
|
let invalidatedCards = 0;
|
|
20575
20670
|
if (listSame && domIntact) {
|
|
20576
|
-
const
|
|
20671
|
+
const pathsUnknown2 = !changedPaths;
|
|
20577
20672
|
let sidebarNeedsStatsUpdate = false;
|
|
20578
20673
|
for (const f2 of newFiles) {
|
|
20579
20674
|
const key = fileKey(f2);
|
|
20580
20675
|
const oldSig = prevCardSignatures.get(key);
|
|
20581
|
-
const newSig = newCardSigs.get(key);
|
|
20676
|
+
const newSig = newCardSigs.get(key) ?? computeCardSignature(f2);
|
|
20582
20677
|
const sigChanged = oldSig !== newSig;
|
|
20583
|
-
const pathHint =
|
|
20678
|
+
const pathHint = pathsUnknown2 || changedPaths.has(f2.path);
|
|
20584
20679
|
if (!sigChanged && !pathHint) {
|
|
20585
20680
|
continue;
|
|
20586
20681
|
}
|
|
20587
|
-
const card = target
|
|
20682
|
+
const card = findDirectDiffCardByKey(target, key);
|
|
20588
20683
|
if (!card)
|
|
20589
20684
|
continue;
|
|
20590
20685
|
const sizeChanged = card.dataset.sizeClass !== (f2.size_class || "small");
|
|
20591
20686
|
const statusChanged = card.dataset.status !== (f2.status || "M");
|
|
20592
20687
|
if (sizeChanged || statusChanged) {
|
|
20593
|
-
card
|
|
20594
|
-
card.classList.add("pending");
|
|
20595
|
-
card.replaceChildren();
|
|
20596
|
-
const tmp = createPlaceholder(f2);
|
|
20597
|
-
while (tmp.firstChild)
|
|
20598
|
-
card.appendChild(tmp.firstChild);
|
|
20599
|
-
card.dataset.sizeClass = f2.size_class || "small";
|
|
20600
|
-
card.dataset.status = f2.status || "M";
|
|
20601
|
-
delete card.dataset.manualRendered;
|
|
20602
|
-
delete card.dataset.manualLoad;
|
|
20603
|
-
delete card.dataset.manualMode;
|
|
20604
|
-
card.style.minHeight = `${f2.estimated_height_px || 80}px`;
|
|
20605
|
-
card._diffData = null;
|
|
20606
|
-
card._file = null;
|
|
20688
|
+
resetReusableCard(card, f2);
|
|
20607
20689
|
activatePendingCard(card, f2);
|
|
20608
20690
|
invalidatedCards++;
|
|
20609
20691
|
sidebarNeedsStatsUpdate = true;
|
|
@@ -20616,6 +20698,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20616
20698
|
const didInvalidate = sigChanged ? invalidateLoadedCard(card, f2, null) : invalidateLoadedCard(card, f2, changedPaths);
|
|
20617
20699
|
if (didInvalidate)
|
|
20618
20700
|
invalidatedCards++;
|
|
20701
|
+
else if ((sigChanged || pathHint) && card.classList.contains("pending")) {
|
|
20702
|
+
activatePendingCard(card, f2);
|
|
20703
|
+
}
|
|
20619
20704
|
if (sigChanged)
|
|
20620
20705
|
sidebarNeedsStatsUpdate = true;
|
|
20621
20706
|
}
|
|
@@ -20650,21 +20735,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20650
20735
|
oldByKey.delete(key);
|
|
20651
20736
|
const sizeChanged = old.dataset.sizeClass !== (f2.size_class || "small");
|
|
20652
20737
|
const statusChanged = old.dataset.status !== (f2.status || "M");
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
while (tmp.firstChild)
|
|
20659
|
-
old.appendChild(tmp.firstChild);
|
|
20660
|
-
old.dataset.sizeClass = f2.size_class || "small";
|
|
20661
|
-
old.dataset.status = f2.status || "M";
|
|
20662
|
-
delete old.dataset.manualRendered;
|
|
20663
|
-
delete old.dataset.manualLoad;
|
|
20664
|
-
delete old.dataset.manualMode;
|
|
20665
|
-
old.style.minHeight = `${f2.estimated_height_px || 80}px`;
|
|
20666
|
-
old._diffData = null;
|
|
20667
|
-
old._file = null;
|
|
20738
|
+
const oldSig = prevCardSignatures.get(key);
|
|
20739
|
+
const newSig = newCardSigs.get(key) ?? computeCardSignature(f2);
|
|
20740
|
+
const sigChanged = oldSig !== newSig;
|
|
20741
|
+
if (sizeChanged || statusChanged || sigChanged) {
|
|
20742
|
+
resetReusableCard(old, f2);
|
|
20668
20743
|
invalidatedCards++;
|
|
20669
20744
|
} else {
|
|
20670
20745
|
const stats = old.querySelector(".gdp-shell-header .stats");
|
|
@@ -20756,20 +20831,29 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20756
20831
|
renderManualLoadPlaceholder(card, file);
|
|
20757
20832
|
return;
|
|
20758
20833
|
}
|
|
20759
|
-
if (LOAD_QUEUE.find((item) => item.card === card))
|
|
20834
|
+
if (LOAD_QUEUE.find((item) => item.card === card && item.epoch === LOAD_EPOCH))
|
|
20760
20835
|
return;
|
|
20761
|
-
LOAD_QUEUE.push({
|
|
20836
|
+
LOAD_QUEUE.push({
|
|
20837
|
+
file,
|
|
20838
|
+
card,
|
|
20839
|
+
priority: priority || 0,
|
|
20840
|
+
epoch: LOAD_EPOCH
|
|
20841
|
+
});
|
|
20762
20842
|
LOAD_QUEUE.sort((a2, b2) => b2.priority - a2.priority);
|
|
20763
20843
|
pumpQueue();
|
|
20764
20844
|
}
|
|
20765
20845
|
function pumpQueue() {
|
|
20766
20846
|
while (ACTIVE_LOADS < MAX_PARALLEL && LOAD_QUEUE.length) {
|
|
20767
20847
|
const item = LOAD_QUEUE.shift();
|
|
20848
|
+
if (item.epoch !== LOAD_EPOCH)
|
|
20849
|
+
continue;
|
|
20768
20850
|
if (item.card.classList.contains("loaded") || item.card.classList.contains("loading"))
|
|
20769
20851
|
continue;
|
|
20770
20852
|
ACTIVE_LOADS++;
|
|
20771
20853
|
loadFile(item.file, item.card).finally(() => {
|
|
20772
|
-
|
|
20854
|
+
if (item.epoch === LOAD_EPOCH) {
|
|
20855
|
+
ACTIVE_LOADS = Math.max(0, ACTIVE_LOADS - 1);
|
|
20856
|
+
}
|
|
20773
20857
|
pumpQueue();
|
|
20774
20858
|
});
|
|
20775
20859
|
}
|
|
@@ -21414,7 +21498,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21414
21498
|
});
|
|
21415
21499
|
}
|
|
21416
21500
|
function clearLoadQueue() {
|
|
21417
|
-
|
|
21501
|
+
resetLoadScheduling();
|
|
21418
21502
|
}
|
|
21419
21503
|
return {
|
|
21420
21504
|
renderMeta,
|
|
@@ -21900,6 +21984,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
21900
21984
|
let hasMore = false;
|
|
21901
21985
|
let loading = false;
|
|
21902
21986
|
let generation = 0;
|
|
21987
|
+
let selectionGeneration = 0;
|
|
21903
21988
|
let selectedSha = "";
|
|
21904
21989
|
let query = "";
|
|
21905
21990
|
let mode = "history";
|
|
@@ -22160,11 +22245,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22160
22245
|
return page.commits.length > 0;
|
|
22161
22246
|
}
|
|
22162
22247
|
async function selectCommit(commit, options = {}) {
|
|
22248
|
+
const selectionGen = ++selectionGeneration;
|
|
22163
22249
|
const gen = generation;
|
|
22164
22250
|
selectedSha = commit.sha;
|
|
22165
22251
|
updateActiveRow();
|
|
22166
22252
|
await updateCommitInfo(commit);
|
|
22167
|
-
if (gen !== generation)
|
|
22253
|
+
if (selectionGen !== selectionGeneration || gen !== generation)
|
|
22168
22254
|
return;
|
|
22169
22255
|
if (options.updateUrl !== false) {
|
|
22170
22256
|
const range = commitDiffRange(commit);
|
|
@@ -22181,13 +22267,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22181
22267
|
deps.setRoute({ screen: "history", ref, commit: commit.sha, range }, true);
|
|
22182
22268
|
}
|
|
22183
22269
|
}
|
|
22184
|
-
if (gen !== generation)
|
|
22270
|
+
if (selectionGen !== selectionGeneration || gen !== generation)
|
|
22185
22271
|
return;
|
|
22186
22272
|
await deps.applyCommitRange(commitDiffRange(commit), pathFilter || undefined);
|
|
22187
|
-
if (gen !== generation)
|
|
22273
|
+
if (selectionGen !== selectionGeneration || gen !== generation)
|
|
22188
22274
|
return;
|
|
22189
22275
|
}
|
|
22190
22276
|
async function selectWorktree(options = {}) {
|
|
22277
|
+
const selectionGen = ++selectionGeneration;
|
|
22191
22278
|
const gen = generation;
|
|
22192
22279
|
selectedSha = HISTORY_WORKTREE_COMMIT;
|
|
22193
22280
|
updateActiveRow();
|
|
@@ -22207,10 +22294,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22207
22294
|
deps.setRoute({ screen: "history", ref, commit: selectedSha, range }, true);
|
|
22208
22295
|
}
|
|
22209
22296
|
}
|
|
22210
|
-
if (gen !== generation)
|
|
22297
|
+
if (selectionGen !== selectionGeneration || gen !== generation)
|
|
22211
22298
|
return;
|
|
22212
22299
|
await deps.applyCommitRange(range, pathFilter || undefined);
|
|
22213
|
-
if (gen !== generation)
|
|
22300
|
+
if (selectionGen !== selectionGeneration || gen !== generation)
|
|
22214
22301
|
return;
|
|
22215
22302
|
}
|
|
22216
22303
|
let lookupFailed = false;
|
|
@@ -22307,6 +22394,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22307
22394
|
hasMore = false;
|
|
22308
22395
|
loading = false;
|
|
22309
22396
|
inFlight = null;
|
|
22397
|
+
selectionGeneration++;
|
|
22310
22398
|
selectedSha = "";
|
|
22311
22399
|
setBanner("");
|
|
22312
22400
|
await updateCommitInfo(null);
|
|
@@ -22323,6 +22411,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22323
22411
|
if (scope2.commit) {
|
|
22324
22412
|
await resolveDeepLink(scope2.commit);
|
|
22325
22413
|
} else {
|
|
22414
|
+
selectionGeneration++;
|
|
22326
22415
|
selectedSha = "";
|
|
22327
22416
|
updateActiveRow();
|
|
22328
22417
|
await updateCommitInfo(null);
|
|
@@ -22352,6 +22441,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22352
22441
|
generation++;
|
|
22353
22442
|
loading = false;
|
|
22354
22443
|
inFlight = null;
|
|
22444
|
+
selectionGeneration++;
|
|
22355
22445
|
selectedSha = "";
|
|
22356
22446
|
setBanner("");
|
|
22357
22447
|
setStatusText("");
|
|
@@ -22376,6 +22466,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22376
22466
|
return;
|
|
22377
22467
|
query = value;
|
|
22378
22468
|
generation++;
|
|
22469
|
+
selectionGeneration++;
|
|
22379
22470
|
commits = [];
|
|
22380
22471
|
hasMore = false;
|
|
22381
22472
|
loading = false;
|
|
@@ -22538,6 +22629,308 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22538
22629
|
};
|
|
22539
22630
|
}
|
|
22540
22631
|
|
|
22632
|
+
// web-src/views/help-keybindings.ts
|
|
22633
|
+
var HIDDEN_HELP_KEYBINDING_ACTIONS = new Set([
|
|
22634
|
+
"start-g-sequence"
|
|
22635
|
+
]);
|
|
22636
|
+
var HELP_KEYBINDING_GROUPS = [
|
|
22637
|
+
{
|
|
22638
|
+
title: { en: "Global", ja: "グローバル" },
|
|
22639
|
+
rows: [
|
|
22640
|
+
{
|
|
22641
|
+
selectors: [{ action: "open-file-palette" }],
|
|
22642
|
+
description: {
|
|
22643
|
+
en: "Open file palette",
|
|
22644
|
+
ja: "ファイルパレットを開く"
|
|
22645
|
+
}
|
|
22646
|
+
},
|
|
22647
|
+
{
|
|
22648
|
+
selectors: [{ action: "open-grep-palette" }],
|
|
22649
|
+
description: {
|
|
22650
|
+
en: "Open grep palette",
|
|
22651
|
+
ja: "grep パレットを開く"
|
|
22652
|
+
}
|
|
22653
|
+
},
|
|
22654
|
+
{
|
|
22655
|
+
selectors: [{ action: "focus-file-filter" }],
|
|
22656
|
+
description: {
|
|
22657
|
+
en: "Focus file filter",
|
|
22658
|
+
ja: "ファイルフィルターへフォーカス"
|
|
22659
|
+
}
|
|
22660
|
+
},
|
|
22661
|
+
{
|
|
22662
|
+
selectors: [{ action: "open-help" }],
|
|
22663
|
+
description: {
|
|
22664
|
+
en: "Open this help (keybindings)",
|
|
22665
|
+
ja: "このヘルプ(キーバインド)を開く"
|
|
22666
|
+
}
|
|
22667
|
+
},
|
|
22668
|
+
{
|
|
22669
|
+
selectors: [{ action: "toggle-theme" }],
|
|
22670
|
+
description: { en: "Toggle theme", ja: "テーマ切り替え" }
|
|
22671
|
+
},
|
|
22672
|
+
{
|
|
22673
|
+
selectors: [
|
|
22674
|
+
{ action: "annotation-previous" },
|
|
22675
|
+
{ action: "annotation-next" }
|
|
22676
|
+
],
|
|
22677
|
+
description: {
|
|
22678
|
+
en: "Previous / next annotation",
|
|
22679
|
+
ja: "前 / 次の注釈へ移動"
|
|
22680
|
+
}
|
|
22681
|
+
},
|
|
22682
|
+
{
|
|
22683
|
+
selectors: [{ action: "layout-unified" }, { action: "layout-split" }],
|
|
22684
|
+
description: {
|
|
22685
|
+
en: "Switch unified / split layout",
|
|
22686
|
+
ja: "統合 / 分割レイアウトへ切り替え"
|
|
22687
|
+
}
|
|
22688
|
+
},
|
|
22689
|
+
{
|
|
22690
|
+
selectors: [{ action: "cancel-source-load" }],
|
|
22691
|
+
description: {
|
|
22692
|
+
en: "Cancel active source load",
|
|
22693
|
+
ja: "進行中のソース読み込みを中断"
|
|
22694
|
+
}
|
|
22695
|
+
}
|
|
22696
|
+
]
|
|
22697
|
+
},
|
|
22698
|
+
{
|
|
22699
|
+
title: { en: "Panels", ja: "パネル" },
|
|
22700
|
+
rows: [
|
|
22701
|
+
{
|
|
22702
|
+
selectors: [{ action: "focus-sidebar" }],
|
|
22703
|
+
description: { en: "Focus sidebar", ja: "サイドバーへフォーカス" }
|
|
22704
|
+
},
|
|
22705
|
+
{
|
|
22706
|
+
selectors: [{ action: "focus-main" }],
|
|
22707
|
+
description: {
|
|
22708
|
+
en: "Focus main panel",
|
|
22709
|
+
ja: "メインパネルへフォーカス"
|
|
22710
|
+
}
|
|
22711
|
+
}
|
|
22712
|
+
]
|
|
22713
|
+
},
|
|
22714
|
+
{
|
|
22715
|
+
title: { en: "Sidebar", ja: "サイドバー" },
|
|
22716
|
+
rows: [
|
|
22717
|
+
{
|
|
22718
|
+
selectors: [{ action: "sidebar-next" }, { action: "sidebar-previous" }],
|
|
22719
|
+
description: {
|
|
22720
|
+
en: "Move selection down / up",
|
|
22721
|
+
ja: "選択を下 / 上へ移動"
|
|
22722
|
+
}
|
|
22723
|
+
},
|
|
22724
|
+
{
|
|
22725
|
+
selectors: [
|
|
22726
|
+
{ action: "sidebar-page-down" },
|
|
22727
|
+
{ action: "sidebar-page-up" }
|
|
22728
|
+
],
|
|
22729
|
+
description: {
|
|
22730
|
+
en: "Move selection by half a page",
|
|
22731
|
+
ja: "半ページ分選択を移動"
|
|
22732
|
+
}
|
|
22733
|
+
},
|
|
22734
|
+
{
|
|
22735
|
+
selectors: [
|
|
22736
|
+
{ action: "goto-top", pendingG: true },
|
|
22737
|
+
{ action: "goto-bottom", shift: true, pendingG: false }
|
|
22738
|
+
],
|
|
22739
|
+
description: { en: "Move to top / bottom", ja: "先頭 / 末尾へ移動" }
|
|
22740
|
+
},
|
|
22741
|
+
{
|
|
22742
|
+
selectors: [{ action: "open-sidebar-item" }],
|
|
22743
|
+
description: { en: "Open selected item", ja: "選択項目を開く" }
|
|
22744
|
+
},
|
|
22745
|
+
{
|
|
22746
|
+
selectors: [
|
|
22747
|
+
{ action: "sidebar-collapse" },
|
|
22748
|
+
{ action: "sidebar-expand" }
|
|
22749
|
+
],
|
|
22750
|
+
description: {
|
|
22751
|
+
en: "Collapse / expand directory",
|
|
22752
|
+
ja: "ディレクトリを閉じる / 開く"
|
|
22753
|
+
}
|
|
22754
|
+
}
|
|
22755
|
+
]
|
|
22756
|
+
},
|
|
22757
|
+
{
|
|
22758
|
+
title: { en: "Main Panel", ja: "メインパネル" },
|
|
22759
|
+
rows: [
|
|
22760
|
+
{
|
|
22761
|
+
selectors: [
|
|
22762
|
+
{ action: "scroll-main-down", scope: "main" },
|
|
22763
|
+
{ action: "scroll-main-up", scope: "main" }
|
|
22764
|
+
],
|
|
22765
|
+
description: {
|
|
22766
|
+
en: "Move code cursor down / up",
|
|
22767
|
+
ja: "コードカーソルを下 / 上へ移動"
|
|
22768
|
+
}
|
|
22769
|
+
},
|
|
22770
|
+
{
|
|
22771
|
+
selectors: [
|
|
22772
|
+
{
|
|
22773
|
+
action: "scroll-main-page-down",
|
|
22774
|
+
scope: "main",
|
|
22775
|
+
key: "d",
|
|
22776
|
+
ctrl: true
|
|
22777
|
+
},
|
|
22778
|
+
{
|
|
22779
|
+
action: "scroll-main-page-up",
|
|
22780
|
+
scope: "main",
|
|
22781
|
+
key: "u",
|
|
22782
|
+
ctrl: true
|
|
22783
|
+
}
|
|
22784
|
+
],
|
|
22785
|
+
description: {
|
|
22786
|
+
en: "Move code cursor by half a page",
|
|
22787
|
+
ja: "コードカーソルを半ページ分移動"
|
|
22788
|
+
}
|
|
22789
|
+
},
|
|
22790
|
+
{
|
|
22791
|
+
selectors: [
|
|
22792
|
+
{ action: "scroll-main-page-down", scope: "main", key: "pagedown" },
|
|
22793
|
+
{ action: "scroll-main-page-up", scope: "main", key: "pageup" }
|
|
22794
|
+
],
|
|
22795
|
+
description: {
|
|
22796
|
+
en: "Move code cursor by a page",
|
|
22797
|
+
ja: "コードカーソルを1ページ分移動"
|
|
22798
|
+
}
|
|
22799
|
+
},
|
|
22800
|
+
{
|
|
22801
|
+
selectors: [
|
|
22802
|
+
{
|
|
22803
|
+
action: "scroll-main-page-down",
|
|
22804
|
+
scope: "main",
|
|
22805
|
+
key: "arrowdown",
|
|
22806
|
+
ctrl: true
|
|
22807
|
+
},
|
|
22808
|
+
{
|
|
22809
|
+
action: "scroll-main-page-up",
|
|
22810
|
+
scope: "main",
|
|
22811
|
+
key: "arrowup",
|
|
22812
|
+
ctrl: true
|
|
22813
|
+
}
|
|
22814
|
+
],
|
|
22815
|
+
description: {
|
|
22816
|
+
en: "Move code cursor by a page",
|
|
22817
|
+
ja: "コードカーソルを1ページ分移動"
|
|
22818
|
+
}
|
|
22819
|
+
},
|
|
22820
|
+
{
|
|
22821
|
+
selectors: [
|
|
22822
|
+
{ action: "goto-top", pendingG: true },
|
|
22823
|
+
{ action: "goto-bottom", shift: true, pendingG: false }
|
|
22824
|
+
],
|
|
22825
|
+
description: {
|
|
22826
|
+
en: "Move code cursor to top / bottom",
|
|
22827
|
+
ja: "コードカーソルを先頭 / 末尾へ移動"
|
|
22828
|
+
}
|
|
22829
|
+
},
|
|
22830
|
+
{
|
|
22831
|
+
selectors: [
|
|
22832
|
+
{ action: "tab-preview", scope: "main", pendingG: true },
|
|
22833
|
+
{ action: "tab-code", scope: "main", pendingG: true }
|
|
22834
|
+
],
|
|
22835
|
+
description: {
|
|
22836
|
+
en: "Switch to Preview / Code tab",
|
|
22837
|
+
ja: "Preview / Code タブへ切り替え"
|
|
22838
|
+
}
|
|
22839
|
+
}
|
|
22840
|
+
]
|
|
22841
|
+
}
|
|
22842
|
+
];
|
|
22843
|
+
function matchesSelector(binding, selector) {
|
|
22844
|
+
if (binding.action !== selector.action)
|
|
22845
|
+
return false;
|
|
22846
|
+
if (selector.key !== undefined && binding.key !== selector.key)
|
|
22847
|
+
return false;
|
|
22848
|
+
if (selector.scope !== undefined && binding.scope !== selector.scope)
|
|
22849
|
+
return false;
|
|
22850
|
+
if (selector.ctrl !== undefined && !!binding.ctrl !== selector.ctrl)
|
|
22851
|
+
return false;
|
|
22852
|
+
if (selector.meta !== undefined && !!binding.meta !== selector.meta)
|
|
22853
|
+
return false;
|
|
22854
|
+
if (selector.alt !== undefined && !!binding.alt !== selector.alt)
|
|
22855
|
+
return false;
|
|
22856
|
+
if (selector.shift !== undefined && !!binding.shift !== selector.shift)
|
|
22857
|
+
return false;
|
|
22858
|
+
if (selector.pendingG !== undefined && !!binding.pendingG !== selector.pendingG)
|
|
22859
|
+
return false;
|
|
22860
|
+
return true;
|
|
22861
|
+
}
|
|
22862
|
+
function formatKeyName(key, shifted) {
|
|
22863
|
+
const lower = key.toLowerCase();
|
|
22864
|
+
if (lower === "escape")
|
|
22865
|
+
return "Escape";
|
|
22866
|
+
if (lower === "enter")
|
|
22867
|
+
return "Enter";
|
|
22868
|
+
if (lower === "pagedown")
|
|
22869
|
+
return "PageDown";
|
|
22870
|
+
if (lower === "pageup")
|
|
22871
|
+
return "PageUp";
|
|
22872
|
+
if (lower === "arrowdown")
|
|
22873
|
+
return "ArrowDown";
|
|
22874
|
+
if (lower === "arrowup")
|
|
22875
|
+
return "ArrowUp";
|
|
22876
|
+
if (key === "?")
|
|
22877
|
+
return "?";
|
|
22878
|
+
if (shifted && key.length === 1)
|
|
22879
|
+
return key.toUpperCase();
|
|
22880
|
+
return key;
|
|
22881
|
+
}
|
|
22882
|
+
function formatKeyBinding(binding) {
|
|
22883
|
+
const key = formatKeyName(binding.key, !!binding.shift || !!binding.ctrl || !!binding.meta || !!binding.alt);
|
|
22884
|
+
if (binding.pendingG && !binding.ctrl && !binding.meta && !binding.alt && !binding.shift && binding.key.length === 1)
|
|
22885
|
+
return `g${key}`;
|
|
22886
|
+
const parts = [];
|
|
22887
|
+
if (binding.pendingG)
|
|
22888
|
+
parts.push("g");
|
|
22889
|
+
if (binding.ctrl)
|
|
22890
|
+
parts.push("Ctrl");
|
|
22891
|
+
if (binding.meta)
|
|
22892
|
+
parts.push("Meta");
|
|
22893
|
+
if (binding.alt)
|
|
22894
|
+
parts.push("Alt");
|
|
22895
|
+
if (binding.shift && binding.key !== "?")
|
|
22896
|
+
parts.push("Shift");
|
|
22897
|
+
parts.push(key);
|
|
22898
|
+
return parts.join("+");
|
|
22899
|
+
}
|
|
22900
|
+
function addUnique(values, next) {
|
|
22901
|
+
if (!values.includes(next))
|
|
22902
|
+
values.push(next);
|
|
22903
|
+
}
|
|
22904
|
+
function collectRowCoverage(row, bindings) {
|
|
22905
|
+
const coverage = [];
|
|
22906
|
+
const seen = new Set;
|
|
22907
|
+
for (const selector of row.selectors) {
|
|
22908
|
+
for (const binding of bindings) {
|
|
22909
|
+
if (!matchesSelector(binding, selector))
|
|
22910
|
+
continue;
|
|
22911
|
+
const label = formatKeyBinding(binding);
|
|
22912
|
+
const key = `${binding.action}\x00${binding.scope || ""}\x00${label}`;
|
|
22913
|
+
if (seen.has(key))
|
|
22914
|
+
continue;
|
|
22915
|
+
seen.add(key);
|
|
22916
|
+
coverage.push({ action: selector.action, binding, label });
|
|
22917
|
+
}
|
|
22918
|
+
}
|
|
22919
|
+
return coverage;
|
|
22920
|
+
}
|
|
22921
|
+
function buildRow(row, language, bindings) {
|
|
22922
|
+
const labels = [];
|
|
22923
|
+
for (const item of collectRowCoverage(row, bindings))
|
|
22924
|
+
addUnique(labels, item.label);
|
|
22925
|
+
return [labels.join(" / "), row.description[language]];
|
|
22926
|
+
}
|
|
22927
|
+
function buildHelpKeybindingGroups(language, bindings = DEFAULT_KEY_BINDINGS) {
|
|
22928
|
+
return HELP_KEYBINDING_GROUPS.map((group) => ({
|
|
22929
|
+
title: group.title[language],
|
|
22930
|
+
rows: group.rows.map((row) => buildRow(row, language, bindings))
|
|
22931
|
+
}));
|
|
22932
|
+
}
|
|
22933
|
+
|
|
22541
22934
|
// web-src/views/help-page.ts
|
|
22542
22935
|
var HELP_LANGUAGES = ["en", "ja"];
|
|
22543
22936
|
var HELP_SECTIONS = [
|
|
@@ -22546,6 +22939,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22546
22939
|
"annotations",
|
|
22547
22940
|
"database",
|
|
22548
22941
|
"skills",
|
|
22942
|
+
"mcp",
|
|
22549
22943
|
"keybindings"
|
|
22550
22944
|
];
|
|
22551
22945
|
var HELP_CONTENT = {
|
|
@@ -22633,6 +23027,21 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
22633
23027
|
{
|
|
22634
23028
|
kind: "paragraph",
|
|
22635
23029
|
text: "Each row reports OK / WARN / ERROR with a remediation hint when relevant. The check groups are Runtime (Node / Bun / NODE_MODULE_VERSION), Package (version + execution origin including npx cache), SQLite driver, Snapshot store, Git, Discovery summary, Docker / Compose (CLI / v2 plugin / daemon / compose config dry-parse / compose ps health per discovered service), and Server. The most common hint is the npx cache fix for better-sqlite3 NODE_MODULE_VERSION mismatch (rm -rf ~/.npm/_npx then re-run with npx -y @youtyan/code-viewer@latest)."
|
|
23030
|
+
},
|
|
23031
|
+
{
|
|
23032
|
+
kind: "paragraph",
|
|
23033
|
+
text: 'From the terminal — and for AI agents or CI — the same report is available without a browser. `code-viewer doctor` prints a status summary; add `--json` for the full DoctorReport (matches the /_doctor endpoint). Exit code is 1 when worstStatus is "error", so it doubles as a CI gate.'
|
|
23034
|
+
},
|
|
23035
|
+
{
|
|
23036
|
+
kind: "command",
|
|
23037
|
+
title: "Doctor summary in the terminal",
|
|
23038
|
+
command: "code-viewer doctor"
|
|
23039
|
+
},
|
|
23040
|
+
{
|
|
23041
|
+
kind: "command",
|
|
23042
|
+
title: "Doctor JSON for agents and CI",
|
|
23043
|
+
command: `code-viewer doctor --json
|
|
23044
|
+
code-viewer doctor --cwd /path/to/repo --port 64160 --json`
|
|
22636
23045
|
}
|
|
22637
23046
|
]
|
|
22638
23047
|
}
|
|
@@ -22948,7 +23357,7 @@ code-viewer query clear --db app.db`
|
|
|
22948
23357
|
{
|
|
22949
23358
|
kind: "command",
|
|
22950
23359
|
title: "Search across all tables",
|
|
22951
|
-
command: 'code-viewer query search --db app.db --term "
|
|
23360
|
+
command: 'code-viewer query search --db app.db --term "sample@example.com" \\\n --tables users,orders --include-non-text --max-hits 20'
|
|
22952
23361
|
},
|
|
22953
23362
|
{
|
|
22954
23363
|
kind: "command",
|
|
@@ -22965,16 +23374,12 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
22965
23374
|
{
|
|
22966
23375
|
kind: "command",
|
|
22967
23376
|
title: "Diff two snapshots",
|
|
22968
|
-
command:
|
|
22969
|
-
--note "User registration test"
|
|
22970
|
-
code-viewer query diff list --db app.db --json
|
|
22971
|
-
code-viewer query diff delete --id diff-xyz789`
|
|
23377
|
+
command: "code-viewer query diff tables --before snap-abc123 --after snap-def456 --json"
|
|
22972
23378
|
},
|
|
22973
23379
|
{
|
|
22974
23380
|
kind: "command",
|
|
22975
23381
|
title: "Inspect a diff",
|
|
22976
|
-
command:
|
|
22977
|
-
code-viewer query diff rows --id diff-xyz789 --table users --type inserted --limit 50`
|
|
23382
|
+
command: "code-viewer query diff rows --before snap-abc123 --after snap-def456 --table users --limit 50"
|
|
22978
23383
|
},
|
|
22979
23384
|
{
|
|
22980
23385
|
kind: "command",
|
|
@@ -23060,63 +23465,120 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23060
23465
|
}
|
|
23061
23466
|
]
|
|
23062
23467
|
},
|
|
23063
|
-
|
|
23064
|
-
nav: "
|
|
23065
|
-
title: "
|
|
23066
|
-
intro: "
|
|
23468
|
+
mcp: {
|
|
23469
|
+
nav: "MCP Server",
|
|
23470
|
+
title: "MCP Server",
|
|
23471
|
+
intro: "While code-viewer is running, the same server also exposes a local, read-only MCP endpoint at /_mcp so AI agents can call status, file, search, and datastore tools directly over JSON-RPC instead of spawning code-viewer CLI subprocesses.",
|
|
23067
23472
|
groups: [
|
|
23068
23473
|
{
|
|
23069
|
-
title: "
|
|
23474
|
+
title: "Connect to the endpoint",
|
|
23070
23475
|
blocks: [
|
|
23071
23476
|
{
|
|
23072
|
-
kind: "
|
|
23073
|
-
|
|
23074
|
-
|
|
23075
|
-
["Ctrl+G", "Open grep palette"],
|
|
23076
|
-
["/", "Focus file filter"],
|
|
23077
|
-
["t", "Toggle theme"],
|
|
23078
|
-
["[ / ]", "Previous / next annotation"]
|
|
23079
|
-
]
|
|
23080
|
-
}
|
|
23081
|
-
]
|
|
23082
|
-
},
|
|
23083
|
-
{
|
|
23084
|
-
title: "Panels",
|
|
23085
|
-
blocks: [
|
|
23477
|
+
kind: "paragraph",
|
|
23478
|
+
text: "The endpoint speaks JSON-RPC 2.0 over the Streamable HTTP transport (initialize, ping, tools/list, tools/call). It accepts POST requests with an application/json body only, and is guarded by the same localhost / same-origin check as every other route."
|
|
23479
|
+
},
|
|
23086
23480
|
{
|
|
23087
|
-
kind: "
|
|
23088
|
-
|
|
23089
|
-
|
|
23090
|
-
["Ctrl+L", "Focus main panel"]
|
|
23091
|
-
]
|
|
23481
|
+
kind: "command",
|
|
23482
|
+
title: "Endpoint URL (port from the printed startup URL)",
|
|
23483
|
+
command: "http://127.0.0.1:<port>/_mcp"
|
|
23092
23484
|
}
|
|
23093
23485
|
]
|
|
23094
23486
|
},
|
|
23095
23487
|
{
|
|
23096
|
-
title: "
|
|
23488
|
+
title: "Available tools",
|
|
23097
23489
|
blocks: [
|
|
23098
23490
|
{
|
|
23099
23491
|
kind: "table",
|
|
23100
23492
|
rows: [
|
|
23101
|
-
[
|
|
23102
|
-
|
|
23103
|
-
|
|
23104
|
-
|
|
23105
|
-
[
|
|
23493
|
+
[
|
|
23494
|
+
"code_viewer_agent_help",
|
|
23495
|
+
"Index of every AI-facing CLI subcommand."
|
|
23496
|
+
],
|
|
23497
|
+
[
|
|
23498
|
+
"code_viewer_status",
|
|
23499
|
+
"Branch, remote, changed files, and recent commits."
|
|
23500
|
+
],
|
|
23501
|
+
[
|
|
23502
|
+
"code_viewer_file_show",
|
|
23503
|
+
"Read a file (optionally a line range) at any ref."
|
|
23504
|
+
],
|
|
23505
|
+
[
|
|
23506
|
+
"code_viewer_file_blame",
|
|
23507
|
+
"Per-line blame (sha / author / time / summary)."
|
|
23508
|
+
],
|
|
23509
|
+
[
|
|
23510
|
+
"code_viewer_file_history",
|
|
23511
|
+
"Commit history for one path (follows renames)."
|
|
23512
|
+
],
|
|
23513
|
+
[
|
|
23514
|
+
"code_viewer_file_diff",
|
|
23515
|
+
"Unified diff for one path (preview-capped by default)."
|
|
23516
|
+
],
|
|
23517
|
+
[
|
|
23518
|
+
"code_viewer_search_files",
|
|
23519
|
+
"Rank repository paths by fuzzy or glob match."
|
|
23520
|
+
],
|
|
23521
|
+
[
|
|
23522
|
+
"code_viewer_search_code",
|
|
23523
|
+
"Grep the repository (rg / git grep / fallback)."
|
|
23524
|
+
],
|
|
23525
|
+
[
|
|
23526
|
+
"code_viewer_datastore_sources",
|
|
23527
|
+
"Discover read-only datastore source ids."
|
|
23528
|
+
],
|
|
23529
|
+
[
|
|
23530
|
+
"code_viewer_datastore_schemas",
|
|
23531
|
+
"List schemas for one SQL datastore."
|
|
23532
|
+
],
|
|
23533
|
+
[
|
|
23534
|
+
"code_viewer_datastore_schema",
|
|
23535
|
+
"Inspect tables, indexes, FKs, and columns."
|
|
23536
|
+
],
|
|
23537
|
+
[
|
|
23538
|
+
"code_viewer_datastore_columns",
|
|
23539
|
+
"Inspect columns for one SQL table."
|
|
23540
|
+
],
|
|
23541
|
+
[
|
|
23542
|
+
"code_viewer_datastore_ddl",
|
|
23543
|
+
"Inspect the CREATE statement and triggers."
|
|
23544
|
+
],
|
|
23545
|
+
[
|
|
23546
|
+
"code_viewer_datastore_query",
|
|
23547
|
+
"Run a read-only SELECT / PRAGMA / EXPLAIN / WITH."
|
|
23548
|
+
],
|
|
23549
|
+
[
|
|
23550
|
+
"code_viewer_datastore_history",
|
|
23551
|
+
"Inspect saved query history."
|
|
23552
|
+
]
|
|
23106
23553
|
]
|
|
23107
23554
|
}
|
|
23108
23555
|
]
|
|
23109
|
-
}
|
|
23556
|
+
}
|
|
23557
|
+
]
|
|
23558
|
+
},
|
|
23559
|
+
keybindings: {
|
|
23560
|
+
nav: "Keybindings",
|
|
23561
|
+
title: "Keyboard Shortcuts",
|
|
23562
|
+
intro: "Use these shortcuts to move between panels and navigate files without leaving the keyboard.",
|
|
23563
|
+
groups: [
|
|
23110
23564
|
{
|
|
23111
|
-
title: "
|
|
23565
|
+
title: "Line selection",
|
|
23112
23566
|
blocks: [
|
|
23113
23567
|
{
|
|
23114
23568
|
kind: "table",
|
|
23115
23569
|
rows: [
|
|
23116
|
-
[
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23570
|
+
[
|
|
23571
|
+
"Drag on line numbers",
|
|
23572
|
+
"Highlight a range; the floating copy pill prepares @path#L1-L9"
|
|
23573
|
+
],
|
|
23574
|
+
[
|
|
23575
|
+
"Click the pill",
|
|
23576
|
+
"Copy @path#L1-L9 to the clipboard for pasting into Claude Code / Codex"
|
|
23577
|
+
],
|
|
23578
|
+
[
|
|
23579
|
+
"Shift+Click the pill",
|
|
23580
|
+
"Copy @path#L1-L9 plus a fenced code block of the selected lines — paste straight to an AI without re-fetching the file"
|
|
23581
|
+
]
|
|
23120
23582
|
]
|
|
23121
23583
|
}
|
|
23122
23584
|
]
|
|
@@ -23209,6 +23671,21 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23209
23671
|
{
|
|
23210
23672
|
kind: "paragraph",
|
|
23211
23673
|
text: "各項目は OK / WARN / ERROR で表示され、必要に応じて対処手順のヒントが付きます。診断グループは Runtime (Node / Bun / NODE_MODULE_VERSION)、Package (バージョン + 実行元: npx cache / global / local / bunx)、SQLite driver、Snapshot store、Git、Discovery summary、Docker / Compose (CLI / v2 plugin / daemon / compose config dry parse / compose ps による各サービスのヘルス)、Server (待ち受けポート) の 8 つ。よくあるヒントは npx キャッシュ起因の better-sqlite3 NODE_MODULE_VERSION 不一致で、rm -rf ~/.npm/_npx の後に npx -y @youtyan/code-viewer@latest を再実行する手順を表示します。"
|
|
23674
|
+
},
|
|
23675
|
+
{
|
|
23676
|
+
kind: "paragraph",
|
|
23677
|
+
text: 'ターミナルからは `code-viewer doctor` で同じレポートを取得できます。AI エージェントや CI からは `--json` で /_doctor と同じ DoctorReport を受け取れます。worstStatus が "error" なら exit code 1 を返すので CI ガードに直接使えます。'
|
|
23678
|
+
},
|
|
23679
|
+
{
|
|
23680
|
+
kind: "command",
|
|
23681
|
+
title: "ターミナル用 doctor サマリー",
|
|
23682
|
+
command: "code-viewer doctor"
|
|
23683
|
+
},
|
|
23684
|
+
{
|
|
23685
|
+
kind: "command",
|
|
23686
|
+
title: "AI / CI 用 doctor JSON",
|
|
23687
|
+
command: `code-viewer doctor --json
|
|
23688
|
+
code-viewer doctor --cwd /path/to/repo --port 64160 --json`
|
|
23212
23689
|
}
|
|
23213
23690
|
]
|
|
23214
23691
|
}
|
|
@@ -23524,7 +24001,7 @@ code-viewer query clear --db app.db`
|
|
|
23524
24001
|
{
|
|
23525
24002
|
kind: "command",
|
|
23526
24003
|
title: "テーブル横断の全文検索",
|
|
23527
|
-
command: 'code-viewer query search --db app.db --term "
|
|
24004
|
+
command: 'code-viewer query search --db app.db --term "sample@example.com" \\\n --tables users,orders --include-non-text --max-hits 20'
|
|
23528
24005
|
},
|
|
23529
24006
|
{
|
|
23530
24007
|
kind: "command",
|
|
@@ -23541,16 +24018,12 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
23541
24018
|
{
|
|
23542
24019
|
kind: "command",
|
|
23543
24020
|
title: "2 つのスナップショットを diff",
|
|
23544
|
-
command:
|
|
23545
|
-
--note "ユーザー登録テストの差分"
|
|
23546
|
-
code-viewer query diff list --db app.db --json
|
|
23547
|
-
code-viewer query diff delete --id diff-xyz789`
|
|
24021
|
+
command: "code-viewer query diff tables --before snap-abc123 --after snap-def456 --json"
|
|
23548
24022
|
},
|
|
23549
24023
|
{
|
|
23550
24024
|
kind: "command",
|
|
23551
24025
|
title: "diff の中身を確認",
|
|
23552
|
-
command:
|
|
23553
|
-
code-viewer query diff rows --id diff-xyz789 --table users --type inserted --limit 50`
|
|
24026
|
+
command: "code-viewer query diff rows --before snap-abc123 --after snap-def456 --table users --limit 50"
|
|
23554
24027
|
},
|
|
23555
24028
|
{
|
|
23556
24029
|
kind: "command",
|
|
@@ -23636,63 +24109,117 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23636
24109
|
}
|
|
23637
24110
|
]
|
|
23638
24111
|
},
|
|
23639
|
-
|
|
23640
|
-
nav: "
|
|
23641
|
-
title: "
|
|
23642
|
-
intro: "
|
|
24112
|
+
mcp: {
|
|
24113
|
+
nav: "MCPサーバー",
|
|
24114
|
+
title: "MCPサーバー",
|
|
24115
|
+
intro: "code-viewer を起動している間、同じサーバーがローカルの read-only な MCP エンドポイント (/_mcp) も公開します。AI エージェントは code-viewer の CLI をサブプロセスとして起動する代わりに、status / file / search / datastore の各ツールを JSON-RPC 経由で直接呼び出せます。",
|
|
23643
24116
|
groups: [
|
|
23644
24117
|
{
|
|
23645
|
-
title: "
|
|
24118
|
+
title: "エンドポイントへの接続",
|
|
23646
24119
|
blocks: [
|
|
23647
24120
|
{
|
|
23648
|
-
kind: "
|
|
23649
|
-
|
|
23650
|
-
|
|
23651
|
-
["Ctrl+G", "grep パレットを開く"],
|
|
23652
|
-
["/", "ファイルフィルターへフォーカス"],
|
|
23653
|
-
["t", "テーマ切り替え"],
|
|
23654
|
-
["[ / ]", "前 / 次の注釈へ移動"]
|
|
23655
|
-
]
|
|
23656
|
-
}
|
|
23657
|
-
]
|
|
23658
|
-
},
|
|
23659
|
-
{
|
|
23660
|
-
title: "パネル",
|
|
23661
|
-
blocks: [
|
|
24121
|
+
kind: "paragraph",
|
|
24122
|
+
text: "エンドポイントは JSON-RPC 2.0 の Streamable HTTP トランスポート (initialize / ping / tools/list / tools/call) で応答します。受け付けるのは application/json ボディの POST リクエストのみで、他のルートと同じ localhost / 同一オリジンチェックで保護されています。"
|
|
24123
|
+
},
|
|
23662
24124
|
{
|
|
23663
|
-
kind: "
|
|
23664
|
-
|
|
23665
|
-
|
|
23666
|
-
["Ctrl+L", "メインパネルへフォーカス"]
|
|
23667
|
-
]
|
|
24125
|
+
kind: "command",
|
|
24126
|
+
title: "エンドポイント URL (port は起動時に表示される URL と同じ)",
|
|
24127
|
+
command: "http://127.0.0.1:<port>/_mcp"
|
|
23668
24128
|
}
|
|
23669
24129
|
]
|
|
23670
24130
|
},
|
|
23671
24131
|
{
|
|
23672
|
-
title: "
|
|
24132
|
+
title: "利用できるツール",
|
|
23673
24133
|
blocks: [
|
|
23674
24134
|
{
|
|
23675
24135
|
kind: "table",
|
|
23676
24136
|
rows: [
|
|
23677
|
-
[
|
|
23678
|
-
|
|
23679
|
-
|
|
23680
|
-
|
|
23681
|
-
[
|
|
24137
|
+
[
|
|
24138
|
+
"code_viewer_agent_help",
|
|
24139
|
+
"AI 向け CLI サブコマンドの一覧索引。"
|
|
24140
|
+
],
|
|
24141
|
+
[
|
|
24142
|
+
"code_viewer_status",
|
|
24143
|
+
"ブランチ、remote、変更ファイル、直近のコミット。"
|
|
24144
|
+
],
|
|
24145
|
+
[
|
|
24146
|
+
"code_viewer_file_show",
|
|
24147
|
+
"任意の ref でファイル(または行範囲)を読む。"
|
|
24148
|
+
],
|
|
24149
|
+
[
|
|
24150
|
+
"code_viewer_file_blame",
|
|
24151
|
+
"行単位の blame (sha / author / time / summary)。"
|
|
24152
|
+
],
|
|
24153
|
+
[
|
|
24154
|
+
"code_viewer_file_history",
|
|
24155
|
+
"1ファイルのコミット履歴(リネーム追跡あり)。"
|
|
24156
|
+
],
|
|
24157
|
+
[
|
|
24158
|
+
"code_viewer_file_diff",
|
|
24159
|
+
"1ファイルの unified diff(既定はプレビュー上限あり)。"
|
|
24160
|
+
],
|
|
24161
|
+
[
|
|
24162
|
+
"code_viewer_search_files",
|
|
24163
|
+
"ファジー / glob マッチでリポジトリのパスを順位付け。"
|
|
24164
|
+
],
|
|
24165
|
+
[
|
|
24166
|
+
"code_viewer_search_code",
|
|
24167
|
+
"リポジトリを grep する (rg / git grep / フォールバック)。"
|
|
24168
|
+
],
|
|
24169
|
+
[
|
|
24170
|
+
"code_viewer_datastore_sources",
|
|
24171
|
+
"read-only なデータストアの source id を発見。"
|
|
24172
|
+
],
|
|
24173
|
+
[
|
|
24174
|
+
"code_viewer_datastore_schemas",
|
|
24175
|
+
"SQL データストア1件のスキーマ一覧。"
|
|
24176
|
+
],
|
|
24177
|
+
[
|
|
24178
|
+
"code_viewer_datastore_schema",
|
|
24179
|
+
"テーブル、インデックス、外部キー、カラムを調査。"
|
|
24180
|
+
],
|
|
24181
|
+
[
|
|
24182
|
+
"code_viewer_datastore_columns",
|
|
24183
|
+
"SQL テーブル1件のカラムを調査。"
|
|
24184
|
+
],
|
|
24185
|
+
["code_viewer_datastore_ddl", "CREATE 文とトリガーを調査。"],
|
|
24186
|
+
[
|
|
24187
|
+
"code_viewer_datastore_query",
|
|
24188
|
+
"read-only な SELECT / PRAGMA / EXPLAIN / WITH を実行。"
|
|
24189
|
+
],
|
|
24190
|
+
[
|
|
24191
|
+
"code_viewer_datastore_history",
|
|
24192
|
+
"保存済みのクエリ履歴を調査。"
|
|
24193
|
+
]
|
|
23682
24194
|
]
|
|
23683
24195
|
}
|
|
23684
24196
|
]
|
|
23685
|
-
}
|
|
24197
|
+
}
|
|
24198
|
+
]
|
|
24199
|
+
},
|
|
24200
|
+
keybindings: {
|
|
24201
|
+
nav: "キーバインド",
|
|
24202
|
+
title: "キーバインド",
|
|
24203
|
+
intro: "キーボードだけでパネル移動、ファイル選択、スクロールを行うためのショートカットです。",
|
|
24204
|
+
groups: [
|
|
23686
24205
|
{
|
|
23687
|
-
title: "
|
|
24206
|
+
title: "行選択",
|
|
23688
24207
|
blocks: [
|
|
23689
24208
|
{
|
|
23690
24209
|
kind: "table",
|
|
23691
24210
|
rows: [
|
|
23692
|
-
[
|
|
23693
|
-
|
|
23694
|
-
|
|
23695
|
-
|
|
24211
|
+
[
|
|
24212
|
+
"行番号でドラッグ",
|
|
24213
|
+
"範囲をハイライトし、フロートする Copy ピルが @path#L1-L9 を用意"
|
|
24214
|
+
],
|
|
24215
|
+
[
|
|
24216
|
+
"ピルをクリック",
|
|
24217
|
+
"@path#L1-L9 をコピー(Claude Code / Codex への貼り付け用)"
|
|
24218
|
+
],
|
|
24219
|
+
[
|
|
24220
|
+
"Shift+ピルをクリック",
|
|
24221
|
+
"@path#L1-L9 と選択行の実コード(フェンス付き)をまとめてコピー — AI へ直接貼れて、ファイル再取得不要"
|
|
24222
|
+
]
|
|
23696
24223
|
]
|
|
23697
24224
|
}
|
|
23698
24225
|
]
|
|
@@ -23708,6 +24235,19 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23708
24235
|
function helpSectionFromRoute(route) {
|
|
23709
24236
|
return route.screen === "help" && HELP_SECTIONS.includes(route.section) ? route.section : "overview";
|
|
23710
24237
|
}
|
|
24238
|
+
function openHelpKeybindings(deps) {
|
|
24239
|
+
const route = deps.getRoute();
|
|
24240
|
+
deps.cancelActiveSourceLoad("navigation");
|
|
24241
|
+
deps.setRoute({
|
|
24242
|
+
screen: "help",
|
|
24243
|
+
lang: route.screen === "help" ? helpLanguageFromRoute(route) : deps.getLanguage(),
|
|
24244
|
+
section: "keybindings",
|
|
24245
|
+
range: deps.currentRange()
|
|
24246
|
+
});
|
|
24247
|
+
deps.setPageMode();
|
|
24248
|
+
deps.renderHelpPage();
|
|
24249
|
+
deps.setStatus("live");
|
|
24250
|
+
}
|
|
23711
24251
|
function renderHelpCommand(block2) {
|
|
23712
24252
|
const wrap = document.createElement("div");
|
|
23713
24253
|
wrap.className = "gdp-help-command";
|
|
@@ -23776,6 +24316,13 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23776
24316
|
const section = helpSectionFromRoute(deps.getRoute());
|
|
23777
24317
|
const content = HELP_CONTENT[lang];
|
|
23778
24318
|
const sectionContent = content.sections[section];
|
|
24319
|
+
const sectionGroups = section === "keybindings" ? [
|
|
24320
|
+
...buildHelpKeybindingGroups(lang).map((group) => ({
|
|
24321
|
+
title: group.title,
|
|
24322
|
+
blocks: [{ kind: "table", rows: group.rows }]
|
|
24323
|
+
})),
|
|
24324
|
+
...sectionContent.groups
|
|
24325
|
+
] : sectionContent.groups;
|
|
23779
24326
|
const shell = document.createElement("section");
|
|
23780
24327
|
shell.className = "gdp-help-shell";
|
|
23781
24328
|
const header = document.createElement("header");
|
|
@@ -23825,7 +24372,7 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
23825
24372
|
const intro = document.createElement("p");
|
|
23826
24373
|
intro.textContent = sectionContent.intro;
|
|
23827
24374
|
article.append(h2, intro);
|
|
23828
|
-
|
|
24375
|
+
sectionGroups.forEach((group) => {
|
|
23829
24376
|
const groupSection = document.createElement("section");
|
|
23830
24377
|
groupSection.className = "gdp-help-group";
|
|
23831
24378
|
const groupTitle = document.createElement("h3");
|
|
@@ -24233,39 +24780,109 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
24233
24780
|
return { setupHunkExpand };
|
|
24234
24781
|
}
|
|
24235
24782
|
|
|
24783
|
+
// web-src/core/html-escape.ts
|
|
24784
|
+
function escapeHtml2(value) {
|
|
24785
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
24786
|
+
}
|
|
24787
|
+
|
|
24236
24788
|
// web-src/views/line-ref-pill.ts
|
|
24237
24789
|
var COPY_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" fill="currentColor">' + '<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>' + '<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>' + "</svg>";
|
|
24238
24790
|
var CHECK_ICON = '<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" fill="currentColor">' + '<path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"/>' + "</svg>";
|
|
24239
|
-
function
|
|
24240
|
-
|
|
24791
|
+
function langFromPath(path) {
|
|
24792
|
+
const m = path.match(/\.([^./]+)$/);
|
|
24793
|
+
if (!m)
|
|
24794
|
+
return "";
|
|
24795
|
+
return EXT_TO_LANG[m[1].toLowerCase()] || "";
|
|
24796
|
+
}
|
|
24797
|
+
function readRenderedLines(path, start, end) {
|
|
24798
|
+
const card = document.querySelector(`.gdp-file-shell[data-path="${CSS.escape(path)}"]`);
|
|
24799
|
+
if (!card)
|
|
24800
|
+
return [];
|
|
24801
|
+
const out = [];
|
|
24802
|
+
for (let line = start;line <= end; line++) {
|
|
24803
|
+
const sourceRow = card.querySelector(`.gdp-source-table tr[data-line="${String(line)}"]`);
|
|
24804
|
+
if (sourceRow) {
|
|
24805
|
+
const code2 = sourceRow.querySelector(".gdp-source-line-code");
|
|
24806
|
+
out.push(code2?.textContent ?? "");
|
|
24807
|
+
}
|
|
24808
|
+
}
|
|
24809
|
+
if (out.length > 0 && out.some((value) => value.length > 0))
|
|
24810
|
+
return out;
|
|
24811
|
+
const diffRows = card.querySelectorAll("table.d2h-diff-table tr");
|
|
24812
|
+
if (diffRows.length === 0)
|
|
24813
|
+
return [];
|
|
24814
|
+
const collected = new Map;
|
|
24815
|
+
diffRows.forEach((row) => {
|
|
24816
|
+
const sideCell = row.querySelector("td.d2h-code-linenumber, td.d2h-code-side-linenumber");
|
|
24817
|
+
if (!sideCell)
|
|
24818
|
+
return;
|
|
24819
|
+
const side = sideCell.closest(".d2h-file-side-diff");
|
|
24820
|
+
const wrapper = sideCell.closest(".d2h-file-wrapper");
|
|
24821
|
+
if (side && wrapper) {
|
|
24822
|
+
const sides = wrapper.querySelectorAll(".d2h-file-side-diff");
|
|
24823
|
+
if (sides.length >= 2 && side !== sides[1])
|
|
24824
|
+
return;
|
|
24825
|
+
}
|
|
24826
|
+
const numText = sideCell.querySelector(".line-num2")?.textContent ?? sideCell.textContent ?? "";
|
|
24827
|
+
const line = Number(numText.trim());
|
|
24828
|
+
if (!Number.isInteger(line) || line < start || line > end)
|
|
24829
|
+
return;
|
|
24830
|
+
const codeCell = row.querySelector(".d2h-code-line-ctn");
|
|
24831
|
+
if (codeCell)
|
|
24832
|
+
collected.set(line, codeCell.textContent ?? "");
|
|
24833
|
+
});
|
|
24834
|
+
if (collected.size === 0)
|
|
24835
|
+
return [];
|
|
24836
|
+
const ordered = [];
|
|
24837
|
+
for (let line = start;line <= end; line++) {
|
|
24838
|
+
ordered.push(collected.get(line) ?? "");
|
|
24839
|
+
}
|
|
24840
|
+
return ordered;
|
|
24241
24841
|
}
|
|
24242
24842
|
function createLineRefPill() {
|
|
24243
24843
|
const pill = document.createElement("button");
|
|
24244
24844
|
pill.id = "line-ref-pill";
|
|
24245
24845
|
pill.type = "button";
|
|
24246
|
-
pill.title = "選択行の参照をコピー(Claude Code / Codex
|
|
24846
|
+
pill.title = "選択行の参照をコピー(Claude Code / Codex に貼り付け用)。Shift+Click でコード本体も添付。";
|
|
24247
24847
|
pill.hidden = true;
|
|
24248
24848
|
document.body.appendChild(pill);
|
|
24249
24849
|
let refText = "";
|
|
24850
|
+
let currentPath = "";
|
|
24851
|
+
let currentStart = 0;
|
|
24852
|
+
let currentEnd = 0;
|
|
24250
24853
|
let feedbackTimer = null;
|
|
24251
24854
|
function render(state) {
|
|
24252
|
-
pill.classList.toggle("copied", state === "copied");
|
|
24855
|
+
pill.classList.toggle("copied", state === "copied" || state === "copied-code");
|
|
24253
24856
|
if (state === "copied") {
|
|
24254
24857
|
pill.innerHTML = `${CHECK_ICON}<span class="lrp-label">Copied!</span>`;
|
|
24255
24858
|
return;
|
|
24256
24859
|
}
|
|
24860
|
+
if (state === "copied-code") {
|
|
24861
|
+
pill.innerHTML = `${CHECK_ICON}<span class="lrp-label">Copied + code</span>`;
|
|
24862
|
+
return;
|
|
24863
|
+
}
|
|
24257
24864
|
if (state === "failed") {
|
|
24258
24865
|
pill.innerHTML = `${COPY_ICON}<span class="lrp-label">copy failed</span>`;
|
|
24259
24866
|
return;
|
|
24260
24867
|
}
|
|
24261
24868
|
pill.innerHTML = `${COPY_ICON}<span class="lrp-label">Copy</span>` + `<span class="lrp-ref">${escapeHtml2(refText)}</span>`;
|
|
24262
24869
|
}
|
|
24263
|
-
pill.addEventListener("click", async () => {
|
|
24870
|
+
pill.addEventListener("click", async (event) => {
|
|
24264
24871
|
if (!refText)
|
|
24265
24872
|
return;
|
|
24873
|
+
const withCode = event.shiftKey;
|
|
24874
|
+
let payload = refText;
|
|
24875
|
+
let copiedCode = false;
|
|
24876
|
+
if (withCode && currentPath) {
|
|
24877
|
+
const lines = readRenderedLines(currentPath, currentStart, currentEnd);
|
|
24878
|
+
if (lines.length > 0) {
|
|
24879
|
+
payload = fileReferenceWithCodeClipboardText(currentPath, currentStart, currentEnd, lines, langFromPath(currentPath));
|
|
24880
|
+
copiedCode = true;
|
|
24881
|
+
}
|
|
24882
|
+
}
|
|
24266
24883
|
try {
|
|
24267
|
-
await navigator.clipboard.writeText(
|
|
24268
|
-
render("copied");
|
|
24884
|
+
await navigator.clipboard.writeText(payload);
|
|
24885
|
+
render(copiedCode ? "copied-code" : "copied");
|
|
24269
24886
|
} catch {
|
|
24270
24887
|
render("failed");
|
|
24271
24888
|
}
|
|
@@ -24284,6 +24901,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
24284
24901
|
return;
|
|
24285
24902
|
const changed = next !== refText;
|
|
24286
24903
|
refText = next;
|
|
24904
|
+
currentPath = path;
|
|
24905
|
+
currentStart = Math.max(1, Math.floor(Math.min(start, end)));
|
|
24906
|
+
currentEnd = Math.max(1, Math.floor(Math.max(start, end)));
|
|
24287
24907
|
if (feedbackTimer) {
|
|
24288
24908
|
clearTimeout(feedbackTimer);
|
|
24289
24909
|
feedbackTimer = null;
|
|
@@ -24298,6 +24918,9 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
24298
24918
|
},
|
|
24299
24919
|
hide() {
|
|
24300
24920
|
refText = "";
|
|
24921
|
+
currentPath = "";
|
|
24922
|
+
currentStart = 0;
|
|
24923
|
+
currentEnd = 0;
|
|
24301
24924
|
pill.hidden = true;
|
|
24302
24925
|
}
|
|
24303
24926
|
};
|
|
@@ -24563,6 +25186,11 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
24563
25186
|
wireRefSelectorInput(refToInput, () => deps.setRange(refFromInput.value, refToInput.value));
|
|
24564
25187
|
wireRefSelectorInput(deps.$("#repo-target"), (ref) => {
|
|
24565
25188
|
const route = deps.getRoute();
|
|
25189
|
+
if (route.screen === "repo") {
|
|
25190
|
+
deps.setRoute({ ...route, ref, range: deps.currentRange() });
|
|
25191
|
+
deps.loadRepo();
|
|
25192
|
+
return;
|
|
25193
|
+
}
|
|
24566
25194
|
if (route.screen !== "file")
|
|
24567
25195
|
return;
|
|
24568
25196
|
const nextRoute = {
|
|
@@ -25526,6 +26154,13 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
25526
26154
|
function renderSidebar(files, onFileClick) {
|
|
25527
26155
|
const ul = $("#filelist");
|
|
25528
26156
|
const repoSidebar = !!onFileClick;
|
|
26157
|
+
if (!repoSidebar) {
|
|
26158
|
+
const repoTarget = document.querySelector("#repo-target-wrap");
|
|
26159
|
+
if (repoTarget) {
|
|
26160
|
+
repoTarget.hidden = true;
|
|
26161
|
+
repoTarget.style.display = "none";
|
|
26162
|
+
}
|
|
26163
|
+
}
|
|
25529
26164
|
const treeMode = STATE.sbView === "tree" || repoSidebar;
|
|
25530
26165
|
ul.innerHTML = "";
|
|
25531
26166
|
ul.classList.toggle("tree", treeMode);
|
|
@@ -26174,8 +26809,10 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
26174
26809
|
const wrap = document.querySelector("#repo-target-wrap");
|
|
26175
26810
|
if (!input || !wrap)
|
|
26176
26811
|
return;
|
|
26177
|
-
|
|
26178
|
-
|
|
26812
|
+
const activeRef = activeRepoTreeRef();
|
|
26813
|
+
input.value = activeRef || ref || "worktree";
|
|
26814
|
+
wrap.hidden = activeRef == null;
|
|
26815
|
+
wrap.style.display = activeRef == null ? "none" : "";
|
|
26179
26816
|
syncSidebarHeaderHeight();
|
|
26180
26817
|
}
|
|
26181
26818
|
function activeRepoTreeRef() {
|
|
@@ -29961,8 +30598,8 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
29961
30598
|
view: "view",
|
|
29962
30599
|
tree: "tree",
|
|
29963
30600
|
flat: "flat",
|
|
29964
|
-
filter: "Filter files
|
|
29965
|
-
filterTitle: "Filter files. Use /pattern/ for regex. Cmd/Ctrl+K
|
|
30601
|
+
filter: "Filter files… / ⌘K",
|
|
30602
|
+
filterTitle: "Filter files. Use /pattern/ for regex. Press / to focus this field, Cmd/Ctrl+K for the full-file palette, Ctrl+G for grep, ? for help.",
|
|
29966
30603
|
hide: "hide sidebar"
|
|
29967
30604
|
},
|
|
29968
30605
|
history: {
|
|
@@ -30067,8 +30704,8 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30067
30704
|
view: "表示",
|
|
30068
30705
|
tree: "ツリー",
|
|
30069
30706
|
flat: "一覧",
|
|
30070
|
-
filter: "
|
|
30071
|
-
filterTitle: "
|
|
30707
|
+
filter: "ファイル絞り込み… / ⌘K",
|
|
30708
|
+
filterTitle: "ファイルを絞り込みます。/pattern/ は正規表現。/ でこの欄にフォーカス、Cmd/Ctrl+K で全ファイルパレット、Ctrl+G で grep、? でヘルプ。",
|
|
30072
30709
|
hide: "サイドバーを隠す"
|
|
30073
30710
|
},
|
|
30074
30711
|
history: {
|
|
@@ -30804,13 +31441,21 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
30804
31441
|
function setPageMode() {
|
|
30805
31442
|
const historyPanelRoute = STATE.route.screen === "history";
|
|
30806
31443
|
const fileHistoryRoute = isFileHistoryRoute(STATE.route);
|
|
31444
|
+
const fileRepoBlobRoute = STATE.route.screen === "file" && (STATE.route.view === "blob" || STATE.route.view === "blame" || STATE.route.view === "history");
|
|
31445
|
+
const repoSidebarRoute = STATE.route.screen === "repo" || fileRepoBlobRoute;
|
|
30807
31446
|
document.body.classList.toggle("gdp-file-detail-page", STATE.route.screen === "file");
|
|
30808
|
-
document.body.classList.toggle("gdp-repo-blob-page",
|
|
31447
|
+
document.body.classList.toggle("gdp-repo-blob-page", fileRepoBlobRoute);
|
|
30809
31448
|
document.body.classList.toggle("gdp-repo-page", STATE.route.screen === "repo");
|
|
31449
|
+
document.body.classList.toggle("gdp-diff-page", STATE.route.screen === "diff");
|
|
30810
31450
|
document.body.classList.toggle("gdp-help-page", STATE.route.screen === "help");
|
|
30811
31451
|
document.body.classList.toggle("gdp-history-page", historyPanelRoute);
|
|
30812
31452
|
document.body.classList.toggle("gdp-file-history-page", fileHistoryRoute);
|
|
30813
31453
|
document.body.classList.toggle("gdp-database-page", STATE.route.screen === "database");
|
|
31454
|
+
const repoTargetWrap = document.querySelector("#repo-target-wrap");
|
|
31455
|
+
if (!repoSidebarRoute && repoTargetWrap) {
|
|
31456
|
+
repoTargetWrap.hidden = true;
|
|
31457
|
+
repoTargetWrap.style.display = "none";
|
|
31458
|
+
}
|
|
30814
31459
|
placeSidebarToggle();
|
|
30815
31460
|
syncSidebarHeaderHeight();
|
|
30816
31461
|
const historyPanel = $("#history-panel");
|
|
@@ -31405,6 +32050,19 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
31405
32050
|
$("#theme").click();
|
|
31406
32051
|
return true;
|
|
31407
32052
|
}
|
|
32053
|
+
if (action === "open-help") {
|
|
32054
|
+
openHelpKeybindings({
|
|
32055
|
+
getRoute: () => STATE.route,
|
|
32056
|
+
getLanguage: () => STATE.language,
|
|
32057
|
+
currentRange,
|
|
32058
|
+
setRoute,
|
|
32059
|
+
setPageMode,
|
|
32060
|
+
renderHelpPage,
|
|
32061
|
+
setStatus,
|
|
32062
|
+
cancelActiveSourceLoad
|
|
32063
|
+
});
|
|
32064
|
+
return true;
|
|
32065
|
+
}
|
|
31408
32066
|
return false;
|
|
31409
32067
|
}
|
|
31410
32068
|
document.addEventListener("keydown", handleVirtualSourcePagingKeydown, {
|
|
@@ -31575,6 +32233,8 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
31575
32233
|
getRoute: () => STATE.route,
|
|
31576
32234
|
setRoute,
|
|
31577
32235
|
applyCommitRange: (range, pathFilter) => {
|
|
32236
|
+
cancelInFlightRequests();
|
|
32237
|
+
DIFF_VIEW.clearLoadQueue();
|
|
31578
32238
|
STATE.from = range.from;
|
|
31579
32239
|
STATE.to = range.to;
|
|
31580
32240
|
activeHistoryPathFilter = pathFilter || null;
|
|
@@ -31706,6 +32366,7 @@ code-viewer query diff rows --id diff-xyz789 --table users --type inserted --lim
|
|
|
31706
32366
|
currentRange,
|
|
31707
32367
|
setRange,
|
|
31708
32368
|
setRoute,
|
|
32369
|
+
loadRepo,
|
|
31709
32370
|
renderStandaloneSource,
|
|
31710
32371
|
getFrom: () => STATE.from,
|
|
31711
32372
|
getTo: () => STATE.to,
|