@youtyan/code-viewer 0.1.11 → 0.1.12
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/package.json +1 -1
- package/web/app.js +711 -9
- package/web/style.css +184 -0
- package/web-src/routes.ts +43 -7
- package/web-src/server/preview.ts +109 -2
- package/web-src/server/search.ts +101 -0
- package/web-src/types.ts +24 -0
package/web/app.js
CHANGED
|
@@ -131,6 +131,164 @@
|
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
// web-src/fuzzy-search.ts
|
|
135
|
+
function basenameStart(path) {
|
|
136
|
+
const slash = path.lastIndexOf("/");
|
|
137
|
+
return slash < 0 ? 0 : slash + 1;
|
|
138
|
+
}
|
|
139
|
+
function isBoundary(path, index) {
|
|
140
|
+
if (index <= 0)
|
|
141
|
+
return true;
|
|
142
|
+
const prev = path[index - 1];
|
|
143
|
+
return prev === "/" || prev === "-" || prev === "_" || prev === "." || prev === " ";
|
|
144
|
+
}
|
|
145
|
+
function toRanges(indices) {
|
|
146
|
+
const ranges = [];
|
|
147
|
+
for (const index of indices) {
|
|
148
|
+
const last = ranges[ranges.length - 1];
|
|
149
|
+
if (last && last.end === index) {
|
|
150
|
+
last.end = index + 1;
|
|
151
|
+
} else {
|
|
152
|
+
ranges.push({ start: index, end: index + 1 });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return ranges;
|
|
156
|
+
}
|
|
157
|
+
function fuzzyMatchPath(query, path) {
|
|
158
|
+
const q = query.trim().toLowerCase();
|
|
159
|
+
if (!q)
|
|
160
|
+
return { score: 0, ranges: [] };
|
|
161
|
+
const lowerPath = path.toLowerCase();
|
|
162
|
+
const baseStart = basenameStart(path);
|
|
163
|
+
const indices = [];
|
|
164
|
+
let from = 0;
|
|
165
|
+
let score = 0;
|
|
166
|
+
for (const ch of q) {
|
|
167
|
+
const index = lowerPath.indexOf(ch, from);
|
|
168
|
+
if (index < 0)
|
|
169
|
+
return null;
|
|
170
|
+
indices.push(index);
|
|
171
|
+
score += 10;
|
|
172
|
+
if (index >= baseStart)
|
|
173
|
+
score += 8;
|
|
174
|
+
if (isBoundary(path, index))
|
|
175
|
+
score += 6;
|
|
176
|
+
const prev = indices[indices.length - 2];
|
|
177
|
+
if (prev != null && prev + 1 === index)
|
|
178
|
+
score += 12;
|
|
179
|
+
from = index + 1;
|
|
180
|
+
}
|
|
181
|
+
const first = indices[0] || 0;
|
|
182
|
+
score -= Math.min(first, 40);
|
|
183
|
+
if (indices[0] >= baseStart)
|
|
184
|
+
score += 20;
|
|
185
|
+
const basename = lowerPath.slice(baseStart);
|
|
186
|
+
if (basename.startsWith(q))
|
|
187
|
+
score += 30;
|
|
188
|
+
if (basename === q || basename.startsWith(q + "."))
|
|
189
|
+
score += 25;
|
|
190
|
+
if (lowerPath.endsWith(q))
|
|
191
|
+
score += 15;
|
|
192
|
+
return { score, ranges: toRanges(indices) };
|
|
193
|
+
}
|
|
194
|
+
function rankFuzzyPaths(query, items) {
|
|
195
|
+
return items.map((item) => {
|
|
196
|
+
const match = fuzzyMatchPath(query, item.path);
|
|
197
|
+
return match ? { item, score: match.score, ranges: match.ranges } : null;
|
|
198
|
+
}).filter((item) => item !== null).sort((a, b) => b.score - a.score || a.item.path.localeCompare(b.item.path));
|
|
199
|
+
}
|
|
200
|
+
function isGlobPathQuery(query) {
|
|
201
|
+
return /[*?]/.test(query.trim());
|
|
202
|
+
}
|
|
203
|
+
function escapeRegexChar(ch) {
|
|
204
|
+
return /[\\^$+?.()|{}]/.test(ch) ? "\\" + ch : ch;
|
|
205
|
+
}
|
|
206
|
+
function globToRegExp(query) {
|
|
207
|
+
const pattern = query.trim();
|
|
208
|
+
if (!pattern)
|
|
209
|
+
return null;
|
|
210
|
+
let source = "^";
|
|
211
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
212
|
+
const ch = pattern[i];
|
|
213
|
+
if (ch === "*") {
|
|
214
|
+
if (pattern[i + 1] === "*") {
|
|
215
|
+
source += ".*";
|
|
216
|
+
i++;
|
|
217
|
+
} else {
|
|
218
|
+
source += "[^/]*";
|
|
219
|
+
}
|
|
220
|
+
} else if (ch === "?") {
|
|
221
|
+
source += "[^/]";
|
|
222
|
+
} else if (ch === "[") {
|
|
223
|
+
const close = pattern.indexOf("]", i + 1);
|
|
224
|
+
if (close < 0) {
|
|
225
|
+
source += "\\[";
|
|
226
|
+
} else {
|
|
227
|
+
const body = pattern.slice(i + 1, close).replace(/\\/g, "\\\\");
|
|
228
|
+
source += "[" + body + "]";
|
|
229
|
+
i = close;
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
source += escapeRegexChar(ch);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
source += "$";
|
|
236
|
+
try {
|
|
237
|
+
return new RegExp(source, "i");
|
|
238
|
+
} catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function globMatchPath(query, path) {
|
|
243
|
+
const regex = globToRegExp(query);
|
|
244
|
+
const baseStart = basenameStart(path);
|
|
245
|
+
const basename = path.slice(baseStart);
|
|
246
|
+
if (!regex || !regex.test(path) && (query.includes("/") || !regex.test(basename)))
|
|
247
|
+
return null;
|
|
248
|
+
const literal = query.replace(/[*?[\]]+/g, " ").trim().split(/\s+/).filter(Boolean);
|
|
249
|
+
const ranges = [];
|
|
250
|
+
const lowerPath = path.toLowerCase();
|
|
251
|
+
for (const part of literal) {
|
|
252
|
+
const start = lowerPath.indexOf(part.toLowerCase());
|
|
253
|
+
if (start >= 0)
|
|
254
|
+
ranges.push({ start, end: start + part.length });
|
|
255
|
+
}
|
|
256
|
+
ranges.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
257
|
+
const mergedRanges = [];
|
|
258
|
+
for (const range of ranges) {
|
|
259
|
+
const last = mergedRanges[mergedRanges.length - 1];
|
|
260
|
+
if (last && last.end >= range.start) {
|
|
261
|
+
last.end = Math.max(last.end, range.end);
|
|
262
|
+
} else {
|
|
263
|
+
mergedRanges.push({ ...range });
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const score = 1000 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(query.replace(/^\*+/, "").toLowerCase()) ? 50 : 0);
|
|
267
|
+
return { score, ranges: mergedRanges };
|
|
268
|
+
}
|
|
269
|
+
function rankPathMatches(query, items) {
|
|
270
|
+
if (isGlobPathQuery(query)) {
|
|
271
|
+
return items.map((item) => {
|
|
272
|
+
const match = globMatchPath(query, item.path);
|
|
273
|
+
return match ? { item, score: match.score, ranges: match.ranges, mode: "glob" } : null;
|
|
274
|
+
}).filter((item) => item !== null).sort((a, b) => b.score - a.score || a.item.path.localeCompare(b.item.path));
|
|
275
|
+
}
|
|
276
|
+
return rankFuzzyPaths(query, items).map((item) => ({ ...item, mode: "fuzzy" }));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// web-src/search-palette.ts
|
|
280
|
+
var PALETTE_RESULT_LIMIT = 50;
|
|
281
|
+
function limitPaletteResults(items) {
|
|
282
|
+
return items.slice(0, PALETTE_RESULT_LIMIT);
|
|
283
|
+
}
|
|
284
|
+
function movePaletteSelection(index, count, direction) {
|
|
285
|
+
if (count <= 0)
|
|
286
|
+
return -1;
|
|
287
|
+
if (index < 0)
|
|
288
|
+
return direction > 0 ? 0 : count - 1;
|
|
289
|
+
return (index + direction + count) % count;
|
|
290
|
+
}
|
|
291
|
+
|
|
134
292
|
// web-src/catch-up.ts
|
|
135
293
|
function shouldCatchUpDiff(route) {
|
|
136
294
|
return route.screen !== "repo" && !(route.screen === "file" && route.view === "blob");
|
|
@@ -160,6 +318,24 @@
|
|
|
160
318
|
to: raw.slice(sep + 2) || fallback.to
|
|
161
319
|
};
|
|
162
320
|
}
|
|
321
|
+
function parseLineTarget(value) {
|
|
322
|
+
const raw = value || "";
|
|
323
|
+
const range = /^(\d+)-(\d+)$/.exec(raw);
|
|
324
|
+
if (range) {
|
|
325
|
+
const a = Number(range[1]);
|
|
326
|
+
const b = Number(range[2]);
|
|
327
|
+
const start = Math.min(a, b);
|
|
328
|
+
const end = Math.max(a, b);
|
|
329
|
+
if (start > 0)
|
|
330
|
+
return { start, end };
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const line = Number(raw);
|
|
334
|
+
return Number.isInteger(line) && line > 0 ? line : undefined;
|
|
335
|
+
}
|
|
336
|
+
function formatLineTarget(line) {
|
|
337
|
+
return typeof line === "number" ? String(line) : line.start + "-" + line.end;
|
|
338
|
+
}
|
|
163
339
|
function parseRoute(pathname, search, fallbackRange) {
|
|
164
340
|
const params = new URLSearchParams(search);
|
|
165
341
|
const legacyRange = parseLegacyRange(params.get("range"), fallbackRange);
|
|
@@ -178,14 +354,20 @@
|
|
|
178
354
|
};
|
|
179
355
|
case "/todif":
|
|
180
356
|
case "/todiff":
|
|
181
|
-
return {
|
|
357
|
+
return {
|
|
358
|
+
screen: "diff",
|
|
359
|
+
range,
|
|
360
|
+
...params.get("path") ? { path: params.get("path") || "" } : {},
|
|
361
|
+
...parseLineTarget(params.get("line")) ? { line: parseLineTarget(params.get("line")) } : {}
|
|
362
|
+
};
|
|
182
363
|
case "/file": {
|
|
183
364
|
const path = params.get("path") || "";
|
|
184
365
|
const target = params.get("target") || "";
|
|
185
366
|
const ref = target || params.get("ref") || "worktree";
|
|
367
|
+
const line = parseLineTarget(params.get("line"));
|
|
186
368
|
if (!path)
|
|
187
369
|
return { screen: "unknown", reason: "missing-path", rawPathname: pathname, rawSearch: search, range };
|
|
188
|
-
return { screen: "file", path, ref, range, view: target ? "blob" : "detail" };
|
|
370
|
+
return { screen: "file", path, ref, range, view: target ? "blob" : "detail", ...line ? { line } : {} };
|
|
189
371
|
}
|
|
190
372
|
default:
|
|
191
373
|
return { screen: "unknown", reason: "unknown-pathname", rawPathname: pathname, rawSearch: search, range };
|
|
@@ -204,11 +386,11 @@
|
|
|
204
386
|
}
|
|
205
387
|
case "file":
|
|
206
388
|
if (route.view === "blob") {
|
|
207
|
-
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree");
|
|
389
|
+
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree") + (route.line ? "&line=" + encodeURIComponent(formatLineTarget(route.line)) : "");
|
|
208
390
|
}
|
|
209
|
-
return "/file?path=" + encodeURIComponent(route.path) + "&ref=" + encodeURIComponent(route.ref || "worktree") + "&from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree");
|
|
391
|
+
return "/file?path=" + encodeURIComponent(route.path) + "&ref=" + encodeURIComponent(route.ref || "worktree") + "&from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.line ? "&line=" + encodeURIComponent(formatLineTarget(route.line)) : "");
|
|
210
392
|
case "diff":
|
|
211
|
-
return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree");
|
|
393
|
+
return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.path ? "&path=" + encodeURIComponent(route.path) : "") + (route.line ? "&line=" + encodeURIComponent(formatLineTarget(route.line)) : "");
|
|
212
394
|
case "unknown":
|
|
213
395
|
return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree");
|
|
214
396
|
default:
|
|
@@ -6954,7 +7136,41 @@
|
|
|
6954
7136
|
return;
|
|
6955
7137
|
enqueueLoad(f2, card, 5);
|
|
6956
7138
|
}
|
|
6957
|
-
function
|
|
7139
|
+
function clearDiffLineFocus() {
|
|
7140
|
+
document.querySelectorAll(".gdp-diff-line-target").forEach((row) => {
|
|
7141
|
+
row.classList.remove("gdp-diff-line-target");
|
|
7142
|
+
});
|
|
7143
|
+
}
|
|
7144
|
+
function diffRowLineNumber(row) {
|
|
7145
|
+
const newLine = row.querySelector(".line-num2, td.d2h-code-side-linenumber");
|
|
7146
|
+
const raw = (newLine?.textContent || "").trim();
|
|
7147
|
+
const line = Number(raw);
|
|
7148
|
+
return Number.isInteger(line) && line > 0 ? line : null;
|
|
7149
|
+
}
|
|
7150
|
+
function focusDiffLine(card, line) {
|
|
7151
|
+
const start = lineTargetStart(line);
|
|
7152
|
+
if (!start)
|
|
7153
|
+
return false;
|
|
7154
|
+
const rows = Array.from(card.querySelectorAll("table.d2h-diff-table tr"));
|
|
7155
|
+
const row = rows.find((candidate) => diffRowLineNumber(candidate) === start);
|
|
7156
|
+
if (!row)
|
|
7157
|
+
return false;
|
|
7158
|
+
clearDiffLineFocus();
|
|
7159
|
+
row.classList.add("gdp-diff-line-target");
|
|
7160
|
+
row.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
7161
|
+
return true;
|
|
7162
|
+
}
|
|
7163
|
+
function applyDiffRouteFocus(card) {
|
|
7164
|
+
if (STATE.route.screen !== "diff" || !STATE.route.path || !STATE.route.line)
|
|
7165
|
+
return false;
|
|
7166
|
+
if (card && card.dataset.path !== STATE.route.path)
|
|
7167
|
+
return false;
|
|
7168
|
+
const targetCard = card || document.querySelector(diffCardSelector(STATE.route.path));
|
|
7169
|
+
if (!targetCard)
|
|
7170
|
+
return false;
|
|
7171
|
+
return focusDiffLine(targetCard, STATE.route.line);
|
|
7172
|
+
}
|
|
7173
|
+
function scrollToFile(path, line) {
|
|
6958
7174
|
const card = document.querySelector(diffCardSelector(path));
|
|
6959
7175
|
if (!card)
|
|
6960
7176
|
return;
|
|
@@ -6970,7 +7186,9 @@
|
|
|
6970
7186
|
if (f2)
|
|
6971
7187
|
enqueueLoad(f2, card, 10);
|
|
6972
7188
|
}
|
|
6973
|
-
|
|
7189
|
+
if (!line || !focusDiffLine(card, line)) {
|
|
7190
|
+
card.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
7191
|
+
}
|
|
6974
7192
|
}
|
|
6975
7193
|
function markActive(path) {
|
|
6976
7194
|
STATE.activeFile = path;
|
|
@@ -8727,9 +8945,12 @@
|
|
|
8727
8945
|
return false;
|
|
8728
8946
|
const line = lines[index];
|
|
8729
8947
|
const tr = document.createElement("tr");
|
|
8948
|
+
tr.dataset.line = String(index + 1);
|
|
8949
|
+
tr.classList.toggle("gdp-source-line-target", lineInSourceTarget(index + 1, currentSourceLineTarget(target)));
|
|
8730
8950
|
const num = document.createElement("td");
|
|
8731
8951
|
num.className = "gdp-source-line-number";
|
|
8732
8952
|
num.textContent = String(index + 1);
|
|
8953
|
+
bindSourceLineNumber(num, card, target, index + 1);
|
|
8733
8954
|
const code2 = document.createElement("td");
|
|
8734
8955
|
code2.className = "gdp-source-line-code";
|
|
8735
8956
|
if (shikiLines && shikiLines[index] != null) {
|
|
@@ -8821,6 +9042,69 @@
|
|
|
8821
9042
|
url.searchParams.delete("virtual");
|
|
8822
9043
|
return url.pathname + url.search;
|
|
8823
9044
|
}
|
|
9045
|
+
function currentSourceLineTarget(target) {
|
|
9046
|
+
const routeTarget = sourceTargetFromRoute();
|
|
9047
|
+
return sourceTargetsEqual(routeTarget, target) && STATE.route.screen === "file" ? STATE.route.line : undefined;
|
|
9048
|
+
}
|
|
9049
|
+
function lineTargetStart(line) {
|
|
9050
|
+
if (!line)
|
|
9051
|
+
return;
|
|
9052
|
+
return typeof line === "number" ? line : line.start;
|
|
9053
|
+
}
|
|
9054
|
+
function lineInSourceTarget(lineNumber, target) {
|
|
9055
|
+
if (!target)
|
|
9056
|
+
return false;
|
|
9057
|
+
if (typeof target === "number")
|
|
9058
|
+
return lineNumber === target;
|
|
9059
|
+
return lineNumber >= target.start && lineNumber <= target.end;
|
|
9060
|
+
}
|
|
9061
|
+
let SOURCE_LINE_DRAG = null;
|
|
9062
|
+
function normalizeSourceLineSelection(start, end) {
|
|
9063
|
+
const a2 = Math.max(1, Math.floor(start));
|
|
9064
|
+
const b2 = Math.max(1, Math.floor(end));
|
|
9065
|
+
const from = Math.min(a2, b2);
|
|
9066
|
+
const to = Math.max(a2, b2);
|
|
9067
|
+
return from === to ? from : { start: from, end: to };
|
|
9068
|
+
}
|
|
9069
|
+
function setSourceLineRoute(target, line) {
|
|
9070
|
+
if (STATE.route.screen !== "file")
|
|
9071
|
+
return;
|
|
9072
|
+
setRoute({
|
|
9073
|
+
screen: "file",
|
|
9074
|
+
path: target.path,
|
|
9075
|
+
ref: target.ref,
|
|
9076
|
+
view: STATE.route.view,
|
|
9077
|
+
range: currentRange(),
|
|
9078
|
+
line
|
|
9079
|
+
}, true);
|
|
9080
|
+
}
|
|
9081
|
+
function syncRenderedSourceLineHighlights(card, target) {
|
|
9082
|
+
const lineTarget = currentSourceLineTarget(target);
|
|
9083
|
+
card.querySelectorAll("[data-line]").forEach((row) => {
|
|
9084
|
+
const line = Number(row.dataset.line || "0");
|
|
9085
|
+
row.classList.toggle("gdp-source-line-target", lineInSourceTarget(line, lineTarget));
|
|
9086
|
+
});
|
|
9087
|
+
}
|
|
9088
|
+
function updateSourceLineSelection(card, target, start, end) {
|
|
9089
|
+
setSourceLineRoute(target, normalizeSourceLineSelection(start, end));
|
|
9090
|
+
syncRenderedSourceLineHighlights(card, target);
|
|
9091
|
+
}
|
|
9092
|
+
function beginSourceLineSelection(event, card, target, line) {
|
|
9093
|
+
event.preventDefault();
|
|
9094
|
+
SOURCE_LINE_DRAG = { target, start: line };
|
|
9095
|
+
updateSourceLineSelection(card, target, line, line);
|
|
9096
|
+
}
|
|
9097
|
+
function bindSourceLineNumber(num, card, target, line) {
|
|
9098
|
+
num.addEventListener("mousedown", (e2) => beginSourceLineSelection(e2, card, target, line));
|
|
9099
|
+
num.addEventListener("mouseenter", () => {
|
|
9100
|
+
if (!SOURCE_LINE_DRAG || !sourceTargetsEqual(SOURCE_LINE_DRAG.target, target))
|
|
9101
|
+
return;
|
|
9102
|
+
updateSourceLineSelection(card, target, SOURCE_LINE_DRAG.start, line);
|
|
9103
|
+
});
|
|
9104
|
+
}
|
|
9105
|
+
document.addEventListener("mouseup", () => {
|
|
9106
|
+
SOURCE_LINE_DRAG = null;
|
|
9107
|
+
});
|
|
8824
9108
|
function renderVirtualSource(target, textValue, lines, hljsRef, lang) {
|
|
8825
9109
|
const wrap = document.createElement("div");
|
|
8826
9110
|
wrap.className = "gdp-source-virtual";
|
|
@@ -8859,7 +9143,8 @@
|
|
|
8859
9143
|
full.title = "Render every line without virtualization. This can be slow for large files.";
|
|
8860
9144
|
full.addEventListener("click", (e2) => {
|
|
8861
9145
|
e2.preventDefault();
|
|
8862
|
-
|
|
9146
|
+
const url = new URL(full.href, window.location.origin);
|
|
9147
|
+
setRoute(parseRoute(url.pathname, url.search, currentRange()), true);
|
|
8863
9148
|
renderStandaloneSource(target);
|
|
8864
9149
|
});
|
|
8865
9150
|
actions.append(copy, full);
|
|
@@ -8893,9 +9178,12 @@
|
|
|
8893
9178
|
for (let index = start;index < end; index++) {
|
|
8894
9179
|
const row = document.createElement("div");
|
|
8895
9180
|
row.className = "gdp-source-virtual-row";
|
|
9181
|
+
row.dataset.line = String(index + 1);
|
|
9182
|
+
row.classList.toggle("gdp-source-line-target", lineInSourceTarget(index + 1, currentSourceLineTarget(target)));
|
|
8896
9183
|
const num = document.createElement("span");
|
|
8897
9184
|
num.className = "gdp-source-virtual-line-number";
|
|
8898
9185
|
num.textContent = String(index + 1);
|
|
9186
|
+
bindSourceLineNumber(num, wrap, target, index + 1);
|
|
8899
9187
|
const code2 = document.createElement("span");
|
|
8900
9188
|
code2.className = "gdp-source-virtual-line-code";
|
|
8901
9189
|
const line = lines[index] ?? "";
|
|
@@ -9143,6 +9431,7 @@
|
|
|
9143
9431
|
return;
|
|
9144
9432
|
if (!rendered)
|
|
9145
9433
|
return;
|
|
9434
|
+
scrollStandaloneSourceLine(card, lineTargetStart(STATE.route.screen === "file" ? STATE.route.line : undefined));
|
|
9146
9435
|
finishSourceLoad(req);
|
|
9147
9436
|
}
|
|
9148
9437
|
} catch (err) {
|
|
@@ -9156,6 +9445,19 @@
|
|
|
9156
9445
|
renderSourceError(card, target, "Cannot load " + target.path + " at " + target.ref);
|
|
9157
9446
|
}
|
|
9158
9447
|
}
|
|
9448
|
+
function scrollStandaloneSourceLine(card, line) {
|
|
9449
|
+
if (!line || line < 1)
|
|
9450
|
+
return;
|
|
9451
|
+
const virtualScroller = card.querySelector(".gdp-source-virtual-scroller");
|
|
9452
|
+
if (virtualScroller) {
|
|
9453
|
+
const centeredOffset = virtualScroller.clientHeight / 2 - VIRTUAL_SOURCE_ROW_HEIGHT / 2;
|
|
9454
|
+
virtualScroller.scrollTop = Math.max(0, (line - 1) * VIRTUAL_SOURCE_ROW_HEIGHT - Math.max(0, centeredOffset));
|
|
9455
|
+
return;
|
|
9456
|
+
}
|
|
9457
|
+
const row = card.querySelector('.gdp-source-table tr[data-line="' + String(line) + '"]');
|
|
9458
|
+
if (row)
|
|
9459
|
+
row.scrollIntoView({ block: "center" });
|
|
9460
|
+
}
|
|
9159
9461
|
function applySourceRouteToShell() {
|
|
9160
9462
|
const target = sourceTargetFromRoute();
|
|
9161
9463
|
setPageMode();
|
|
@@ -9344,6 +9646,7 @@
|
|
|
9344
9646
|
card.classList.add("loaded");
|
|
9345
9647
|
card.style.minHeight = "";
|
|
9346
9648
|
mountDiff(card, file, data);
|
|
9649
|
+
applyDiffRouteFocus(card);
|
|
9347
9650
|
card.style.containIntrinsicSize = Math.max(card.offsetHeight, file.estimated_height_px || 200) + "px";
|
|
9348
9651
|
applyViewedToCard(card, STATE.viewedFiles.has(file.path), true);
|
|
9349
9652
|
if (data.truncated && data.mode === "preview") {
|
|
@@ -9775,10 +10078,409 @@
|
|
|
9775
10078
|
input.focus();
|
|
9776
10079
|
input.select();
|
|
9777
10080
|
}
|
|
10081
|
+
let PALETTE = null;
|
|
10082
|
+
const REPO_FILE_CACHE = new Map;
|
|
10083
|
+
function paletteSource() {
|
|
10084
|
+
if (STATE.route.screen === "diff")
|
|
10085
|
+
return "diff";
|
|
10086
|
+
if (STATE.route.screen === "file" && STATE.route.view !== "blob")
|
|
10087
|
+
return "diff";
|
|
10088
|
+
return "repo";
|
|
10089
|
+
}
|
|
10090
|
+
function paletteRef(source) {
|
|
10091
|
+
if (source === "diff")
|
|
10092
|
+
return STATE.to && STATE.to !== "worktree" ? STATE.to : "worktree";
|
|
10093
|
+
if (STATE.route.screen === "repo")
|
|
10094
|
+
return STATE.route.ref || "worktree";
|
|
10095
|
+
if (STATE.route.screen === "file")
|
|
10096
|
+
return STATE.route.ref || "worktree";
|
|
10097
|
+
return STATE.repoRef || "worktree";
|
|
10098
|
+
}
|
|
10099
|
+
function closeSearchPalette() {
|
|
10100
|
+
if (!PALETTE)
|
|
10101
|
+
return;
|
|
10102
|
+
PALETTE.controller?.abort();
|
|
10103
|
+
if (PALETTE.debounce)
|
|
10104
|
+
window.clearTimeout(PALETTE.debounce);
|
|
10105
|
+
PALETTE.root.remove();
|
|
10106
|
+
PALETTE = null;
|
|
10107
|
+
}
|
|
10108
|
+
function createPalette(mode) {
|
|
10109
|
+
closeSearchPalette();
|
|
10110
|
+
const root = document.createElement("div");
|
|
10111
|
+
root.className = "gdp-palette-backdrop";
|
|
10112
|
+
const dialog = document.createElement("div");
|
|
10113
|
+
dialog.className = "gdp-palette";
|
|
10114
|
+
dialog.setAttribute("role", "dialog");
|
|
10115
|
+
dialog.setAttribute("aria-modal", "true");
|
|
10116
|
+
const label = document.createElement("div");
|
|
10117
|
+
label.className = "gdp-palette-label";
|
|
10118
|
+
label.textContent = mode === "file" ? "Files" : "Grep";
|
|
10119
|
+
const input = document.createElement("input");
|
|
10120
|
+
input.className = "gdp-palette-input";
|
|
10121
|
+
input.type = "search";
|
|
10122
|
+
input.autocomplete = "off";
|
|
10123
|
+
input.spellcheck = false;
|
|
10124
|
+
input.placeholder = mode === "file" ? "Search files" : "Search text";
|
|
10125
|
+
input.setAttribute("role", "combobox");
|
|
10126
|
+
input.setAttribute("aria-expanded", "true");
|
|
10127
|
+
input.setAttribute("aria-controls", "gdp-palette-list");
|
|
10128
|
+
const status = document.createElement("div");
|
|
10129
|
+
status.className = "gdp-palette-status";
|
|
10130
|
+
const controls = document.createElement("div");
|
|
10131
|
+
controls.className = "gdp-palette-controls";
|
|
10132
|
+
const list2 = document.createElement("div");
|
|
10133
|
+
list2.id = "gdp-palette-list";
|
|
10134
|
+
list2.className = "gdp-palette-list";
|
|
10135
|
+
list2.setAttribute("role", "listbox");
|
|
10136
|
+
dialog.append(label, input, controls, status, list2);
|
|
10137
|
+
root.appendChild(dialog);
|
|
10138
|
+
document.body.appendChild(root);
|
|
10139
|
+
const state = {
|
|
10140
|
+
root,
|
|
10141
|
+
input,
|
|
10142
|
+
controls,
|
|
10143
|
+
list: list2,
|
|
10144
|
+
status,
|
|
10145
|
+
mode,
|
|
10146
|
+
grepRegex: false,
|
|
10147
|
+
selected: -1,
|
|
10148
|
+
items: [],
|
|
10149
|
+
composing: false,
|
|
10150
|
+
diffSnapshot: [...STATE.files]
|
|
10151
|
+
};
|
|
10152
|
+
PALETTE = state;
|
|
10153
|
+
root.addEventListener("mousedown", (e2) => {
|
|
10154
|
+
if (e2.target === root)
|
|
10155
|
+
closeSearchPalette();
|
|
10156
|
+
});
|
|
10157
|
+
input.addEventListener("compositionstart", () => {
|
|
10158
|
+
state.composing = true;
|
|
10159
|
+
});
|
|
10160
|
+
input.addEventListener("compositionend", () => {
|
|
10161
|
+
state.composing = false;
|
|
10162
|
+
});
|
|
10163
|
+
input.addEventListener("input", () => updatePaletteResults(state));
|
|
10164
|
+
input.addEventListener("keydown", (e2) => handlePaletteKeydown(e2, state));
|
|
10165
|
+
input.focus();
|
|
10166
|
+
updatePaletteResults(state);
|
|
10167
|
+
return state;
|
|
10168
|
+
}
|
|
10169
|
+
function renderPaletteControls(state) {
|
|
10170
|
+
state.controls.innerHTML = "";
|
|
10171
|
+
if (state.mode === "file") {
|
|
10172
|
+
const hint2 = document.createElement("span");
|
|
10173
|
+
hint2.className = "gdp-palette-mode-hint";
|
|
10174
|
+
hint2.textContent = isGlobPathQuery(state.input.value) ? "Glob: * ? []" : "Fuzzy path search";
|
|
10175
|
+
state.controls.appendChild(hint2);
|
|
10176
|
+
return;
|
|
10177
|
+
}
|
|
10178
|
+
const plain = document.createElement("button");
|
|
10179
|
+
plain.type = "button";
|
|
10180
|
+
plain.className = "gdp-palette-mode-button";
|
|
10181
|
+
plain.setAttribute("aria-pressed", String(!state.grepRegex));
|
|
10182
|
+
plain.textContent = "Plain";
|
|
10183
|
+
plain.addEventListener("mousedown", (e2) => {
|
|
10184
|
+
e2.preventDefault();
|
|
10185
|
+
state.grepRegex = false;
|
|
10186
|
+
renderPaletteControls(state);
|
|
10187
|
+
updatePaletteResults(state);
|
|
10188
|
+
state.input.focus();
|
|
10189
|
+
});
|
|
10190
|
+
const regex = document.createElement("button");
|
|
10191
|
+
regex.type = "button";
|
|
10192
|
+
regex.className = "gdp-palette-mode-button";
|
|
10193
|
+
regex.setAttribute("aria-pressed", String(state.grepRegex));
|
|
10194
|
+
regex.textContent = ".* Regex";
|
|
10195
|
+
regex.title = "Alt+R";
|
|
10196
|
+
regex.addEventListener("mousedown", (e2) => {
|
|
10197
|
+
e2.preventDefault();
|
|
10198
|
+
state.grepRegex = true;
|
|
10199
|
+
renderPaletteControls(state);
|
|
10200
|
+
updatePaletteResults(state);
|
|
10201
|
+
state.input.focus();
|
|
10202
|
+
});
|
|
10203
|
+
const hint = document.createElement("span");
|
|
10204
|
+
hint.className = "gdp-palette-mode-hint";
|
|
10205
|
+
hint.textContent = "Alt+R toggles regex";
|
|
10206
|
+
state.controls.append(plain, regex, hint);
|
|
10207
|
+
}
|
|
10208
|
+
function regexQueryIsValid(query) {
|
|
10209
|
+
try {
|
|
10210
|
+
new RegExp(query);
|
|
10211
|
+
return true;
|
|
10212
|
+
} catch {
|
|
10213
|
+
return false;
|
|
10214
|
+
}
|
|
10215
|
+
}
|
|
10216
|
+
function appendHighlightedPath(parent, path, ranges) {
|
|
10217
|
+
let cursor = 0;
|
|
10218
|
+
for (const range of ranges) {
|
|
10219
|
+
if (range.start > cursor)
|
|
10220
|
+
parent.appendChild(document.createTextNode(path.slice(cursor, range.start)));
|
|
10221
|
+
const mark = document.createElement("mark");
|
|
10222
|
+
mark.textContent = path.slice(range.start, range.end);
|
|
10223
|
+
parent.appendChild(mark);
|
|
10224
|
+
cursor = range.end;
|
|
10225
|
+
}
|
|
10226
|
+
if (cursor < path.length)
|
|
10227
|
+
parent.appendChild(document.createTextNode(path.slice(cursor)));
|
|
10228
|
+
}
|
|
10229
|
+
function renderPalette(state) {
|
|
10230
|
+
state.list.innerHTML = "";
|
|
10231
|
+
state.items.forEach((item, index) => {
|
|
10232
|
+
const row = document.createElement("button");
|
|
10233
|
+
row.type = "button";
|
|
10234
|
+
row.id = "gdp-palette-item-" + index;
|
|
10235
|
+
row.className = "gdp-palette-row";
|
|
10236
|
+
row.setAttribute("role", "option");
|
|
10237
|
+
row.setAttribute("aria-selected", index === state.selected ? "true" : "false");
|
|
10238
|
+
const title = document.createElement("span");
|
|
10239
|
+
title.className = "gdp-palette-row-title";
|
|
10240
|
+
const detail = document.createElement("span");
|
|
10241
|
+
detail.className = "gdp-palette-row-detail";
|
|
10242
|
+
if (item.kind === "file") {
|
|
10243
|
+
title.textContent = item.path.split("/").pop() || item.path;
|
|
10244
|
+
appendHighlightedPath(detail, item.displayPath, item.ranges);
|
|
10245
|
+
if (item.old_path && item.displayPath !== item.old_path) {
|
|
10246
|
+
detail.appendChild(document.createTextNode(" " + item.old_path));
|
|
10247
|
+
}
|
|
10248
|
+
} else {
|
|
10249
|
+
title.textContent = item.path + ":" + item.line;
|
|
10250
|
+
detail.textContent = item.preview;
|
|
10251
|
+
}
|
|
10252
|
+
row.append(title, detail);
|
|
10253
|
+
row.addEventListener("mouseenter", () => {
|
|
10254
|
+
state.selected = index;
|
|
10255
|
+
syncPaletteSelection(state);
|
|
10256
|
+
});
|
|
10257
|
+
row.addEventListener("mousedown", (e2) => {
|
|
10258
|
+
e2.preventDefault();
|
|
10259
|
+
state.selected = index;
|
|
10260
|
+
selectPaletteItem(state);
|
|
10261
|
+
});
|
|
10262
|
+
state.list.appendChild(row);
|
|
10263
|
+
});
|
|
10264
|
+
syncPaletteSelection(state);
|
|
10265
|
+
}
|
|
10266
|
+
function syncPaletteSelection(state) {
|
|
10267
|
+
state.input.setAttribute("aria-activedescendant", state.selected >= 0 ? "gdp-palette-item-" + state.selected : "");
|
|
10268
|
+
state.list.querySelectorAll(".gdp-palette-row").forEach((row, index) => {
|
|
10269
|
+
row.setAttribute("aria-selected", index === state.selected ? "true" : "false");
|
|
10270
|
+
if (index === state.selected)
|
|
10271
|
+
row.scrollIntoView({ block: "nearest" });
|
|
10272
|
+
});
|
|
10273
|
+
}
|
|
10274
|
+
async function repoPaletteFiles(ref) {
|
|
10275
|
+
const cached = REPO_FILE_CACHE.get(ref);
|
|
10276
|
+
if (cached && cached.generation === SERVER_GENERATION)
|
|
10277
|
+
return cached;
|
|
10278
|
+
const params = new URLSearchParams;
|
|
10279
|
+
params.set("ref", ref);
|
|
10280
|
+
const res = await trackLoad(fetch("/_files?" + params.toString()).then((r2) => {
|
|
10281
|
+
if (!r2.ok)
|
|
10282
|
+
throw new Error("failed to load files");
|
|
10283
|
+
return r2.json();
|
|
10284
|
+
}));
|
|
10285
|
+
REPO_FILE_CACHE.set(ref, res);
|
|
10286
|
+
return res;
|
|
10287
|
+
}
|
|
10288
|
+
function diffFilePaletteItems(state, query) {
|
|
10289
|
+
const matchPath = isGlobPathQuery(query) ? globMatchPath : fuzzyMatchPath;
|
|
10290
|
+
const candidates = state.diffSnapshot.map((file) => {
|
|
10291
|
+
const current = matchPath(query, file.path);
|
|
10292
|
+
const old = file.old_path ? matchPath(query, file.old_path) : null;
|
|
10293
|
+
const best = old && (!current || old.score > current.score) ? { match: old, displayPath: file.old_path || file.path } : current ? { match: current, displayPath: file.path } : null;
|
|
10294
|
+
return best ? { file, ...best } : null;
|
|
10295
|
+
}).filter((item) => item !== null).sort((a2, b2) => b2.match.score - a2.match.score || a2.file.path.localeCompare(b2.file.path));
|
|
10296
|
+
return limitPaletteResults(candidates).map((candidate) => ({
|
|
10297
|
+
kind: "file",
|
|
10298
|
+
path: candidate.file.path,
|
|
10299
|
+
old_path: candidate.file.old_path,
|
|
10300
|
+
displayPath: candidate.displayPath,
|
|
10301
|
+
ref: paletteRef("diff"),
|
|
10302
|
+
targetPath: fileSourceTarget(candidate.file).path,
|
|
10303
|
+
targetRef: fileSourceTarget(candidate.file).ref,
|
|
10304
|
+
source: "diff",
|
|
10305
|
+
ranges: candidate.match.ranges
|
|
10306
|
+
}));
|
|
10307
|
+
}
|
|
10308
|
+
async function updateFilePalette(state, query) {
|
|
10309
|
+
renderPaletteControls(state);
|
|
10310
|
+
const source = paletteSource();
|
|
10311
|
+
if (!query.trim()) {
|
|
10312
|
+
const base2 = source === "diff" ? state.diffSnapshot.map((file) => {
|
|
10313
|
+
const target = fileSourceTarget(file);
|
|
10314
|
+
return { kind: "file", path: file.path, old_path: file.old_path, displayPath: file.path, ref: paletteRef(source), targetPath: target.path, targetRef: target.ref, source, ranges: [] };
|
|
10315
|
+
}) : [];
|
|
10316
|
+
state.items = limitPaletteResults(base2);
|
|
10317
|
+
state.selected = state.items.length ? 0 : -1;
|
|
10318
|
+
state.status.textContent = source === "diff" ? state.diffSnapshot.length + " diff files" : "Type to search repository files";
|
|
10319
|
+
renderPalette(state);
|
|
10320
|
+
return;
|
|
10321
|
+
}
|
|
10322
|
+
if (source === "diff") {
|
|
10323
|
+
state.items = diffFilePaletteItems(state, query);
|
|
10324
|
+
} else {
|
|
10325
|
+
state.status.textContent = "Loading files...";
|
|
10326
|
+
const ref = paletteRef(source);
|
|
10327
|
+
const response = await repoPaletteFiles(ref);
|
|
10328
|
+
if (PALETTE !== state || state.input.value !== query)
|
|
10329
|
+
return;
|
|
10330
|
+
state.items = limitPaletteResults(rankPathMatches(query, response.files)).map((match2) => ({
|
|
10331
|
+
kind: "file",
|
|
10332
|
+
path: match2.item.path,
|
|
10333
|
+
displayPath: match2.item.path,
|
|
10334
|
+
ref,
|
|
10335
|
+
source,
|
|
10336
|
+
ranges: match2.ranges
|
|
10337
|
+
}));
|
|
10338
|
+
}
|
|
10339
|
+
state.selected = state.items.length ? 0 : -1;
|
|
10340
|
+
state.status.textContent = state.items.length ? state.items.length + " results" : "No results";
|
|
10341
|
+
renderPalette(state);
|
|
10342
|
+
}
|
|
10343
|
+
function updateGrepPalette(state, query) {
|
|
10344
|
+
renderPaletteControls(state);
|
|
10345
|
+
state.controller?.abort();
|
|
10346
|
+
if (state.debounce)
|
|
10347
|
+
window.clearTimeout(state.debounce);
|
|
10348
|
+
if (!query.trim()) {
|
|
10349
|
+
state.items = [];
|
|
10350
|
+
state.selected = -1;
|
|
10351
|
+
state.status.textContent = "Type to grep";
|
|
10352
|
+
renderPalette(state);
|
|
10353
|
+
return;
|
|
10354
|
+
}
|
|
10355
|
+
if (state.grepRegex && !regexQueryIsValid(query)) {
|
|
10356
|
+
state.controller?.abort();
|
|
10357
|
+
state.items = [];
|
|
10358
|
+
state.selected = -1;
|
|
10359
|
+
state.status.textContent = "Invalid regular expression";
|
|
10360
|
+
renderPalette(state);
|
|
10361
|
+
return;
|
|
10362
|
+
}
|
|
10363
|
+
state.status.textContent = "Searching...";
|
|
10364
|
+
state.debounce = window.setTimeout(() => {
|
|
10365
|
+
const source = paletteSource();
|
|
10366
|
+
const ref = paletteRef(source);
|
|
10367
|
+
const params = new URLSearchParams;
|
|
10368
|
+
params.set("ref", ref);
|
|
10369
|
+
params.set("q", query);
|
|
10370
|
+
params.set("max", "200");
|
|
10371
|
+
if (state.grepRegex)
|
|
10372
|
+
params.set("regex", "1");
|
|
10373
|
+
if (source === "diff") {
|
|
10374
|
+
for (const file of state.diffSnapshot)
|
|
10375
|
+
params.append("path", file.path);
|
|
10376
|
+
}
|
|
10377
|
+
const controller = new AbortController;
|
|
10378
|
+
state.controller = controller;
|
|
10379
|
+
trackLoad(fetch("/_grep?" + params.toString(), { signal: controller.signal }).then((r2) => {
|
|
10380
|
+
if (!r2.ok)
|
|
10381
|
+
throw new Error("grep failed");
|
|
10382
|
+
return r2.json();
|
|
10383
|
+
})).then((response) => {
|
|
10384
|
+
if (PALETTE !== state || controller.signal.aborted)
|
|
10385
|
+
return;
|
|
10386
|
+
state.items = limitPaletteResults(response.matches.map((match2) => ({
|
|
10387
|
+
kind: "grep",
|
|
10388
|
+
path: match2.path,
|
|
10389
|
+
line: match2.line,
|
|
10390
|
+
column: match2.column,
|
|
10391
|
+
preview: match2.preview,
|
|
10392
|
+
ref,
|
|
10393
|
+
source
|
|
10394
|
+
})));
|
|
10395
|
+
state.selected = state.items.length ? 0 : -1;
|
|
10396
|
+
state.status.textContent = response.engine + (state.grepRegex ? " regex" : " plain") + (response.truncated ? " truncated" : "") + " - " + state.items.length + " results";
|
|
10397
|
+
renderPalette(state);
|
|
10398
|
+
}).catch((err) => {
|
|
10399
|
+
if (isAbortError(err))
|
|
10400
|
+
return;
|
|
10401
|
+
state.status.textContent = "Search failed";
|
|
10402
|
+
});
|
|
10403
|
+
}, 80);
|
|
10404
|
+
}
|
|
10405
|
+
function updatePaletteResults(state) {
|
|
10406
|
+
const query = state.input.value;
|
|
10407
|
+
if (state.mode === "file") {
|
|
10408
|
+
updateFilePalette(state, query).catch(() => {
|
|
10409
|
+
state.status.textContent = "Search failed";
|
|
10410
|
+
});
|
|
10411
|
+
} else {
|
|
10412
|
+
updateGrepPalette(state, query);
|
|
10413
|
+
}
|
|
10414
|
+
}
|
|
10415
|
+
function selectPaletteItem(state) {
|
|
10416
|
+
const item = state.items[state.selected];
|
|
10417
|
+
if (!item)
|
|
10418
|
+
return;
|
|
10419
|
+
closeSearchPalette();
|
|
10420
|
+
if (item.kind === "file") {
|
|
10421
|
+
if (item.source === "diff") {
|
|
10422
|
+
if (STATE.route.screen === "file") {
|
|
10423
|
+
setRoute({ screen: "file", path: item.targetPath || item.path, ref: item.targetRef || item.ref, range: currentRange() });
|
|
10424
|
+
applySourceRouteToShell();
|
|
10425
|
+
} else {
|
|
10426
|
+
scrollToFile(item.path);
|
|
10427
|
+
}
|
|
10428
|
+
} else {
|
|
10429
|
+
setRoute({ screen: "file", path: item.path, ref: item.ref, view: "blob", range: currentRange() });
|
|
10430
|
+
renderStandaloneSource({ path: item.path, ref: item.ref });
|
|
10431
|
+
}
|
|
10432
|
+
return;
|
|
10433
|
+
}
|
|
10434
|
+
if (item.source === "diff") {
|
|
10435
|
+
setRoute({ screen: "diff", range: currentRange(), path: item.path, line: item.line });
|
|
10436
|
+
scrollToFile(item.path, item.line);
|
|
10437
|
+
} else {
|
|
10438
|
+
setRoute({ screen: "file", path: item.path, ref: item.ref, view: "blob", line: item.line, range: currentRange() });
|
|
10439
|
+
renderStandaloneSource({ path: item.path, ref: item.ref });
|
|
10440
|
+
}
|
|
10441
|
+
}
|
|
10442
|
+
function handlePaletteKeydown(e2, state) {
|
|
10443
|
+
if (e2.key === "Escape") {
|
|
10444
|
+
e2.preventDefault();
|
|
10445
|
+
closeSearchPalette();
|
|
10446
|
+
return;
|
|
10447
|
+
}
|
|
10448
|
+
if (e2.key === "Enter") {
|
|
10449
|
+
if (state.composing)
|
|
10450
|
+
return;
|
|
10451
|
+
e2.preventDefault();
|
|
10452
|
+
selectPaletteItem(state);
|
|
10453
|
+
return;
|
|
10454
|
+
}
|
|
10455
|
+
if (state.mode === "grep" && e2.altKey && e2.key.toLowerCase() === "r") {
|
|
10456
|
+
e2.preventDefault();
|
|
10457
|
+
state.grepRegex = !state.grepRegex;
|
|
10458
|
+
updatePaletteResults(state);
|
|
10459
|
+
return;
|
|
10460
|
+
}
|
|
10461
|
+
const direction = e2.key === "ArrowDown" || e2.ctrlKey && e2.key.toLowerCase() === "n" ? 1 : e2.key === "ArrowUp" || e2.ctrlKey && e2.key.toLowerCase() === "p" ? -1 : 0;
|
|
10462
|
+
if (direction) {
|
|
10463
|
+
e2.preventDefault();
|
|
10464
|
+
state.selected = movePaletteSelection(state.selected, state.items.length, direction);
|
|
10465
|
+
syncPaletteSelection(state);
|
|
10466
|
+
}
|
|
10467
|
+
}
|
|
10468
|
+
function openSearchPalette(mode) {
|
|
10469
|
+
createPalette(mode);
|
|
10470
|
+
}
|
|
9778
10471
|
document.addEventListener("keydown", (e2) => {
|
|
9779
10472
|
if ((e2.metaKey || e2.ctrlKey) && e2.key.toLowerCase() === "k") {
|
|
9780
10473
|
e2.preventDefault();
|
|
9781
|
-
|
|
10474
|
+
if (PALETTE?.mode === "file")
|
|
10475
|
+
return;
|
|
10476
|
+
openSearchPalette("file");
|
|
10477
|
+
return;
|
|
10478
|
+
}
|
|
10479
|
+
if ((e2.metaKey || e2.ctrlKey) && e2.key.toLowerCase() === "g") {
|
|
10480
|
+
e2.preventDefault();
|
|
10481
|
+
if (PALETTE?.mode === "grep")
|
|
10482
|
+
return;
|
|
10483
|
+
openSearchPalette("grep");
|
|
9782
10484
|
return;
|
|
9783
10485
|
}
|
|
9784
10486
|
const targetEl = e2.target;
|