@youtyan/code-viewer 0.8.6 → 0.8.7
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/dist/code-viewer.js +44 -23
- package/package.json +1 -1
- package/web/app.js +73 -13
package/dist/code-viewer.js
CHANGED
|
@@ -1449,18 +1449,13 @@ function resolveGitArgs(args) {
|
|
|
1449
1449
|
return [commandForExternal("git"), ...args.slice(1)];
|
|
1450
1450
|
}
|
|
1451
1451
|
function gitFailureMessage(res, fallback) {
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
return
|
|
1452
|
+
const message = isCommandNotFoundResult("git", res) ? commandNotFoundDetail("git") : res.stderr?.trim() || fallback;
|
|
1453
|
+
console.error(`[code-viewer] ${fallback} (git exit ${res.code}): ${message}`);
|
|
1454
|
+
return message;
|
|
1455
1455
|
}
|
|
1456
1456
|
function gitFailureResult(res, fallback) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
}
|
|
1460
|
-
return {
|
|
1461
|
-
error: commandNotFoundDetail("git"),
|
|
1462
|
-
status: 503
|
|
1463
|
-
};
|
|
1457
|
+
const error = gitFailureMessage(res, fallback);
|
|
1458
|
+
return isCommandNotFoundResult("git", res) ? { error, status: 503 } : { error };
|
|
1464
1459
|
}
|
|
1465
1460
|
function runGitRefLookup(args, cwd) {
|
|
1466
1461
|
const res = run(args, cwd);
|
|
@@ -2534,10 +2529,19 @@ async function untrackedMetaAsync(cwd) {
|
|
|
2534
2529
|
return results.filter((meta) => meta !== null);
|
|
2535
2530
|
}
|
|
2536
2531
|
async function fileMetaResultAsync(args, cwd, includeUntracked = false) {
|
|
2537
|
-
|
|
2532
|
+
let ns;
|
|
2533
|
+
let nm;
|
|
2534
|
+
if (args.includes("--")) {
|
|
2535
|
+
[ns, nm] = await Promise.all([
|
|
2536
|
+
nameStatusResultAsync(args, cwd),
|
|
2537
|
+
numstatZResultAsync(args, cwd)
|
|
2538
|
+
]);
|
|
2539
|
+
} else {
|
|
2540
|
+
ns = await nameStatusResultAsync(args, cwd);
|
|
2541
|
+
nm = await numstatZResultAsync(args, cwd);
|
|
2542
|
+
}
|
|
2538
2543
|
if (ns.error)
|
|
2539
2544
|
return { files: [], error: ns.error };
|
|
2540
|
-
const nm = await numstatZResultAsync(args, cwd);
|
|
2541
2545
|
if (nm.error)
|
|
2542
2546
|
return { files: [], error: nm.error };
|
|
2543
2547
|
const byPath = new Map(nm.files.map((file) => [file.path, file]));
|
|
@@ -15054,6 +15058,7 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15054
15058
|
const initialScanAsync = options.initialScanMode === "async" || (!options.watch || options.watch === nodeWatch) && !options.readdirSync;
|
|
15055
15059
|
const initialScanQueue = [];
|
|
15056
15060
|
let initialScanTimer = null;
|
|
15061
|
+
let processingInitialScan = false;
|
|
15057
15062
|
const pendingPathInspections = new Map;
|
|
15058
15063
|
let pathInspectionTimer = null;
|
|
15059
15064
|
let timer = null;
|
|
@@ -15141,8 +15146,14 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15141
15146
|
return;
|
|
15142
15147
|
}
|
|
15143
15148
|
const next = initialScanQueue.shift();
|
|
15144
|
-
if (next)
|
|
15145
|
-
|
|
15149
|
+
if (next) {
|
|
15150
|
+
processingInitialScan = true;
|
|
15151
|
+
try {
|
|
15152
|
+
watchDirectory(next, true);
|
|
15153
|
+
} finally {
|
|
15154
|
+
processingInitialScan = false;
|
|
15155
|
+
}
|
|
15156
|
+
}
|
|
15146
15157
|
if (watchers.size >= maxWatchedDirectories) {
|
|
15147
15158
|
reportWatchLimit();
|
|
15148
15159
|
initialScanQueue.length = 0;
|
|
@@ -15160,7 +15171,7 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15160
15171
|
if (children.length > remaining)
|
|
15161
15172
|
reportWatchLimit();
|
|
15162
15173
|
initialScanQueue.push(...children.slice(0, remaining));
|
|
15163
|
-
if (!initialScanTimer)
|
|
15174
|
+
if (!initialScanTimer && !processingInitialScan)
|
|
15164
15175
|
initialScanTimer = setTimer(processInitialScanQueue, 5000);
|
|
15165
15176
|
};
|
|
15166
15177
|
const processChangedPath = (changed, fullChangedPath) => {
|
|
@@ -24819,7 +24830,7 @@ function buildQuery(params) {
|
|
|
24819
24830
|
const s = q.toString();
|
|
24820
24831
|
return s ? `?${s}` : "";
|
|
24821
24832
|
}
|
|
24822
|
-
function fileToMeta(file, range, extraQs) {
|
|
24833
|
+
function fileToMeta(file, range, extraQs, responseGeneration) {
|
|
24823
24834
|
const sizeClass = classify(file);
|
|
24824
24835
|
const q = {
|
|
24825
24836
|
path: file.path,
|
|
@@ -24827,6 +24838,7 @@ function fileToMeta(file, range, extraQs) {
|
|
|
24827
24838
|
status: file.status,
|
|
24828
24839
|
from: range.from,
|
|
24829
24840
|
to: range.to,
|
|
24841
|
+
generation: responseGeneration,
|
|
24830
24842
|
...extraQs
|
|
24831
24843
|
};
|
|
24832
24844
|
if (file.untracked)
|
|
@@ -24865,7 +24877,7 @@ async function computePayload(extras, range, pathFilter = "", responseGeneration
|
|
|
24865
24877
|
};
|
|
24866
24878
|
}
|
|
24867
24879
|
const { args, refs } = buildRangeArgs(range);
|
|
24868
|
-
const fullArgs = [...extras, ...args];
|
|
24880
|
+
const fullArgs = pathFilter ? [...extras, ...args, "--", pathFilter] : [...extras, ...args];
|
|
24869
24881
|
const metaResult = await fileMetaResultAsync(fullArgs, cwd, false);
|
|
24870
24882
|
const files = metaResult.files;
|
|
24871
24883
|
if (!metaResult.error && includeUntracked(range, refs)) {
|
|
@@ -24883,7 +24895,7 @@ async function computePayload(extras, range, pathFilter = "", responseGeneration
|
|
|
24883
24895
|
if (e === "--ignore-blank-lines")
|
|
24884
24896
|
extraQs.ignore_blank = "1";
|
|
24885
24897
|
}
|
|
24886
|
-
const meta = filteredFiles.map((file) => fileToMeta(file, range, extraQs));
|
|
24898
|
+
const meta = filteredFiles.map((file) => fileToMeta(file, range, extraQs, responseGeneration));
|
|
24887
24899
|
const totals = meta.reduce((acc, file) => {
|
|
24888
24900
|
acc.additions += file.additions || 0;
|
|
24889
24901
|
acc.deletions += file.deletions || 0;
|
|
@@ -24902,7 +24914,7 @@ async function computePayload(extras, range, pathFilter = "", responseGeneration
|
|
|
24902
24914
|
};
|
|
24903
24915
|
}
|
|
24904
24916
|
async function handleDiffJson(url) {
|
|
24905
|
-
|
|
24917
|
+
let responseGeneration = generation;
|
|
24906
24918
|
const extras = [];
|
|
24907
24919
|
if (url.searchParams.get("ignore_ws") === "1")
|
|
24908
24920
|
extras.push("-w");
|
|
@@ -24928,9 +24940,15 @@ async function handleDiffJson(url) {
|
|
|
24928
24940
|
const requestSequence = ++diffMetaRequestSequence;
|
|
24929
24941
|
latestDiffMetaRequest.set(key, requestSequence);
|
|
24930
24942
|
try {
|
|
24931
|
-
|
|
24932
|
-
if (latestDiffMetaRequest.get(key) !== requestSequence
|
|
24943
|
+
let payload = await computePayload(extras, range, path, responseGeneration);
|
|
24944
|
+
if (latestDiffMetaRequest.get(key) !== requestSequence)
|
|
24933
24945
|
return json2(payload);
|
|
24946
|
+
if (responseGeneration !== generation) {
|
|
24947
|
+
responseGeneration = generation;
|
|
24948
|
+
payload = await computePayload(extras, range, path, responseGeneration);
|
|
24949
|
+
if (latestDiffMetaRequest.get(key) !== requestSequence || responseGeneration !== generation)
|
|
24950
|
+
return json2(payload);
|
|
24951
|
+
}
|
|
24934
24952
|
const sig = JSON.stringify({ ...payload, generation: undefined });
|
|
24935
24953
|
if (noCache && (!cached || cached.sig !== sig)) {
|
|
24936
24954
|
generation++;
|
|
@@ -25399,7 +25417,7 @@ async function handleFileBlame(url) {
|
|
|
25399
25417
|
return json2({ ...result, base, ref, generation: responseGeneration });
|
|
25400
25418
|
}
|
|
25401
25419
|
async function handleFileDiff(url) {
|
|
25402
|
-
const
|
|
25420
|
+
const serverGenerationAtRequest = generation;
|
|
25403
25421
|
const path = url.searchParams.get("path") || "";
|
|
25404
25422
|
if (!safePath(path))
|
|
25405
25423
|
return text("invalid path", 400);
|
|
@@ -25413,6 +25431,9 @@ async function handleFileDiff(url) {
|
|
|
25413
25431
|
from: url.searchParams.get("from") || "",
|
|
25414
25432
|
to: url.searchParams.get("to") || ""
|
|
25415
25433
|
};
|
|
25434
|
+
const requestedGeneration = Number(url.searchParams.get("generation"));
|
|
25435
|
+
const usesWorktree = !range.from || range.from === "worktree" || !range.to || range.to === "worktree";
|
|
25436
|
+
const responseGeneration = !usesWorktree && Number.isSafeInteger(requestedGeneration) && requestedGeneration > 0 ? requestedGeneration : serverGenerationAtRequest;
|
|
25416
25437
|
if (isSameWorktreeRange(range)) {
|
|
25417
25438
|
return json2({
|
|
25418
25439
|
path,
|
|
@@ -25466,7 +25487,7 @@ async function handleFileDiff(url) {
|
|
|
25466
25487
|
errStatus = res.status ?? 500;
|
|
25467
25488
|
}
|
|
25468
25489
|
}
|
|
25469
|
-
if (!errText &&
|
|
25490
|
+
if (!errText && serverGenerationAtRequest === generation)
|
|
25470
25491
|
setTimedCacheEntry(fileCache, cacheKey, { diffText });
|
|
25471
25492
|
}
|
|
25472
25493
|
if (errStatus)
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -227,6 +227,8 @@ ${lines.join(`
|
|
|
227
227
|
function shouldAutoLoadForRoute(route, options = {}) {
|
|
228
228
|
if (route.screen === "history")
|
|
229
229
|
return options.historyWorktreeSelected === true;
|
|
230
|
+
if (route.screen === "diff")
|
|
231
|
+
return !route.range.from || route.range.from === "worktree" || !route.range.to || route.range.to === "worktree";
|
|
230
232
|
if (route.screen === "database" || route.screen === "journal" || route.screen === "help" || route.screen === "unknown")
|
|
231
233
|
return false;
|
|
232
234
|
return true;
|
|
@@ -9791,14 +9793,18 @@ ${frontmatter.yaml}
|
|
|
9791
9793
|
sticky.appendChild(tabsHost);
|
|
9792
9794
|
return { sticky, header, tabsHost };
|
|
9793
9795
|
}
|
|
9794
|
-
function mountFileShellCard(deps, target, card, repoTarget = deps.repoFileTargetFromRoute()) {
|
|
9796
|
+
function mountFileShellCard(deps, target, card, repoTarget = deps.repoFileTargetFromRoute(), options = {}) {
|
|
9795
9797
|
const root = deps.$("#diff");
|
|
9796
9798
|
if (repoTarget) {
|
|
9797
9799
|
const layout = document.createElement("div");
|
|
9798
9800
|
layout.className = "gdp-repo-blob-layout";
|
|
9799
9801
|
layout.appendChild(card);
|
|
9800
9802
|
root.prepend(layout);
|
|
9801
|
-
|
|
9803
|
+
if (options.loadSidebar !== false) {
|
|
9804
|
+
Promise.resolve(deps.renderRepoBlobSidebar(target.path, repoTarget)).catch((error2) => {
|
|
9805
|
+
console.error("[code-viewer] failed to load repository sidebar", error2);
|
|
9806
|
+
}).finally(() => deps.placeSidebarToggle());
|
|
9807
|
+
}
|
|
9802
9808
|
} else {
|
|
9803
9809
|
root.prepend(card);
|
|
9804
9810
|
}
|
|
@@ -23773,7 +23779,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23773
23779
|
if (fresh && card.isConnected)
|
|
23774
23780
|
enqueueLoad(fresh, card, 0);
|
|
23775
23781
|
};
|
|
23776
|
-
|
|
23782
|
+
const request = trackLoad(fetch(url).then(async (r2) => {
|
|
23777
23783
|
if (!r2.ok)
|
|
23778
23784
|
throw new Error(await r2.text());
|
|
23779
23785
|
return r2.json();
|
|
@@ -23793,9 +23799,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23793
23799
|
if (String(myReq) !== card.dataset.reqId)
|
|
23794
23800
|
return;
|
|
23795
23801
|
renderFile(file, data, card);
|
|
23796
|
-
}).catch(() => {
|
|
23802
|
+
}).catch((error2) => {
|
|
23797
23803
|
if (String(myReq) !== card.dataset.reqId)
|
|
23798
23804
|
return;
|
|
23805
|
+
console.error("[code-viewer] failed to load diff", error2);
|
|
23799
23806
|
card.classList.remove("loading");
|
|
23800
23807
|
card.classList.add("error");
|
|
23801
23808
|
card.style.minHeight = "";
|
|
@@ -23812,13 +23819,24 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
23812
23819
|
enqueueLoad(file, card, 1);
|
|
23813
23820
|
});
|
|
23814
23821
|
});
|
|
23822
|
+
const completed = request.finally(() => {
|
|
23823
|
+
if (card._loadPromise === completed)
|
|
23824
|
+
delete card._loadPromise;
|
|
23825
|
+
});
|
|
23826
|
+
card._loadPromise = completed;
|
|
23827
|
+
return completed;
|
|
23815
23828
|
}
|
|
23816
23829
|
async function loadDiffFile(path) {
|
|
23817
|
-
const
|
|
23830
|
+
const root = getDiffRoot?.() || document;
|
|
23831
|
+
const card = root.querySelector(diffCardSelector(path));
|
|
23818
23832
|
if (!card || card.classList.contains("gdp-standalone-source"))
|
|
23819
23833
|
return false;
|
|
23820
23834
|
if (card.classList.contains("loaded"))
|
|
23821
23835
|
return true;
|
|
23836
|
+
if (card.classList.contains("loading") && card._loadPromise) {
|
|
23837
|
+
await card._loadPromise;
|
|
23838
|
+
return card.classList.contains("loaded");
|
|
23839
|
+
}
|
|
23822
23840
|
const file = card._file || STATE.files.find((x) => x.path === path);
|
|
23823
23841
|
if (!file)
|
|
23824
23842
|
return false;
|
|
@@ -25609,7 +25627,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
25609
25627
|
(el.closest(".gdp-repo-blob-layout") || el).remove();
|
|
25610
25628
|
});
|
|
25611
25629
|
}
|
|
25612
|
-
function renderFileHistoryShell(deps, route) {
|
|
25630
|
+
function renderFileHistoryShell(deps, route, options = {}) {
|
|
25613
25631
|
removeFileHistoryShell();
|
|
25614
25632
|
const target = { path: route.path, ref: route.ref };
|
|
25615
25633
|
const card = document.createElement("article");
|
|
@@ -25645,7 +25663,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
25645
25663
|
body.appendChild(embed);
|
|
25646
25664
|
wrapper.appendChild(body);
|
|
25647
25665
|
card.appendChild(wrapper);
|
|
25648
|
-
mountFileShellCard(deps, target, card, target.ref);
|
|
25666
|
+
mountFileShellCard(deps, target, card, target.ref, options);
|
|
25649
25667
|
return {
|
|
25650
25668
|
...panelDom,
|
|
25651
25669
|
commitInfo,
|
|
@@ -30161,14 +30179,34 @@ code-viewer query agent-help`
|
|
|
30161
30179
|
if (!popBody || !popSearch)
|
|
30162
30180
|
return;
|
|
30163
30181
|
let popTarget = null;
|
|
30182
|
+
let refsLoaded = false;
|
|
30183
|
+
let refsLoading = false;
|
|
30184
|
+
let refsError = false;
|
|
30185
|
+
let refsInFlight = null;
|
|
30164
30186
|
function fetchRefs() {
|
|
30165
|
-
|
|
30187
|
+
if (refsLoaded)
|
|
30188
|
+
return Promise.resolve();
|
|
30189
|
+
if (refsInFlight)
|
|
30190
|
+
return refsInFlight;
|
|
30191
|
+
refsLoading = true;
|
|
30192
|
+
refsError = false;
|
|
30193
|
+
const request = fetch("/_refs").then((r2) => r2.json()).then((refs) => {
|
|
30166
30194
|
Object.assign(REFS, refs);
|
|
30167
|
-
|
|
30168
|
-
|
|
30195
|
+
refsLoaded = true;
|
|
30196
|
+
if (!popover.hidden && popTab !== "commits")
|
|
30197
|
+
buildPopBody(popSearch.value);
|
|
30198
|
+
}).catch((error2) => {
|
|
30199
|
+
refsError = true;
|
|
30200
|
+
console.error("[code-viewer] failed to load refs", error2);
|
|
30201
|
+
}).finally(() => {
|
|
30202
|
+
refsLoading = false;
|
|
30203
|
+
refsInFlight = null;
|
|
30204
|
+
if (!popover.hidden && popTab !== "commits")
|
|
30205
|
+
buildPopBody(popSearch.value);
|
|
30169
30206
|
});
|
|
30207
|
+
refsInFlight = request;
|
|
30208
|
+
return request;
|
|
30170
30209
|
}
|
|
30171
|
-
fetchRefs();
|
|
30172
30210
|
let popTab = "commits";
|
|
30173
30211
|
const COMMIT_PAGE_SIZE = 50;
|
|
30174
30212
|
let commitSearchTimer = null;
|
|
@@ -30309,6 +30347,10 @@ code-viewer query agent-help`
|
|
|
30309
30347
|
} else if (commitHasMore) {
|
|
30310
30348
|
html.push('<div class="rp-empty">scroll for more commits...</div>');
|
|
30311
30349
|
}
|
|
30350
|
+
} else if (refsLoading) {
|
|
30351
|
+
html.push('<div class="rp-empty">loading refs...</div>');
|
|
30352
|
+
} else if (refsError) {
|
|
30353
|
+
html.push('<div class="rp-empty">failed to load refs</div>');
|
|
30312
30354
|
} else if (popTab === "branches") {
|
|
30313
30355
|
const branches = (REFS.branches || []).filter((b2) => m(b2.name));
|
|
30314
30356
|
if (!branches.length) {
|
|
@@ -30443,6 +30485,14 @@ code-viewer query agent-help`
|
|
|
30443
30485
|
});
|
|
30444
30486
|
if (popTab === "commits")
|
|
30445
30487
|
scheduleCommitSearch(popSearch.value);
|
|
30488
|
+
else {
|
|
30489
|
+
if (commitSearchTimer) {
|
|
30490
|
+
clearTimeout(commitSearchTimer);
|
|
30491
|
+
commitSearchTimer = null;
|
|
30492
|
+
}
|
|
30493
|
+
commitSearchLoading = false;
|
|
30494
|
+
fetchRefs();
|
|
30495
|
+
}
|
|
30446
30496
|
buildPopBody(popSearch.value);
|
|
30447
30497
|
});
|
|
30448
30498
|
});
|
|
@@ -37650,7 +37700,7 @@ code-viewer query agent-help`
|
|
|
37650
37700
|
setPreferredSourceTab: (tab) => SOURCE_VIEW.setPreferredSourceTab(tab),
|
|
37651
37701
|
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref),
|
|
37652
37702
|
emptyText: () => uiText().diff
|
|
37653
|
-
}, historyRoute);
|
|
37703
|
+
}, historyRoute, { loadSidebar: false });
|
|
37654
37704
|
activeFileHistoryDiffHost = mount.diffHost;
|
|
37655
37705
|
activeFileHistoryEmptyHost = mount.emptyHost;
|
|
37656
37706
|
return mount;
|
|
@@ -37705,7 +37755,17 @@ code-viewer query agent-help`
|
|
|
37705
37755
|
parkRangeForHistory();
|
|
37706
37756
|
setPageMode();
|
|
37707
37757
|
const mount = renderFileHistoryShell2(route);
|
|
37708
|
-
HISTORY_VIEW.enterHistory({ mount })
|
|
37758
|
+
HISTORY_VIEW.enterHistory({ mount }).then(async () => {
|
|
37759
|
+
const currentRoute = STATE.route;
|
|
37760
|
+
if (currentRoute.screen !== "file" || currentRoute.view !== "history" || currentRoute.path !== route.path || currentRoute.ref !== route.ref)
|
|
37761
|
+
return;
|
|
37762
|
+
await loadDiffFile(route.path);
|
|
37763
|
+
const routeAfterDiff = STATE.route;
|
|
37764
|
+
if (routeAfterDiff.screen !== "file" || routeAfterDiff.view !== "history" || routeAfterDiff.path !== route.path || routeAfterDiff.ref !== route.ref)
|
|
37765
|
+
return;
|
|
37766
|
+
await REPO_VIEW.renderRepoBlobSidebar(route.path, route.ref);
|
|
37767
|
+
placeSidebarToggle();
|
|
37768
|
+
});
|
|
37709
37769
|
return true;
|
|
37710
37770
|
}
|
|
37711
37771
|
return false;
|