@youtyan/code-viewer 0.14.0 → 0.15.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 +50 -4
- package/dist/code-viewer.js +526 -99
- package/package.json +1 -1
- package/web/app.js +1949 -527
- package/web/index.html +3 -0
- package/web/style.css +142 -1
package/web/app.js
CHANGED
|
@@ -835,6 +835,281 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
835
835
|
applyTrailingResult
|
|
836
836
|
};
|
|
837
837
|
|
|
838
|
+
// web-src/core/fuzzy-search.ts
|
|
839
|
+
function basenameStart(path) {
|
|
840
|
+
const slash = path.lastIndexOf("/");
|
|
841
|
+
return slash < 0 ? 0 : slash + 1;
|
|
842
|
+
}
|
|
843
|
+
function isBoundary(path, index) {
|
|
844
|
+
if (index <= 0) return true;
|
|
845
|
+
const prev = path[index - 1];
|
|
846
|
+
return prev === "/" || prev === "-" || prev === "_" || prev === "." || prev === " ";
|
|
847
|
+
}
|
|
848
|
+
function toRanges(indices) {
|
|
849
|
+
const ranges = [];
|
|
850
|
+
for (const index of indices) {
|
|
851
|
+
const last = ranges[ranges.length - 1];
|
|
852
|
+
if (last && last.end === index) {
|
|
853
|
+
last.end = index + 1;
|
|
854
|
+
} else {
|
|
855
|
+
ranges.push({ start: index, end: index + 1 });
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return ranges;
|
|
859
|
+
}
|
|
860
|
+
function basenameMatchTier(loweredQuery, loweredBasename) {
|
|
861
|
+
if (loweredBasename === loweredQuery) return 4;
|
|
862
|
+
if (loweredBasename.startsWith(`${loweredQuery}.`)) return 3;
|
|
863
|
+
if (loweredBasename.startsWith(loweredQuery)) return 2;
|
|
864
|
+
if (loweredBasename.includes(loweredQuery)) return 1;
|
|
865
|
+
return 0;
|
|
866
|
+
}
|
|
867
|
+
function pathMatchTier(loweredQuery, loweredPath, loweredBasename) {
|
|
868
|
+
if (loweredQuery.includes("/") && (loweredPath === loweredQuery || loweredPath.endsWith(`/${loweredQuery}`)))
|
|
869
|
+
return 4;
|
|
870
|
+
return basenameMatchTier(loweredQuery, loweredBasename);
|
|
871
|
+
}
|
|
872
|
+
function contiguousPathRange(loweredQuery, loweredPath, baseStart) {
|
|
873
|
+
const loweredBasename = loweredPath.slice(baseStart);
|
|
874
|
+
const basenameMatchStart = loweredBasename.indexOf(loweredQuery);
|
|
875
|
+
if (basenameMatchStart >= 0) {
|
|
876
|
+
const start = baseStart + basenameMatchStart;
|
|
877
|
+
return { start, end: start + loweredQuery.length };
|
|
878
|
+
}
|
|
879
|
+
if (loweredQuery.includes("/")) {
|
|
880
|
+
const pathMatchStart = loweredPath.endsWith(`/${loweredQuery}`) ? loweredPath.length - loweredQuery.length : loweredPath === loweredQuery ? 0 : -1;
|
|
881
|
+
if (pathMatchStart >= 0)
|
|
882
|
+
return {
|
|
883
|
+
start: pathMatchStart,
|
|
884
|
+
end: pathMatchStart + loweredQuery.length
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
return null;
|
|
888
|
+
}
|
|
889
|
+
function computeFuzzyMatch(query, path) {
|
|
890
|
+
const q = query.trim().toLowerCase();
|
|
891
|
+
if (!q) return { score: 0, ranges: [], tier: 0 };
|
|
892
|
+
const lowerPath = path.toLowerCase();
|
|
893
|
+
const baseStart = basenameStart(path);
|
|
894
|
+
const indices = [];
|
|
895
|
+
let from = 0;
|
|
896
|
+
let score = 0;
|
|
897
|
+
for (const ch of q) {
|
|
898
|
+
const index = lowerPath.indexOf(ch, from);
|
|
899
|
+
if (index < 0) return null;
|
|
900
|
+
indices.push(index);
|
|
901
|
+
score += 10;
|
|
902
|
+
if (index >= baseStart) score += 8;
|
|
903
|
+
if (isBoundary(path, index)) score += 6;
|
|
904
|
+
const prev = indices[indices.length - 2];
|
|
905
|
+
if (prev != null && prev + 1 === index) score += 12;
|
|
906
|
+
from = index + 1;
|
|
907
|
+
}
|
|
908
|
+
const first = indices[0];
|
|
909
|
+
score -= Math.min(first, 40);
|
|
910
|
+
if (indices[0] >= baseStart) score += 20;
|
|
911
|
+
const basename = lowerPath.slice(baseStart);
|
|
912
|
+
const tier = pathMatchTier(q, lowerPath, basename);
|
|
913
|
+
const contiguousRange = contiguousPathRange(q, lowerPath, baseStart);
|
|
914
|
+
return {
|
|
915
|
+
score,
|
|
916
|
+
ranges: contiguousRange ? [contiguousRange] : toRanges(indices),
|
|
917
|
+
tier
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
function fuzzyMatchPath(query, path) {
|
|
921
|
+
const match2 = computeFuzzyMatch(query, path);
|
|
922
|
+
return match2 ? { score: match2.score, ranges: match2.ranges } : null;
|
|
923
|
+
}
|
|
924
|
+
function rankFuzzyPaths(query, items, limit, stats) {
|
|
925
|
+
const bounded = Number.isInteger(limit) && limit !== void 0 && limit > 0 ? Math.floor(limit) : 0;
|
|
926
|
+
const compare = (a2, b2) => b2.tier - a2.tier || b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
927
|
+
if (!bounded) {
|
|
928
|
+
const ranked = items.map((item) => {
|
|
929
|
+
const match2 = computeFuzzyMatch(query, item.path);
|
|
930
|
+
return match2 ? { item, score: match2.score, ranges: match2.ranges, tier: match2.tier } : null;
|
|
931
|
+
}).filter(
|
|
932
|
+
(item) => item !== null
|
|
933
|
+
).sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
934
|
+
if (stats) stats.total = ranked.length;
|
|
935
|
+
return ranked;
|
|
936
|
+
}
|
|
937
|
+
const top = [];
|
|
938
|
+
let total = 0;
|
|
939
|
+
for (const item of items) {
|
|
940
|
+
const match2 = computeFuzzyMatch(query, item.path);
|
|
941
|
+
if (!match2) continue;
|
|
942
|
+
total++;
|
|
943
|
+
const ranked = {
|
|
944
|
+
item,
|
|
945
|
+
score: match2.score,
|
|
946
|
+
ranges: match2.ranges,
|
|
947
|
+
tier: match2.tier
|
|
948
|
+
};
|
|
949
|
+
pushBoundedTop(top, ranked, bounded, compare);
|
|
950
|
+
}
|
|
951
|
+
if (stats) stats.total = total;
|
|
952
|
+
return top.sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
953
|
+
}
|
|
954
|
+
function pushBoundedTop(heap, item, limit, compareBestFirst) {
|
|
955
|
+
const isWorse = (a2, b2) => compareBestFirst(a2, b2) > 0;
|
|
956
|
+
const siftUp = (index) => {
|
|
957
|
+
while (index > 0) {
|
|
958
|
+
const parent = Math.floor((index - 1) / 2);
|
|
959
|
+
if (!isWorse(heap[index], heap[parent])) break;
|
|
960
|
+
[heap[index], heap[parent]] = [heap[parent], heap[index]];
|
|
961
|
+
index = parent;
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
const siftDown = (index) => {
|
|
965
|
+
while (true) {
|
|
966
|
+
const left = index * 2 + 1;
|
|
967
|
+
const right = left + 1;
|
|
968
|
+
let worst = index;
|
|
969
|
+
if (left < heap.length && isWorse(heap[left], heap[worst])) worst = left;
|
|
970
|
+
if (right < heap.length && isWorse(heap[right], heap[worst]))
|
|
971
|
+
worst = right;
|
|
972
|
+
if (worst === index) break;
|
|
973
|
+
[heap[index], heap[worst]] = [heap[worst], heap[index]];
|
|
974
|
+
index = worst;
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
if (heap.length < limit) {
|
|
978
|
+
heap.push(item);
|
|
979
|
+
siftUp(heap.length - 1);
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (compareBestFirst(item, heap[0]) >= 0) return;
|
|
983
|
+
heap[0] = item;
|
|
984
|
+
siftDown(0);
|
|
985
|
+
}
|
|
986
|
+
function rankGlobPathMatches(query, items, limit, stats) {
|
|
987
|
+
const matchPath = createGlobPathMatcher(query);
|
|
988
|
+
if (!matchPath) {
|
|
989
|
+
if (stats) stats.total = 0;
|
|
990
|
+
return [];
|
|
991
|
+
}
|
|
992
|
+
const bounded = Number.isInteger(limit) && limit !== void 0 && limit > 0 ? Math.floor(limit) : 0;
|
|
993
|
+
const compare = (a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
994
|
+
if (!bounded) {
|
|
995
|
+
const ranked = items.map((item) => {
|
|
996
|
+
const match2 = matchPath(item.path);
|
|
997
|
+
return match2 ? {
|
|
998
|
+
item,
|
|
999
|
+
score: match2.score,
|
|
1000
|
+
ranges: match2.ranges,
|
|
1001
|
+
mode: "glob"
|
|
1002
|
+
} : null;
|
|
1003
|
+
}).filter((item) => item !== null).sort(compare);
|
|
1004
|
+
if (stats) stats.total = ranked.length;
|
|
1005
|
+
return ranked;
|
|
1006
|
+
}
|
|
1007
|
+
const top = [];
|
|
1008
|
+
let total = 0;
|
|
1009
|
+
for (const item of items) {
|
|
1010
|
+
const match2 = matchPath(item.path);
|
|
1011
|
+
if (!match2) continue;
|
|
1012
|
+
total++;
|
|
1013
|
+
const ranked = {
|
|
1014
|
+
item,
|
|
1015
|
+
score: match2.score,
|
|
1016
|
+
ranges: match2.ranges,
|
|
1017
|
+
mode: "glob"
|
|
1018
|
+
};
|
|
1019
|
+
pushBoundedTop(top, ranked, bounded, compare);
|
|
1020
|
+
}
|
|
1021
|
+
if (stats) stats.total = total;
|
|
1022
|
+
return top.sort(compare);
|
|
1023
|
+
}
|
|
1024
|
+
function rankPathMatches(query, items, limit, stats) {
|
|
1025
|
+
if (isGlobPathQuery(query)) {
|
|
1026
|
+
return rankGlobPathMatches(query, items, limit, stats);
|
|
1027
|
+
}
|
|
1028
|
+
return rankFuzzyPaths(query, items, limit, stats).map((item) => ({
|
|
1029
|
+
...item,
|
|
1030
|
+
mode: "fuzzy"
|
|
1031
|
+
}));
|
|
1032
|
+
}
|
|
1033
|
+
function isGlobPathQuery(query) {
|
|
1034
|
+
return /[*?]/.test(query.trim());
|
|
1035
|
+
}
|
|
1036
|
+
function escapeRegexChar(ch) {
|
|
1037
|
+
return /[\\^$+?.()|{}]/.test(ch) ? `\\${ch}` : ch;
|
|
1038
|
+
}
|
|
1039
|
+
function globToRegExp(query) {
|
|
1040
|
+
const pattern = query.trim();
|
|
1041
|
+
if (!pattern) return null;
|
|
1042
|
+
let source = "^";
|
|
1043
|
+
for (let i2 = 0; i2 < pattern.length; i2++) {
|
|
1044
|
+
const ch = pattern[i2];
|
|
1045
|
+
if (ch === "*") {
|
|
1046
|
+
if (pattern[i2 + 1] === "*") {
|
|
1047
|
+
if (pattern[i2 + 2] === "/") {
|
|
1048
|
+
source += "(?:.*/)?";
|
|
1049
|
+
i2 += 2;
|
|
1050
|
+
} else {
|
|
1051
|
+
source += ".*";
|
|
1052
|
+
i2++;
|
|
1053
|
+
}
|
|
1054
|
+
} else {
|
|
1055
|
+
source += "[^/]*";
|
|
1056
|
+
}
|
|
1057
|
+
} else if (ch === "?") {
|
|
1058
|
+
source += "[^/]";
|
|
1059
|
+
} else if (ch === "[") {
|
|
1060
|
+
const close = pattern.indexOf("]", i2 + 1);
|
|
1061
|
+
if (close < 0) {
|
|
1062
|
+
source += "\\[";
|
|
1063
|
+
} else {
|
|
1064
|
+
const body = pattern.slice(i2 + 1, close).replace(/\\/g, "\\\\");
|
|
1065
|
+
source += `[${body}]`;
|
|
1066
|
+
i2 = close;
|
|
1067
|
+
}
|
|
1068
|
+
} else {
|
|
1069
|
+
source += escapeRegexChar(ch);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
source += "$";
|
|
1073
|
+
try {
|
|
1074
|
+
return new RegExp(source, "i");
|
|
1075
|
+
} catch {
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
function globMatchPath(query, path) {
|
|
1080
|
+
return createGlobPathMatcher(query)?.(path) ?? null;
|
|
1081
|
+
}
|
|
1082
|
+
function createGlobPathMatcher(query) {
|
|
1083
|
+
const regex = globToRegExp(query);
|
|
1084
|
+
if (!regex) return null;
|
|
1085
|
+
const literal = query.replace(/[*?[\]]+/g, " ").trim().split(/\s+/).filter(Boolean);
|
|
1086
|
+
const suffix = query.replace(/^\*+/, "").toLowerCase();
|
|
1087
|
+
return (path) => {
|
|
1088
|
+
const baseStart = basenameStart(path);
|
|
1089
|
+
const basename = path.slice(baseStart);
|
|
1090
|
+
if (!regex.test(path) && (query.includes("/") || !regex.test(basename)))
|
|
1091
|
+
return null;
|
|
1092
|
+
const ranges = [];
|
|
1093
|
+
const lowerPath = path.toLowerCase();
|
|
1094
|
+
for (const part of literal) {
|
|
1095
|
+
const start = lowerPath.indexOf(part.toLowerCase());
|
|
1096
|
+
if (start >= 0) ranges.push({ start, end: start + part.length });
|
|
1097
|
+
}
|
|
1098
|
+
ranges.sort((a2, b2) => a2.start - b2.start || a2.end - b2.end);
|
|
1099
|
+
const mergedRanges = [];
|
|
1100
|
+
for (const range of ranges) {
|
|
1101
|
+
const last = mergedRanges[mergedRanges.length - 1];
|
|
1102
|
+
if (last && last.end >= range.start) {
|
|
1103
|
+
last.end = Math.max(last.end, range.end);
|
|
1104
|
+
} else {
|
|
1105
|
+
mergedRanges.push({ ...range });
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
const score = 1e3 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(suffix) ? 50 : 0);
|
|
1109
|
+
return { score, ranges: mergedRanges };
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
|
|
838
1113
|
// web-src/core/file-filter.ts
|
|
839
1114
|
function normalizeFileFilterQuery(value) {
|
|
840
1115
|
return (value || "").toLowerCase().trim();
|
|
@@ -868,6 +1143,14 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
868
1143
|
};
|
|
869
1144
|
}
|
|
870
1145
|
}
|
|
1146
|
+
if (raw.startsWith("~")) {
|
|
1147
|
+
const needle = raw.slice(1).trim();
|
|
1148
|
+
if (!needle) return { kind: "empty", match: () => true };
|
|
1149
|
+
return { kind: "fuzzy", match: (path) => !!fuzzyMatchPath(needle, path) };
|
|
1150
|
+
}
|
|
1151
|
+
if (isGlobPathQuery(raw)) {
|
|
1152
|
+
return { kind: "glob", match: (path) => !!globMatchPath(raw, path) };
|
|
1153
|
+
}
|
|
871
1154
|
const q = normalizeFileFilterQuery(raw.startsWith("/") ? raw.slice(1) : raw);
|
|
872
1155
|
return {
|
|
873
1156
|
kind: "substring",
|
|
@@ -894,6 +1177,8 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
894
1177
|
}
|
|
895
1178
|
function keymapScope(target) {
|
|
896
1179
|
if (target?.closest("#app-panel")) return "panel";
|
|
1180
|
+
if (target?.closest("#history-panel, .gdp-file-history-panel"))
|
|
1181
|
+
return "history";
|
|
897
1182
|
if (target?.closest("#content")) return "main";
|
|
898
1183
|
if (target?.closest("#sidebar")) return "sidebar";
|
|
899
1184
|
return "global";
|
|
@@ -1158,7 +1443,13 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1158
1443
|
}
|
|
1159
1444
|
|
|
1160
1445
|
// web-src/core/keymap.ts
|
|
1161
|
-
var KEYMAP_SCOPES = [
|
|
1446
|
+
var KEYMAP_SCOPES = [
|
|
1447
|
+
"global",
|
|
1448
|
+
"sidebar",
|
|
1449
|
+
"main",
|
|
1450
|
+
"panel",
|
|
1451
|
+
"history"
|
|
1452
|
+
];
|
|
1162
1453
|
var KEYMAP_ACTIONS = [
|
|
1163
1454
|
"open-file-palette",
|
|
1164
1455
|
"open-grep-palette",
|
|
@@ -1198,6 +1489,8 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1198
1489
|
"previous-hunk",
|
|
1199
1490
|
"goto-diff",
|
|
1200
1491
|
"goto-history",
|
|
1492
|
+
"history-next-commit",
|
|
1493
|
+
"history-previous-commit",
|
|
1201
1494
|
"goto-repo",
|
|
1202
1495
|
"toggle-terminal-panel",
|
|
1203
1496
|
"toggle-sidebar",
|
|
@@ -1334,6 +1627,10 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1334
1627
|
{ action: "previous-hunk", key: "{", shift: true },
|
|
1335
1628
|
{ action: "goto-diff", key: "d", pendingG: true },
|
|
1336
1629
|
{ action: "goto-history", key: "h", pendingG: true },
|
|
1630
|
+
{ action: "history-next-commit", key: "arrowdown" },
|
|
1631
|
+
{ action: "history-previous-commit", key: "arrowup" },
|
|
1632
|
+
{ action: "history-next-commit", key: "j", scope: "history" },
|
|
1633
|
+
{ action: "history-previous-commit", key: "k", scope: "history" },
|
|
1337
1634
|
{ action: "goto-repo", key: "r", pendingG: true },
|
|
1338
1635
|
{ action: "toggle-sidebar", key: "b" },
|
|
1339
1636
|
{ action: "toggle-terminal-panel", key: "`", ctrl: true },
|
|
@@ -1638,6 +1935,14 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1638
1935
|
if (remote.hostname.toLowerCase() !== "github.com") {
|
|
1639
1936
|
return { url: base2, provider: "web" };
|
|
1640
1937
|
}
|
|
1938
|
+
if (options.kind === "commit") {
|
|
1939
|
+
const sha = (options.ref || "").trim();
|
|
1940
|
+
if (!sha || sha === "worktree") return { url: base2, provider: "github" };
|
|
1941
|
+
return {
|
|
1942
|
+
url: `${base2}/commit/${encodeURIComponent(sha)}`,
|
|
1943
|
+
provider: "github"
|
|
1944
|
+
};
|
|
1945
|
+
}
|
|
1641
1946
|
const ref = encodePath(resolvedRef(options.ref, options.fallbackRef));
|
|
1642
1947
|
const path = encodePath(options.path || "");
|
|
1643
1948
|
if (!ref || options.kind === "blob" && !path) {
|
|
@@ -1660,6 +1965,61 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1660
1965
|
return { url: `${target}${lineHash}`, provider: "github" };
|
|
1661
1966
|
}
|
|
1662
1967
|
|
|
1968
|
+
// web-src/core/history.ts
|
|
1969
|
+
function parseHistoryLineRange(value) {
|
|
1970
|
+
const match2 = /^(\d+)-(\d+)$/.exec(value || "");
|
|
1971
|
+
if (!match2) return void 0;
|
|
1972
|
+
const a2 = Number(match2[1]);
|
|
1973
|
+
const b2 = Number(match2[2]);
|
|
1974
|
+
if (!(a2 > 0) || !(b2 > 0)) return void 0;
|
|
1975
|
+
return { start: Math.min(a2, b2), end: Math.max(a2, b2) };
|
|
1976
|
+
}
|
|
1977
|
+
function formatHistoryLineRange(range) {
|
|
1978
|
+
return `${range.start}-${range.end}`;
|
|
1979
|
+
}
|
|
1980
|
+
var EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
1981
|
+
var HISTORY_PAGE_SIZE = 50;
|
|
1982
|
+
var HISTORY_AUTO_LOAD_MAX_PAGES = 20;
|
|
1983
|
+
function commitDiffRange(commit) {
|
|
1984
|
+
return { from: commit.parents[0] || EMPTY_TREE_SHA, to: commit.sha };
|
|
1985
|
+
}
|
|
1986
|
+
function shouldContinueAutoLoad(state) {
|
|
1987
|
+
if (state.found) return false;
|
|
1988
|
+
if (!state.hasMore) return false;
|
|
1989
|
+
return state.pagesLoaded < HISTORY_AUTO_LOAD_MAX_PAGES;
|
|
1990
|
+
}
|
|
1991
|
+
var MONTH_NAMES = [
|
|
1992
|
+
"January",
|
|
1993
|
+
"February",
|
|
1994
|
+
"March",
|
|
1995
|
+
"April",
|
|
1996
|
+
"May",
|
|
1997
|
+
"June",
|
|
1998
|
+
"July",
|
|
1999
|
+
"August",
|
|
2000
|
+
"September",
|
|
2001
|
+
"October",
|
|
2002
|
+
"November",
|
|
2003
|
+
"December"
|
|
2004
|
+
];
|
|
2005
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
2006
|
+
function historyGroupLabel(whenIso, now) {
|
|
2007
|
+
const t2 = Date.parse(whenIso);
|
|
2008
|
+
if (!Number.isFinite(t2)) return "Unknown date";
|
|
2009
|
+
const dayStart = new Date(
|
|
2010
|
+
now.getFullYear(),
|
|
2011
|
+
now.getMonth(),
|
|
2012
|
+
now.getDate()
|
|
2013
|
+
).getTime();
|
|
2014
|
+
if (t2 >= dayStart) return "Today";
|
|
2015
|
+
if (t2 >= dayStart - DAY_MS) return "Yesterday";
|
|
2016
|
+
if (t2 >= dayStart - 6 * DAY_MS) return "This week";
|
|
2017
|
+
const d2 = new Date(t2);
|
|
2018
|
+
if (d2.getFullYear() === now.getFullYear() && d2.getMonth() === now.getMonth())
|
|
2019
|
+
return "This month";
|
|
2020
|
+
return `${MONTH_NAMES[d2.getMonth()]} ${d2.getFullYear()}`;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
1663
2023
|
// web-src/core/shell.ts
|
|
1664
2024
|
var MIN_SHELL_COLS = 20;
|
|
1665
2025
|
var MAX_SHELL_COLS = 1e3;
|
|
@@ -1756,6 +2116,7 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1756
2116
|
};
|
|
1757
2117
|
const rawView = params.get("view");
|
|
1758
2118
|
const preview = params.get("preview") === "1";
|
|
2119
|
+
const hl = params.get("hl") || "";
|
|
1759
2120
|
if (rawView === "blob") {
|
|
1760
2121
|
return {
|
|
1761
2122
|
screen: "file",
|
|
@@ -1765,6 +2126,7 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1765
2126
|
view: "blob",
|
|
1766
2127
|
...preview ? { preview: true } : {},
|
|
1767
2128
|
...line ? { line } : {},
|
|
2129
|
+
...line && hl ? { hl } : {},
|
|
1768
2130
|
...params.get("virtual") === "off" ? { virtual: "off" } : {}
|
|
1769
2131
|
};
|
|
1770
2132
|
}
|
|
@@ -1786,6 +2148,9 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1786
2148
|
range,
|
|
1787
2149
|
view: "history",
|
|
1788
2150
|
...params.get("commit") ? { commit: params.get("commit") || "" } : {},
|
|
2151
|
+
...params.get("compare") ? { compare: params.get("compare") || "" } : {},
|
|
2152
|
+
...params.get("q") ? { q: params.get("q") || "" } : {},
|
|
2153
|
+
...parseHistoryLineRange(params.get("lines")) ? { lines: parseHistoryLineRange(params.get("lines")) } : {},
|
|
1789
2154
|
...line ? { line } : {}
|
|
1790
2155
|
};
|
|
1791
2156
|
}
|
|
@@ -1829,10 +2194,18 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1829
2194
|
};
|
|
1830
2195
|
case "/history": {
|
|
1831
2196
|
const commit = params.get("commit") || "";
|
|
2197
|
+
const compare = params.get("compare") || "";
|
|
2198
|
+
const q = params.get("q") || "";
|
|
2199
|
+
const path = params.get("path") || "";
|
|
2200
|
+
const lines = parseHistoryLineRange(params.get("lines"));
|
|
1832
2201
|
return {
|
|
1833
2202
|
screen: "history",
|
|
1834
2203
|
ref: params.get("ref") || "HEAD",
|
|
1835
2204
|
...commit ? { commit } : {},
|
|
2205
|
+
...compare ? { compare } : {},
|
|
2206
|
+
...q ? { q } : {},
|
|
2207
|
+
...path ? { path } : {},
|
|
2208
|
+
...path && lines ? { lines } : {},
|
|
1836
2209
|
range
|
|
1837
2210
|
};
|
|
1838
2211
|
}
|
|
@@ -1891,14 +2264,14 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1891
2264
|
}
|
|
1892
2265
|
case "file":
|
|
1893
2266
|
if (route.view === "blob") {
|
|
1894
|
-
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree") + "&view=blob" + (route.preview ? "&preview=1" : "") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "") + (route.virtual === "off" ? "&virtual=off" : "");
|
|
2267
|
+
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree") + "&view=blob" + (route.preview ? "&preview=1" : "") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "") + (route.line && route.hl ? `&hl=${encodeURIComponent(route.hl)}` : "") + (route.virtual === "off" ? "&virtual=off" : "");
|
|
1895
2268
|
}
|
|
1896
2269
|
if (route.view === "blame") {
|
|
1897
2270
|
const ref = route.ref || "worktree";
|
|
1898
2271
|
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(ref) + "&view=blame" + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "");
|
|
1899
2272
|
}
|
|
1900
2273
|
if (route.view === "history") {
|
|
1901
|
-
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree") + "&view=history" + (route.commit ? `&commit=${encodeURIComponent(route.commit)}` : "") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "");
|
|
2274
|
+
return "/file?path=" + encodeURIComponent(route.path) + "&target=" + encodeURIComponent(route.ref || "worktree") + "&view=history" + (route.commit ? `&commit=${encodeURIComponent(route.commit)}` : "") + (route.compare ? `&compare=${encodeURIComponent(route.compare)}` : "") + (route.q ? `&q=${encodeURIComponent(route.q)}` : "") + (route.lines ? `&lines=${encodeURIComponent(formatHistoryLineRange(route.lines))}` : "") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "");
|
|
1902
2275
|
}
|
|
1903
2276
|
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))}` : "") + (route.virtual === "off" ? "&virtual=off" : "");
|
|
1904
2277
|
case "diff":
|
|
@@ -1922,7 +2295,12 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1922
2295
|
case "history": {
|
|
1923
2296
|
const params = new URLSearchParams();
|
|
1924
2297
|
if (route.ref && route.ref !== "HEAD") params.set("ref", route.ref);
|
|
2298
|
+
if (route.path) params.set("path", route.path);
|
|
2299
|
+
if (route.path && route.lines)
|
|
2300
|
+
params.set("lines", formatHistoryLineRange(route.lines));
|
|
1925
2301
|
if (route.commit) params.set("commit", route.commit);
|
|
2302
|
+
if (route.compare) params.set("compare", route.compare);
|
|
2303
|
+
if (route.q) params.set("q", route.q);
|
|
1926
2304
|
const qs = params.toString();
|
|
1927
2305
|
return `/history${qs ? `?${qs}` : ""}`;
|
|
1928
2306
|
}
|
|
@@ -1989,6 +2367,64 @@ Details: ${JSON.stringify(output)}` : "";
|
|
|
1989
2367
|
function withTerminalOverlay(url, state) {
|
|
1990
2368
|
return withQueryParam(url, "terminal", state);
|
|
1991
2369
|
}
|
|
2370
|
+
function parseSearchResultsOverlay(search) {
|
|
2371
|
+
return new URLSearchParams(search).get("results");
|
|
2372
|
+
}
|
|
2373
|
+
function withSearchResultsOverlay(url, query) {
|
|
2374
|
+
return withQueryParam(url, "results", query);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
// web-src/core/search-palette.ts
|
|
2378
|
+
var PALETTE_RESULT_LIMIT = 50;
|
|
2379
|
+
var GREP_SELECTION_HISTORY_LIMIT = 100;
|
|
2380
|
+
var MIN_GREP_PALETTE_WIDTH = 720;
|
|
2381
|
+
var MAX_GREP_PALETTE_WIDTH = 2400;
|
|
2382
|
+
var MIN_GREP_PALETTE_HEIGHT = 420;
|
|
2383
|
+
var MAX_GREP_PALETTE_HEIGHT = 1400;
|
|
2384
|
+
function limitPaletteResults(items) {
|
|
2385
|
+
return items.slice(0, PALETTE_RESULT_LIMIT);
|
|
2386
|
+
}
|
|
2387
|
+
function movePaletteSelection(index, count, direction) {
|
|
2388
|
+
if (count <= 0) return -1;
|
|
2389
|
+
if (index < 0) return direction > 0 ? 0 : count - 1;
|
|
2390
|
+
return Math.max(0, Math.min(count - 1, index + direction));
|
|
2391
|
+
}
|
|
2392
|
+
function rememberPaletteSelection(history2, path) {
|
|
2393
|
+
const next = history2.filter((entry) => entry !== path);
|
|
2394
|
+
next.push(path);
|
|
2395
|
+
return next.slice(-GREP_SELECTION_HISTORY_LIMIT);
|
|
2396
|
+
}
|
|
2397
|
+
function rankPaletteResultsByHistory(items, history2) {
|
|
2398
|
+
const priority = new Map(history2.map((path, index) => [path, index + 1]));
|
|
2399
|
+
return items.map((item, index) => ({ item, index })).sort(
|
|
2400
|
+
(a2, b2) => (priority.get(b2.item.path) ?? 0) - (priority.get(a2.item.path) ?? 0) || a2.index - b2.index
|
|
2401
|
+
).map(({ item }) => item);
|
|
2402
|
+
}
|
|
2403
|
+
function parseGrepQuery(raw) {
|
|
2404
|
+
const paths = [];
|
|
2405
|
+
const words = [];
|
|
2406
|
+
for (const token of raw.trim().split(/\s+/)) {
|
|
2407
|
+
if (!token) continue;
|
|
2408
|
+
const scoped = /^path:(.*)$/.exec(token);
|
|
2409
|
+
if (scoped) {
|
|
2410
|
+
if (scoped[1]) paths.push(scoped[1]);
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
words.push(token);
|
|
2414
|
+
}
|
|
2415
|
+
return { term: words.join(" "), paths };
|
|
2416
|
+
}
|
|
2417
|
+
function buildGrepRequestParams(options) {
|
|
2418
|
+
const params = new URLSearchParams();
|
|
2419
|
+
params.set("ref", options.ref);
|
|
2420
|
+
params.set("q", options.term);
|
|
2421
|
+
params.set("max", String(options.max));
|
|
2422
|
+
if (options.regex) params.set("regex", "1");
|
|
2423
|
+
if (options.caseSensitive) params.set("case", "1");
|
|
2424
|
+
if (options.wholeWord) params.set("word", "1");
|
|
2425
|
+
if (options.hideTests) params.set("exclude_tests", "1");
|
|
2426
|
+
return params;
|
|
2427
|
+
}
|
|
1992
2428
|
|
|
1993
2429
|
// web-src/views/media-player.ts
|
|
1994
2430
|
var PLAYBACK_RATES = [1, 1.25, 1.5, 2];
|
|
@@ -11534,6 +11970,8 @@ ${frontmatter.yaml}
|
|
|
11534
11970
|
header.appendChild(name);
|
|
11535
11971
|
const repositoryWebLink = deps.createRepositoryWebLink?.(target);
|
|
11536
11972
|
if (repositoryWebLink) header.appendChild(repositoryWebLink);
|
|
11973
|
+
const revisionNav = deps.createRevisionNav?.(target, activeTab);
|
|
11974
|
+
if (revisionNav) header.appendChild(revisionNav);
|
|
11537
11975
|
sticky.appendChild(header);
|
|
11538
11976
|
const tabsHost = document.createElement("div");
|
|
11539
11977
|
tabsHost.className = "gdp-file-detail-tabs";
|
|
@@ -11753,7 +12191,8 @@ ${frontmatter.yaml}
|
|
|
11753
12191
|
setRoute: deps.setRoute,
|
|
11754
12192
|
setPreferredSourceTab: deps.setPreferredSourceTab,
|
|
11755
12193
|
createFileBreadcrumb: deps.createFileBreadcrumb,
|
|
11756
|
-
createRepositoryWebLink: deps.createRepositoryWebLink
|
|
12194
|
+
createRepositoryWebLink: deps.createRepositoryWebLink,
|
|
12195
|
+
createRevisionNav: deps.createRevisionNav
|
|
11757
12196
|
},
|
|
11758
12197
|
target,
|
|
11759
12198
|
"blame"
|
|
@@ -27301,50 +27740,6 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27301
27740
|
deps.setStatus("live");
|
|
27302
27741
|
}
|
|
27303
27742
|
|
|
27304
|
-
// web-src/core/history.ts
|
|
27305
|
-
var EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
27306
|
-
var HISTORY_PAGE_SIZE = 50;
|
|
27307
|
-
var HISTORY_AUTO_LOAD_MAX_PAGES = 20;
|
|
27308
|
-
function commitDiffRange(commit) {
|
|
27309
|
-
return { from: commit.parents[0] || EMPTY_TREE_SHA, to: commit.sha };
|
|
27310
|
-
}
|
|
27311
|
-
function shouldContinueAutoLoad(state) {
|
|
27312
|
-
if (state.found) return false;
|
|
27313
|
-
if (!state.hasMore) return false;
|
|
27314
|
-
return state.pagesLoaded < HISTORY_AUTO_LOAD_MAX_PAGES;
|
|
27315
|
-
}
|
|
27316
|
-
var MONTH_NAMES = [
|
|
27317
|
-
"January",
|
|
27318
|
-
"February",
|
|
27319
|
-
"March",
|
|
27320
|
-
"April",
|
|
27321
|
-
"May",
|
|
27322
|
-
"June",
|
|
27323
|
-
"July",
|
|
27324
|
-
"August",
|
|
27325
|
-
"September",
|
|
27326
|
-
"October",
|
|
27327
|
-
"November",
|
|
27328
|
-
"December"
|
|
27329
|
-
];
|
|
27330
|
-
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
27331
|
-
function historyGroupLabel(whenIso, now) {
|
|
27332
|
-
const t2 = Date.parse(whenIso);
|
|
27333
|
-
if (!Number.isFinite(t2)) return "Unknown date";
|
|
27334
|
-
const dayStart = new Date(
|
|
27335
|
-
now.getFullYear(),
|
|
27336
|
-
now.getMonth(),
|
|
27337
|
-
now.getDate()
|
|
27338
|
-
).getTime();
|
|
27339
|
-
if (t2 >= dayStart) return "Today";
|
|
27340
|
-
if (t2 >= dayStart - DAY_MS) return "Yesterday";
|
|
27341
|
-
if (t2 >= dayStart - 6 * DAY_MS) return "This week";
|
|
27342
|
-
const d2 = new Date(t2);
|
|
27343
|
-
if (d2.getFullYear() === now.getFullYear() && d2.getMonth() === now.getMonth())
|
|
27344
|
-
return "This month";
|
|
27345
|
-
return `${MONTH_NAMES[d2.getMonth()]} ${d2.getFullYear()}`;
|
|
27346
|
-
}
|
|
27347
|
-
|
|
27348
27743
|
// web-src/views/history-view.ts
|
|
27349
27744
|
var HISTORY_BODY_COLLAPSE_LINES = 10;
|
|
27350
27745
|
var HISTORY_WORKTREE_COMMIT = "worktree";
|
|
@@ -27357,7 +27752,21 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27357
27752
|
refreshTitle: "Refresh commit history",
|
|
27358
27753
|
refreshTitlePending: "History may have changed. Refresh",
|
|
27359
27754
|
filterClearLabel: "Clear",
|
|
27360
|
-
filterClearTitle: "Clear commit filter"
|
|
27755
|
+
filterClearTitle: "Clear commit filter",
|
|
27756
|
+
filterPlaceholder: "filter… text author: path: since: code:",
|
|
27757
|
+
filterTitle: 'Filter commits. Words match the message ("quoted" keeps spaces), sha prefixes match commits, author:<name>, path:<part>, since:/after:<date>, until:/before:<date>, code:<text> (lines added or removed), merges:no / merges:only. Kinds combine with AND.',
|
|
27758
|
+
commitsTitle: "Commits",
|
|
27759
|
+
commitsIn: (path) => `Commits · ${path}`,
|
|
27760
|
+
commitsForLines: (start, end) => start === end ? `Commits · line ${start}` : `Commits · lines ${start}-${end}`,
|
|
27761
|
+
copyShaTitle: "Copy full commit sha",
|
|
27762
|
+
copiedTitle: "Copied",
|
|
27763
|
+
copyFailedTitle: "Copy failed",
|
|
27764
|
+
mergeBadge: "merge",
|
|
27765
|
+
compareWith: "Compare with",
|
|
27766
|
+
parentLabel: (index, shortSha) => `parent ${index} (${shortSha})`,
|
|
27767
|
+
comparing: (from, to) => `Comparing ${from}..${to}`,
|
|
27768
|
+
clearCompare: "Clear",
|
|
27769
|
+
refTitle: (kind, name) => kind === "tag" ? `Tag ${name}` : kind === "head" ? "HEAD" : `Branch ${name}`
|
|
27361
27770
|
},
|
|
27362
27771
|
ja: {
|
|
27363
27772
|
worktreeLabel: "未コミット変更 (Working tree)",
|
|
@@ -27367,7 +27776,21 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27367
27776
|
refreshTitle: "コミット履歴を更新",
|
|
27368
27777
|
refreshTitlePending: "新しい履歴がある可能性があります。更新",
|
|
27369
27778
|
filterClearLabel: "解除",
|
|
27370
|
-
filterClearTitle: "コミットフィルタを解除"
|
|
27779
|
+
filterClearTitle: "コミットフィルタを解除",
|
|
27780
|
+
filterPlaceholder: "絞り込み… 文字列 author: path: since: code:",
|
|
27781
|
+
filterTitle: 'コミットを絞り込みます。語はメッセージに一致("引用" で空白を含む句)、sha の前方一致、author:<名前>、path:<一部>、since:/after:<日付>、until:/before:<日付>、code:<文字列>(追加・削除された行)、merges:no / merges:only。種類が違う条件は AND。',
|
|
27782
|
+
commitsTitle: "コミット",
|
|
27783
|
+
commitsIn: (path) => `コミット · ${path}`,
|
|
27784
|
+
commitsForLines: (start, end) => start === end ? `コミット · ${start} 行目` : `コミット · ${start}-${end} 行`,
|
|
27785
|
+
copyShaTitle: "コミットの sha をコピー",
|
|
27786
|
+
copiedTitle: "コピーしました",
|
|
27787
|
+
copyFailedTitle: "コピーに失敗しました",
|
|
27788
|
+
mergeBadge: "merge",
|
|
27789
|
+
compareWith: "比較対象",
|
|
27790
|
+
parentLabel: (index, shortSha) => `親 ${index} (${shortSha})`,
|
|
27791
|
+
comparing: (from, to) => `${from}..${to} を比較中`,
|
|
27792
|
+
clearCompare: "解除",
|
|
27793
|
+
refTitle: (kind, name) => kind === "tag" ? `タグ ${name}` : kind === "head" ? "HEAD" : `ブランチ ${name}`
|
|
27371
27794
|
}
|
|
27372
27795
|
};
|
|
27373
27796
|
function historyText(lang) {
|
|
@@ -27387,6 +27810,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27387
27810
|
panel.className = "gdp-file-history-panel";
|
|
27388
27811
|
}
|
|
27389
27812
|
panel.setAttribute("aria-label", "Commit history");
|
|
27813
|
+
panel.tabIndex = -1;
|
|
27390
27814
|
const panelHead = document.createElement("div");
|
|
27391
27815
|
panelHead.className = "history-head";
|
|
27392
27816
|
const title = document.createElement("span");
|
|
@@ -27422,8 +27846,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27422
27846
|
if (page) filterInput.id = "history-filter";
|
|
27423
27847
|
else filterInput.className = "history-filter";
|
|
27424
27848
|
filterInput.type = "search";
|
|
27425
|
-
filterInput.placeholder =
|
|
27849
|
+
filterInput.placeholder = HISTORY_TEXT.en.filterPlaceholder;
|
|
27850
|
+
filterInput.title = HISTORY_TEXT.en.filterTitle;
|
|
27426
27851
|
filterInput.autocomplete = "off";
|
|
27852
|
+
const authorList = document.createElement("datalist");
|
|
27853
|
+
authorList.id = page ? "history-filter-authors" : `history-filter-authors-${Math.random().toString(36).slice(2, 8)}`;
|
|
27854
|
+
filterInput.setAttribute("list", authorList.id);
|
|
27427
27855
|
const filterClearButton = document.createElement("button");
|
|
27428
27856
|
filterClearButton.type = "button";
|
|
27429
27857
|
if (page) filterClearButton.id = "history-filter-clear";
|
|
@@ -27435,7 +27863,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27435
27863
|
"aria-label",
|
|
27436
27864
|
HISTORY_TEXT.en.filterClearTitle
|
|
27437
27865
|
);
|
|
27438
|
-
filterWrap.append(filterInput, filterClearButton);
|
|
27866
|
+
filterWrap.append(filterInput, filterClearButton, authorList);
|
|
27439
27867
|
const banner = document.createElement("div");
|
|
27440
27868
|
if (page) banner.id = "history-banner";
|
|
27441
27869
|
banner.className = "history-banner";
|
|
@@ -27462,6 +27890,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27462
27890
|
sentinel,
|
|
27463
27891
|
filterInput,
|
|
27464
27892
|
filterClearButton,
|
|
27893
|
+
authorList,
|
|
27465
27894
|
refreshButton,
|
|
27466
27895
|
refreshResult
|
|
27467
27896
|
};
|
|
@@ -27485,7 +27914,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27485
27914
|
const date = document.createElement("span");
|
|
27486
27915
|
if (page) date.id = "hci-date";
|
|
27487
27916
|
date.className = "hci-date";
|
|
27488
|
-
|
|
27917
|
+
const actions = document.createElement("span");
|
|
27918
|
+
actions.className = "hci-actions";
|
|
27919
|
+
head.append(sha, author, date, actions);
|
|
27489
27920
|
const subject = document.createElement("h2");
|
|
27490
27921
|
if (page) subject.id = "hci-subject";
|
|
27491
27922
|
subject.className = "hci-subject";
|
|
@@ -27587,6 +28018,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27587
28018
|
let pathFilter = "";
|
|
27588
28019
|
let refreshStatus = { type: "none" };
|
|
27589
28020
|
let freshSha = "";
|
|
28021
|
+
let compareSha = "";
|
|
28022
|
+
let authorsLoadedFor = "";
|
|
28023
|
+
let lineRange2;
|
|
28024
|
+
function lineRangeKey(range) {
|
|
28025
|
+
return range ? formatHistoryLineRange(range) : "";
|
|
28026
|
+
}
|
|
27590
28027
|
function historyScopeFromRoute(route = deps.getRoute()) {
|
|
27591
28028
|
if (route.screen === "history") {
|
|
27592
28029
|
const nextRef = route.ref || "HEAD";
|
|
@@ -27594,8 +28031,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27594
28031
|
mode: "history",
|
|
27595
28032
|
logRef: nextRef,
|
|
27596
28033
|
routeRef: nextRef,
|
|
27597
|
-
pathFilter: "",
|
|
27598
|
-
|
|
28034
|
+
pathFilter: route.path || "",
|
|
28035
|
+
query: route.q || "",
|
|
28036
|
+
lines: route.path ? route.lines : void 0,
|
|
28037
|
+
commit: route.commit,
|
|
28038
|
+
compare: route.compare
|
|
27599
28039
|
};
|
|
27600
28040
|
}
|
|
27601
28041
|
if (route.screen === "file" && route.view === "history") {
|
|
@@ -27605,11 +28045,51 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27605
28045
|
logRef: nextRouteRef === "worktree" ? "HEAD" : nextRouteRef,
|
|
27606
28046
|
routeRef: nextRouteRef,
|
|
27607
28047
|
pathFilter: route.path,
|
|
27608
|
-
|
|
28048
|
+
query: route.q || "",
|
|
28049
|
+
lines: route.lines,
|
|
28050
|
+
commit: route.commit,
|
|
28051
|
+
compare: route.compare
|
|
27609
28052
|
};
|
|
27610
28053
|
}
|
|
27611
28054
|
return null;
|
|
27612
28055
|
}
|
|
28056
|
+
function routeFor(options) {
|
|
28057
|
+
const commit = options.commit;
|
|
28058
|
+
const compare = options.compare || void 0;
|
|
28059
|
+
const q = (options.query ?? query) || void 0;
|
|
28060
|
+
const range = commit && commit !== HISTORY_WORKTREE_COMMIT ? diffRangeFor(commit, compare) : worktreeDiffRange();
|
|
28061
|
+
if (mode === "file") {
|
|
28062
|
+
return {
|
|
28063
|
+
screen: "file",
|
|
28064
|
+
path: pathFilter,
|
|
28065
|
+
ref: options.ref ?? routeRef,
|
|
28066
|
+
view: "history",
|
|
28067
|
+
...commit ? { commit } : {},
|
|
28068
|
+
...compare ? { compare } : {},
|
|
28069
|
+
...q ? { q } : {},
|
|
28070
|
+
...lineRange2 ? { lines: lineRange2 } : {},
|
|
28071
|
+
range
|
|
28072
|
+
};
|
|
28073
|
+
}
|
|
28074
|
+
return {
|
|
28075
|
+
screen: "history",
|
|
28076
|
+
ref: options.ref ?? ref,
|
|
28077
|
+
...pathFilter ? { path: pathFilter } : {},
|
|
28078
|
+
...pathFilter && lineRange2 ? { lines: lineRange2 } : {},
|
|
28079
|
+
...commit ? { commit } : {},
|
|
28080
|
+
...compare ? { compare } : {},
|
|
28081
|
+
...q ? { q } : {},
|
|
28082
|
+
range
|
|
28083
|
+
};
|
|
28084
|
+
}
|
|
28085
|
+
function diffRangeFor(sha, compare) {
|
|
28086
|
+
const commit = commits.find((item) => item.sha === sha);
|
|
28087
|
+
if (compare) return { from: compare, to: sha };
|
|
28088
|
+
return commit ? commitDiffRange(commit) : { from: `${sha}^`, to: sha };
|
|
28089
|
+
}
|
|
28090
|
+
function shortSha(sha) {
|
|
28091
|
+
return sha.slice(0, 7);
|
|
28092
|
+
}
|
|
27613
28093
|
function currentRefreshScopeKey() {
|
|
27614
28094
|
const scope = historyScopeFromRoute();
|
|
27615
28095
|
if (!scope) return "";
|
|
@@ -27618,6 +28098,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27618
28098
|
scope.logRef,
|
|
27619
28099
|
scope.routeRef,
|
|
27620
28100
|
scope.pathFilter,
|
|
28101
|
+
lineRangeKey(scope.lines),
|
|
27621
28102
|
query
|
|
27622
28103
|
].join("\0");
|
|
27623
28104
|
}
|
|
@@ -27699,6 +28180,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27699
28180
|
if (query) params.set("q", query);
|
|
27700
28181
|
if (pathFilter) {
|
|
27701
28182
|
params.set("path", pathFilter);
|
|
28183
|
+
if (lineRange2) params.set("lines", formatHistoryLineRange(lineRange2));
|
|
27702
28184
|
if (routeRef === "worktree") params.set("worktree", "1");
|
|
27703
28185
|
}
|
|
27704
28186
|
const url = `/_log?${params.toString()}`;
|
|
@@ -27715,10 +28197,43 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27715
28197
|
return null;
|
|
27716
28198
|
});
|
|
27717
28199
|
}
|
|
27718
|
-
function
|
|
28200
|
+
function refChipsHtml(commit) {
|
|
28201
|
+
const text3 = historyText(deps.getLanguage());
|
|
28202
|
+
const chips = [];
|
|
28203
|
+
for (const ref2 of commit.refs ?? []) {
|
|
28204
|
+
const classes = [
|
|
28205
|
+
"history-ref",
|
|
28206
|
+
`history-ref-${ref2.kind}`,
|
|
28207
|
+
ref2.head ? "history-ref-head" : ""
|
|
28208
|
+
].filter(Boolean).join(" ");
|
|
28209
|
+
chips.push(
|
|
28210
|
+
`<span class="${classes}" title="${deps.escapeHtml(text3.refTitle(ref2.kind, ref2.name))}">${deps.escapeHtml(ref2.name)}</span>`
|
|
28211
|
+
);
|
|
28212
|
+
}
|
|
28213
|
+
if (commit.parents.length > 1) {
|
|
28214
|
+
chips.push(
|
|
28215
|
+
`<span class="history-ref history-ref-merge" title="${deps.escapeHtml(text3.mergeBadge)}">${deps.escapeHtml(text3.mergeBadge)}</span>`
|
|
28216
|
+
);
|
|
28217
|
+
}
|
|
28218
|
+
return chips.length ? `<span class="history-refs">${chips.join("")}</span>` : "";
|
|
28219
|
+
}
|
|
28220
|
+
function commitRow(commit, inRange) {
|
|
27719
28221
|
const active = commit.sha === selectedSha ? " active" : "";
|
|
27720
28222
|
const fresh = commit.sha === freshSha ? " history-item-fresh" : "";
|
|
27721
|
-
|
|
28223
|
+
const ranged = inRange ? " history-item-in-range" : "";
|
|
28224
|
+
return `<li class="history-item${active}${fresh}${ranged}" data-sha="${deps.escapeHtml(commit.sha)}"><span class="subject" title="${deps.escapeHtml(commit.subject)}">${deps.escapeHtml(commit.subject)}</span><span class="meta2"><span class="sha">${deps.escapeHtml(shortSha(commit.sha))}</span><span class="author">${deps.escapeHtml(commit.author)}</span><span class="when">${deps.escapeHtml(displayWhen(commit.when))}</span>` + refChipsHtml(commit) + `</span></li>`;
|
|
28225
|
+
}
|
|
28226
|
+
function rangeShas() {
|
|
28227
|
+
const shas = /* @__PURE__ */ new Set();
|
|
28228
|
+
if (!compareSha || !selectedSha) return shas;
|
|
28229
|
+
const start = commits.findIndex((commit) => commit.sha === selectedSha);
|
|
28230
|
+
if (start < 0) return shas;
|
|
28231
|
+
const end = commits.findIndex(
|
|
28232
|
+
(commit, index) => index >= start && commit.parents[0] === compareSha
|
|
28233
|
+
);
|
|
28234
|
+
if (end < 0) return shas;
|
|
28235
|
+
for (let index = start; index <= end; index++) shas.add(commits[index].sha);
|
|
28236
|
+
return shas;
|
|
27722
28237
|
}
|
|
27723
28238
|
function worktreeRow() {
|
|
27724
28239
|
const active = selectedSha === HISTORY_WORKTREE_COMMIT ? " active" : "";
|
|
@@ -27729,6 +28244,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27729
28244
|
syncRefreshResult(activeMount.refreshResult);
|
|
27730
28245
|
const now = /* @__PURE__ */ new Date();
|
|
27731
28246
|
const html = mode === "history" ? [worktreeRow()] : [];
|
|
28247
|
+
const inRange = rangeShas();
|
|
27732
28248
|
let lastGroup = "";
|
|
27733
28249
|
for (const commit of commits) {
|
|
27734
28250
|
if (commit.sha === HISTORY_WORKTREE_COMMIT) {
|
|
@@ -27742,7 +28258,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27742
28258
|
);
|
|
27743
28259
|
lastGroup = group;
|
|
27744
28260
|
}
|
|
27745
|
-
html.push(commitRow(commit));
|
|
28261
|
+
html.push(commitRow(commit, inRange.has(commit.sha)));
|
|
27746
28262
|
}
|
|
27747
28263
|
list2.innerHTML = html.join("");
|
|
27748
28264
|
activeHistoryRow = list2.querySelector(".history-item.active");
|
|
@@ -27792,6 +28308,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27792
28308
|
info.querySelector(".hci-head")?.removeAttribute("hidden");
|
|
27793
28309
|
set2(".hci-sha", commit.sha);
|
|
27794
28310
|
set2(".hci-author", commit.author);
|
|
28311
|
+
renderCommitActions(info, commit);
|
|
27795
28312
|
const t2 = Date.parse(commit.when);
|
|
27796
28313
|
set2(
|
|
27797
28314
|
".hci-date",
|
|
@@ -27818,6 +28335,80 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27818
28335
|
}
|
|
27819
28336
|
info.hidden = false;
|
|
27820
28337
|
}
|
|
28338
|
+
function renderCommitActions(info, commit) {
|
|
28339
|
+
const actions = info.querySelector(".hci-actions");
|
|
28340
|
+
if (!actions) return;
|
|
28341
|
+
actions.replaceChildren();
|
|
28342
|
+
const text3 = historyText(deps.getLanguage());
|
|
28343
|
+
if (deps.copyText) {
|
|
28344
|
+
const copy = document.createElement("button");
|
|
28345
|
+
copy.type = "button";
|
|
28346
|
+
copy.className = "gdp-btn gdp-btn-sm hci-copy";
|
|
28347
|
+
copy.title = text3.copyShaTitle;
|
|
28348
|
+
copy.setAttribute("aria-label", text3.copyShaTitle);
|
|
28349
|
+
copy.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
28350
|
+
let resetTimer = null;
|
|
28351
|
+
const copyText = deps.copyText;
|
|
28352
|
+
copy.addEventListener("click", () => {
|
|
28353
|
+
void copyText(commit.sha).then(() => {
|
|
28354
|
+
copy.innerHTML = iconSvg("octicon-check", CHECK_16_PATHS);
|
|
28355
|
+
copy.title = text3.copiedTitle;
|
|
28356
|
+
copy.classList.add("copied");
|
|
28357
|
+
}).catch((err) => {
|
|
28358
|
+
console.error("Failed to copy commit sha", err);
|
|
28359
|
+
copy.title = text3.copyFailedTitle;
|
|
28360
|
+
copy.classList.add("failed");
|
|
28361
|
+
}).finally(() => {
|
|
28362
|
+
if (resetTimer) clearTimeout(resetTimer);
|
|
28363
|
+
resetTimer = setTimeout(() => {
|
|
28364
|
+
copy.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
28365
|
+
copy.title = text3.copyShaTitle;
|
|
28366
|
+
copy.classList.remove("copied", "failed");
|
|
28367
|
+
}, 1200);
|
|
28368
|
+
});
|
|
28369
|
+
});
|
|
28370
|
+
actions.appendChild(copy);
|
|
28371
|
+
}
|
|
28372
|
+
const link2 = deps.commitWebLink?.(commit.sha);
|
|
28373
|
+
if (link2) {
|
|
28374
|
+
link2.classList.add("hci-link");
|
|
28375
|
+
actions.appendChild(link2);
|
|
28376
|
+
}
|
|
28377
|
+
if (commit.parents.length > 1) {
|
|
28378
|
+
const label = document.createElement("span");
|
|
28379
|
+
label.className = "hci-compare-label";
|
|
28380
|
+
label.textContent = text3.compareWith;
|
|
28381
|
+
actions.appendChild(label);
|
|
28382
|
+
commit.parents.forEach((parent, index) => {
|
|
28383
|
+
const button = document.createElement("button");
|
|
28384
|
+
button.type = "button";
|
|
28385
|
+
button.className = "gdp-btn gdp-btn-sm hci-parent";
|
|
28386
|
+
button.textContent = text3.parentLabel(index + 1, shortSha(parent));
|
|
28387
|
+
const active = compareSha ? compareSha === parent : index === 0;
|
|
28388
|
+
button.setAttribute("aria-pressed", String(active));
|
|
28389
|
+
button.addEventListener("click", () => {
|
|
28390
|
+
void selectCommit(commit, { compare: index === 0 ? "" : parent });
|
|
28391
|
+
});
|
|
28392
|
+
actions.appendChild(button);
|
|
28393
|
+
});
|
|
28394
|
+
}
|
|
28395
|
+
if (compareSha && !commit.parents.includes(compareSha)) {
|
|
28396
|
+
const label = document.createElement("span");
|
|
28397
|
+
label.className = "hci-compare-label";
|
|
28398
|
+
label.textContent = text3.comparing(
|
|
28399
|
+
shortSha(compareSha),
|
|
28400
|
+
shortSha(commit.sha)
|
|
28401
|
+
);
|
|
28402
|
+
const clear = document.createElement("button");
|
|
28403
|
+
clear.type = "button";
|
|
28404
|
+
clear.className = "gdp-btn gdp-btn-sm hci-compare-clear";
|
|
28405
|
+
clear.textContent = text3.clearCompare;
|
|
28406
|
+
clear.addEventListener("click", () => {
|
|
28407
|
+
void selectCommit(commit, { compare: "" });
|
|
28408
|
+
});
|
|
28409
|
+
actions.append(label, clear);
|
|
28410
|
+
}
|
|
28411
|
+
}
|
|
27821
28412
|
function updateWorktreeInfo() {
|
|
27822
28413
|
const info = commitInfoElement();
|
|
27823
28414
|
if (!info) return;
|
|
@@ -27843,11 +28434,16 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27843
28434
|
}
|
|
27844
28435
|
activeHistoryRow = selectedSha ? list2.querySelector(historyItemSelector(selectedSha)) : null;
|
|
27845
28436
|
activeHistoryRow?.classList.add("active");
|
|
28437
|
+
updateRangeRows();
|
|
27846
28438
|
}
|
|
27847
|
-
function
|
|
27848
|
-
|
|
27849
|
-
|
|
27850
|
-
|
|
28439
|
+
function updateRangeRows() {
|
|
28440
|
+
const inRange = rangeShas();
|
|
28441
|
+
list2.querySelectorAll(".history-item").forEach((row) => {
|
|
28442
|
+
row.classList.toggle(
|
|
28443
|
+
"history-item-in-range",
|
|
28444
|
+
inRange.has(row.dataset.sha || "")
|
|
28445
|
+
);
|
|
28446
|
+
});
|
|
27851
28447
|
}
|
|
27852
28448
|
function selectableShas() {
|
|
27853
28449
|
const shas = mode === "history" ? [HISTORY_WORKTREE_COMMIT] : [];
|
|
@@ -27909,63 +28505,46 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
27909
28505
|
const selectionGen = ++selectionGeneration;
|
|
27910
28506
|
const gen = generation;
|
|
27911
28507
|
selectedSha = commit.sha;
|
|
28508
|
+
compareSha = options.compare ?? "";
|
|
28509
|
+
if (compareSha === commit.parents[0]) compareSha = "";
|
|
27912
28510
|
updateActiveRow();
|
|
27913
28511
|
await updateCommitInfo(commit);
|
|
27914
28512
|
if (selectionGen !== selectionGeneration || gen !== generation) return;
|
|
28513
|
+
const range = compareSha ? { from: compareSha, to: commit.sha } : commitDiffRange(commit);
|
|
27915
28514
|
if (options.updateUrl !== false) {
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
screen: "file",
|
|
27921
|
-
path: pathFilter,
|
|
27922
|
-
ref: routeRef,
|
|
27923
|
-
view: "history",
|
|
27924
|
-
commit: commit.sha,
|
|
27925
|
-
range
|
|
27926
|
-
},
|
|
27927
|
-
true
|
|
27928
|
-
);
|
|
27929
|
-
} else {
|
|
27930
|
-
deps.setRoute(
|
|
27931
|
-
{ screen: "history", ref, commit: commit.sha, range },
|
|
27932
|
-
true
|
|
27933
|
-
);
|
|
27934
|
-
}
|
|
28515
|
+
deps.setRoute(
|
|
28516
|
+
routeFor({ commit: commit.sha, compare: compareSha }),
|
|
28517
|
+
true
|
|
28518
|
+
);
|
|
27935
28519
|
}
|
|
27936
28520
|
if (selectionGen !== selectionGeneration || gen !== generation) return;
|
|
27937
|
-
await deps.applyCommitRange(
|
|
27938
|
-
commitDiffRange(commit),
|
|
27939
|
-
pathFilter || void 0
|
|
27940
|
-
);
|
|
28521
|
+
await deps.applyCommitRange(range, pathFilter || void 0);
|
|
27941
28522
|
if (selectionGen !== selectionGeneration || gen !== generation) return;
|
|
27942
28523
|
}
|
|
28524
|
+
async function selectRange(clicked) {
|
|
28525
|
+
const anchor = commits.find((item) => item.sha === selectedSha);
|
|
28526
|
+
if (!anchor || anchor.sha === clicked.sha) {
|
|
28527
|
+
await selectCommit(clicked, { compare: "" });
|
|
28528
|
+
return;
|
|
28529
|
+
}
|
|
28530
|
+
const anchorIndex = commits.indexOf(anchor);
|
|
28531
|
+
const clickedIndex = commits.indexOf(clicked);
|
|
28532
|
+
const newer = anchorIndex < clickedIndex ? anchor : clicked;
|
|
28533
|
+
const older = newer === anchor ? clicked : anchor;
|
|
28534
|
+
await selectCommit(newer, {
|
|
28535
|
+
compare: older.parents[0] || EMPTY_TREE_SHA
|
|
28536
|
+
});
|
|
28537
|
+
}
|
|
27943
28538
|
async function selectWorktree(options = {}) {
|
|
27944
28539
|
const selectionGen = ++selectionGeneration;
|
|
27945
28540
|
const gen = generation;
|
|
27946
28541
|
selectedSha = HISTORY_WORKTREE_COMMIT;
|
|
28542
|
+
compareSha = "";
|
|
27947
28543
|
updateActiveRow();
|
|
27948
28544
|
updateWorktreeInfo();
|
|
27949
28545
|
const range = worktreeDiffRange();
|
|
27950
28546
|
if (options.updateUrl !== false) {
|
|
27951
|
-
|
|
27952
|
-
deps.setRoute(
|
|
27953
|
-
{
|
|
27954
|
-
screen: "file",
|
|
27955
|
-
path: pathFilter,
|
|
27956
|
-
ref: routeRef,
|
|
27957
|
-
view: "history",
|
|
27958
|
-
commit: selectedSha,
|
|
27959
|
-
range
|
|
27960
|
-
},
|
|
27961
|
-
true
|
|
27962
|
-
);
|
|
27963
|
-
} else {
|
|
27964
|
-
deps.setRoute(
|
|
27965
|
-
{ screen: "history", ref, commit: selectedSha, range },
|
|
27966
|
-
true
|
|
27967
|
-
);
|
|
27968
|
-
}
|
|
28547
|
+
deps.setRoute(routeFor({ commit: selectedSha }), true);
|
|
27969
28548
|
}
|
|
27970
28549
|
if (selectionGen !== selectionGeneration || gen !== generation) return;
|
|
27971
28550
|
await deps.applyCommitRange(range, pathFilter || void 0);
|
|
@@ -28003,10 +28582,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28003
28582
|
} else {
|
|
28004
28583
|
pagesLoaded = 1;
|
|
28005
28584
|
}
|
|
28585
|
+
const compare = historyScopeFromRoute()?.compare || "";
|
|
28006
28586
|
for (; ; ) {
|
|
28007
28587
|
const found = commits.find((c2) => c2.sha.startsWith(sha));
|
|
28008
28588
|
if (found) {
|
|
28009
|
-
await selectCommit(found, { updateUrl: false });
|
|
28589
|
+
await selectCommit(found, { updateUrl: false, compare });
|
|
28010
28590
|
scrollToSelected();
|
|
28011
28591
|
return;
|
|
28012
28592
|
}
|
|
@@ -28030,7 +28610,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28030
28610
|
setBanner(`showing commit outside the loaded ${ref} log`);
|
|
28031
28611
|
commits = [single, ...commits];
|
|
28032
28612
|
renderList();
|
|
28033
|
-
await selectCommit(single, { updateUrl: false });
|
|
28613
|
+
await selectCommit(single, { updateUrl: false, compare });
|
|
28034
28614
|
scrollToSelected();
|
|
28035
28615
|
}
|
|
28036
28616
|
function scrollToSelected() {
|
|
@@ -28047,14 +28627,19 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28047
28627
|
async function doEnterHistory(force = false) {
|
|
28048
28628
|
const scope = historyScopeFromRoute();
|
|
28049
28629
|
if (!scope) return;
|
|
28050
|
-
const scopeChanged = scope.logRef !== ref || scope.routeRef !== routeRef || scope.pathFilter !== pathFilter || scope.mode !== mode;
|
|
28630
|
+
const scopeChanged = scope.logRef !== ref || scope.routeRef !== routeRef || scope.pathFilter !== pathFilter || lineRangeKey(scope.lines) !== lineRangeKey(lineRange2) || scope.query !== query || scope.mode !== mode;
|
|
28051
28631
|
if (scopeChanged || force || commits.length === 0) {
|
|
28052
28632
|
generation++;
|
|
28053
28633
|
const gen = generation;
|
|
28054
28634
|
ref = scope.logRef;
|
|
28055
28635
|
routeRef = scope.routeRef;
|
|
28056
28636
|
pathFilter = scope.pathFilter;
|
|
28637
|
+
lineRange2 = scope.lines;
|
|
28638
|
+
query = scope.query;
|
|
28057
28639
|
mode = scope.mode;
|
|
28640
|
+
compareSha = "";
|
|
28641
|
+
syncFilterInputValue();
|
|
28642
|
+
syncPanelTitle();
|
|
28058
28643
|
commits = [];
|
|
28059
28644
|
hasMore = false;
|
|
28060
28645
|
loading = false;
|
|
@@ -28084,33 +28669,19 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28084
28669
|
}
|
|
28085
28670
|
function onRefPicked(nextRef) {
|
|
28086
28671
|
const value = nextRef && nextRef !== "worktree" ? nextRef : "HEAD";
|
|
28087
|
-
|
|
28088
|
-
|
|
28089
|
-
|
|
28090
|
-
|
|
28091
|
-
|
|
28092
|
-
|
|
28093
|
-
view: "history",
|
|
28094
|
-
range: { from: "HEAD", to: "worktree" }
|
|
28095
|
-
},
|
|
28096
|
-
false
|
|
28097
|
-
);
|
|
28098
|
-
} else {
|
|
28099
|
-
deps.setRoute(
|
|
28100
|
-
{
|
|
28101
|
-
screen: "history",
|
|
28102
|
-
ref: value,
|
|
28103
|
-
range: { from: "HEAD", to: "worktree" }
|
|
28104
|
-
},
|
|
28105
|
-
false
|
|
28106
|
-
);
|
|
28107
|
-
}
|
|
28672
|
+
deps.setRoute(
|
|
28673
|
+
routeFor({
|
|
28674
|
+
ref: mode === "file" ? nextRef || "worktree" : value
|
|
28675
|
+
}),
|
|
28676
|
+
false
|
|
28677
|
+
);
|
|
28108
28678
|
void enterHistory({ force: true });
|
|
28109
28679
|
}
|
|
28110
28680
|
function leaveHistory() {
|
|
28111
28681
|
generation++;
|
|
28112
28682
|
loading = false;
|
|
28113
28683
|
inFlight = null;
|
|
28684
|
+
compareSha = "";
|
|
28114
28685
|
if (filterTimer) {
|
|
28115
28686
|
clearTimeout(filterTimer);
|
|
28116
28687
|
filterTimer = void 0;
|
|
@@ -28125,17 +28696,33 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28125
28696
|
function handleListClick(e2) {
|
|
28126
28697
|
const row = e2.target.closest(".history-item");
|
|
28127
28698
|
if (!row?.dataset.sha) return;
|
|
28699
|
+
panel.focus?.();
|
|
28128
28700
|
if (row.dataset.sha === HISTORY_WORKTREE_COMMIT) {
|
|
28129
28701
|
void selectWorktree();
|
|
28130
28702
|
return;
|
|
28131
28703
|
}
|
|
28132
28704
|
const commit = commits.find((c2) => c2.sha === row.dataset.sha);
|
|
28133
|
-
if (commit)
|
|
28705
|
+
if (!commit) return;
|
|
28706
|
+
if (e2.shiftKey && selectedSha && selectedSha !== HISTORY_WORKTREE_COMMIT) {
|
|
28707
|
+
void selectRange(commit);
|
|
28708
|
+
return;
|
|
28709
|
+
}
|
|
28710
|
+
void selectCommit(commit, { compare: "" });
|
|
28134
28711
|
}
|
|
28135
28712
|
function applyFilter(next) {
|
|
28136
28713
|
const value = next.trim();
|
|
28137
28714
|
if (value === query) return;
|
|
28138
28715
|
query = value;
|
|
28716
|
+
if (historyScopeFromRoute()) {
|
|
28717
|
+
deps.setRoute(
|
|
28718
|
+
routeFor({
|
|
28719
|
+
commit: selectedSha || void 0,
|
|
28720
|
+
compare: compareSha,
|
|
28721
|
+
query: value
|
|
28722
|
+
}),
|
|
28723
|
+
true
|
|
28724
|
+
);
|
|
28725
|
+
}
|
|
28139
28726
|
generation++;
|
|
28140
28727
|
selectionGeneration++;
|
|
28141
28728
|
clearRefreshResult();
|
|
@@ -28224,6 +28811,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28224
28811
|
attachedFilterInput.removeEventListener("input", handleFilterInput);
|
|
28225
28812
|
attachedFilterInput.removeEventListener("change", handleFilterInput);
|
|
28226
28813
|
attachedFilterInput.removeEventListener("keydown", handleFilterKeydown);
|
|
28814
|
+
attachedFilterInput.removeEventListener("focus", handleFilterFocus);
|
|
28227
28815
|
attachedFilterInput = null;
|
|
28228
28816
|
}
|
|
28229
28817
|
if (attachedFilterClearButton) {
|
|
@@ -28256,8 +28844,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28256
28844
|
input2.addEventListener("input", handleFilterInput);
|
|
28257
28845
|
input2.addEventListener("change", handleFilterInput);
|
|
28258
28846
|
input2.addEventListener("keydown", handleFilterKeydown);
|
|
28847
|
+
input2.addEventListener("focus", handleFilterFocus);
|
|
28259
28848
|
attachedFilterInput = input2;
|
|
28260
28849
|
}
|
|
28850
|
+
syncPanelTitle();
|
|
28851
|
+
syncFilterChrome();
|
|
28261
28852
|
const filterClearButton = mount.filterClearButton ?? null;
|
|
28262
28853
|
if (filterClearButton) {
|
|
28263
28854
|
syncFilterClearButton(filterClearButton);
|
|
@@ -28281,14 +28872,50 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28281
28872
|
);
|
|
28282
28873
|
observer.observe(sentinel);
|
|
28283
28874
|
}
|
|
28875
|
+
function syncFilterInputValue() {
|
|
28876
|
+
const input2 = activeMount.filterInput ?? null;
|
|
28877
|
+
if (input2 && input2.value !== query) input2.value = query;
|
|
28878
|
+
syncFilterClearButton();
|
|
28879
|
+
}
|
|
28880
|
+
function syncFilterChrome() {
|
|
28881
|
+
const input2 = activeMount.filterInput ?? null;
|
|
28882
|
+
if (!input2) return;
|
|
28883
|
+
const text3 = historyText(deps.getLanguage());
|
|
28884
|
+
input2.placeholder = text3.filterPlaceholder;
|
|
28885
|
+
input2.title = text3.filterTitle;
|
|
28886
|
+
}
|
|
28887
|
+
function syncPanelTitle() {
|
|
28888
|
+
const title = panel.querySelector?.(".history-title");
|
|
28889
|
+
if (!title) return;
|
|
28890
|
+
const text3 = historyText(deps.getLanguage());
|
|
28891
|
+
title.textContent = lineRange2 ? text3.commitsForLines(lineRange2.start, lineRange2.end) : mode === "history" && pathFilter ? text3.commitsIn(pathFilter) : text3.commitsTitle;
|
|
28892
|
+
}
|
|
28893
|
+
function handleFilterFocus() {
|
|
28894
|
+
const list3 = activeMount.authorList ?? null;
|
|
28895
|
+
if (!list3 || typeof fetch !== "function") return;
|
|
28896
|
+
const key = ref;
|
|
28897
|
+
if (authorsLoadedFor === key) return;
|
|
28898
|
+
authorsLoadedFor = key;
|
|
28899
|
+
void deps.trackLoad(
|
|
28900
|
+
fetch(`/_authors?ref=${encodeURIComponent(ref)}`).then(async (r2) => {
|
|
28901
|
+
if (!r2.ok) throw new Error(await r2.text());
|
|
28902
|
+
return await r2.json();
|
|
28903
|
+
})
|
|
28904
|
+
).then((res) => {
|
|
28905
|
+
if (activeMount.authorList !== list3 || key !== ref) return;
|
|
28906
|
+
list3.replaceChildren(
|
|
28907
|
+
...res.authors.map((author) => {
|
|
28908
|
+
const option = document.createElement("option");
|
|
28909
|
+
option.value = `author:${author.name}`;
|
|
28910
|
+
return option;
|
|
28911
|
+
})
|
|
28912
|
+
);
|
|
28913
|
+
}).catch((err) => {
|
|
28914
|
+
authorsLoadedFor = "";
|
|
28915
|
+
console.error("Failed to load history authors", err);
|
|
28916
|
+
});
|
|
28917
|
+
}
|
|
28284
28918
|
const docWithEvents = document;
|
|
28285
|
-
docWithEvents.addEventListener?.("keydown", (e2) => {
|
|
28286
|
-
if (isImeComposing(e2) || isEditableTarget(e2.target)) return;
|
|
28287
|
-
if (e2.key !== "ArrowDown" && e2.key !== "ArrowUp") return;
|
|
28288
|
-
if (!historyScopeFromRoute()) return;
|
|
28289
|
-
e2.preventDefault();
|
|
28290
|
-
void moveSelection(e2.key === "ArrowDown" ? 1 : -1);
|
|
28291
|
-
});
|
|
28292
28919
|
docWithEvents.addEventListener?.("input", (e2) => {
|
|
28293
28920
|
if (e2.target !== activeMount.filterInput) return;
|
|
28294
28921
|
handleFilterInput(e2);
|
|
@@ -28306,8 +28933,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28306
28933
|
syncRefreshButton(activeMount.refreshButton);
|
|
28307
28934
|
syncRefreshResult(activeMount.refreshResult);
|
|
28308
28935
|
syncFilterClearButton(activeMount.filterClearButton);
|
|
28936
|
+
syncFilterChrome();
|
|
28937
|
+
syncPanelTitle();
|
|
28309
28938
|
renderList();
|
|
28310
28939
|
},
|
|
28940
|
+
// Keyboard stepping through the commit list (keymap actions
|
|
28941
|
+
// history-next-commit / history-previous-commit).
|
|
28942
|
+
moveCommitSelection: (delta) => moveSelection(delta),
|
|
28311
28943
|
// Called from the SSE "update" listener when a history panel is on
|
|
28312
28944
|
// screen. Only updates existing local UI hints — no fetch, no list redraw,
|
|
28313
28945
|
// no generation bump, so it can't race with trackLoad/cancelInFlightRequests.
|
|
@@ -28563,8 +29195,28 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
28563
29195
|
{
|
|
28564
29196
|
selectors: [{ action: "goto-history" }],
|
|
28565
29197
|
description: {
|
|
28566
|
-
en: "Go to the history screen",
|
|
28567
|
-
ja: "
|
|
29198
|
+
en: "Go to the history screen (keeps the ref you are viewing)",
|
|
29199
|
+
ja: "履歴画面へ移動(見ている ref を引き継ぐ)"
|
|
29200
|
+
}
|
|
29201
|
+
},
|
|
29202
|
+
{
|
|
29203
|
+
selectors: [
|
|
29204
|
+
{ action: "history-next-commit", key: "arrowdown" },
|
|
29205
|
+
{ action: "history-previous-commit", key: "arrowup" }
|
|
29206
|
+
],
|
|
29207
|
+
description: {
|
|
29208
|
+
en: "Select the next / previous commit in the history list",
|
|
29209
|
+
ja: "履歴一覧で次 / 前のコミットを選ぶ"
|
|
29210
|
+
}
|
|
29211
|
+
},
|
|
29212
|
+
{
|
|
29213
|
+
selectors: [
|
|
29214
|
+
{ action: "history-next-commit", scope: "history" },
|
|
29215
|
+
{ action: "history-previous-commit", scope: "history" }
|
|
29216
|
+
],
|
|
29217
|
+
description: {
|
|
29218
|
+
en: "Same, while the commit list has focus",
|
|
29219
|
+
ja: "同上(コミット一覧にフォーカスがあるとき)"
|
|
28568
29220
|
}
|
|
28569
29221
|
},
|
|
28570
29222
|
{
|
|
@@ -29247,6 +29899,23 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
29247
29899
|
}
|
|
29248
29900
|
]
|
|
29249
29901
|
},
|
|
29902
|
+
{
|
|
29903
|
+
title: "Search and history",
|
|
29904
|
+
blocks: [
|
|
29905
|
+
{
|
|
29906
|
+
kind: "paragraph",
|
|
29907
|
+
text: "Ctrl+K opens the file palette and Ctrl+G the text palette; the search button at the left of the header icons does the same (Shift+click for text). The two share one window: switching keeps what you typed, and reopening restores the last query, selected so typing replaces it. With an empty query the file palette lists the files you opened most recently, and the result line says when the ranking was cut at 50. The text palette has regex (Alt+R), match-case (Alt+C) and whole-word (Alt+W) toggles, and path:<dir or glob> tokens in the query narrow the search; matching is case-insensitive on every engine unless match-case is on. Opening a hit marks the matched text on the target line, and in a large virtualized file it pre-fills the in-file find bar. Pin (or Ctrl+Enter) moves the query into the bottom panel's Search tab, where the grouped result list stays open while you browse files; the query is part of the URL (?results=) so a reload re-runs it."
|
|
29908
|
+
},
|
|
29909
|
+
{
|
|
29910
|
+
kind: "paragraph",
|
|
29911
|
+
text: "The sidebar filter takes plain text (anywhere in the path), /pattern/ for a regex, ~text for a fuzzy match and *.ts or src/** for a glob, and shows matching / all file counts while active."
|
|
29912
|
+
},
|
|
29913
|
+
{
|
|
29914
|
+
kind: "paragraph",
|
|
29915
|
+
text: `The History screen filter understands words (message text, "quoted" keeps spaces), sha prefixes, author:<name>, path:<part>, since:/after:<date>, until:/before:<date>, code:<text> (lines added or removed) and merges:no / merges:only; different kinds combine with AND, author: offers the repository's authors as suggestions, and the filter is part of the URL (?q=) so a reload or shared link keeps it. Rows show branch and tag labels and a merge marker. The selected commit can be copied (sha) or opened on GitHub, Shift+click a second commit to diff the whole range between them, and a merge commit lets you pick which parent to compare against. ↑ / ↓ step commits anywhere on the screen, j / k do when the commit list has focus, and g h opens the history of the ref you are looking at. A folder page has a History button that opens the log restricted to that folder; selected source lines offer a Line history action (git log -L) in the line-reference pill, file pages have older / newer revision buttons that step through the commits that touched that file, and the ref picker keeps the refs you picked last as quick chips.`
|
|
29916
|
+
}
|
|
29917
|
+
]
|
|
29918
|
+
},
|
|
29250
29919
|
{
|
|
29251
29920
|
title: "Scratch on pasted text",
|
|
29252
29921
|
blocks: [
|
|
@@ -30014,6 +30683,23 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
30014
30683
|
}
|
|
30015
30684
|
]
|
|
30016
30685
|
},
|
|
30686
|
+
{
|
|
30687
|
+
title: "検索と履歴",
|
|
30688
|
+
blocks: [
|
|
30689
|
+
{
|
|
30690
|
+
kind: "paragraph",
|
|
30691
|
+
text: "Ctrl+K でファイルパレット、Ctrl+G でコード検索パレットが開きます。ヘッダのアイコン列の左端にある検索ボタンでも同じです(Shift+クリックでコード検索)。2 つは 1 つのウィンドウを共有し、切り替えても入力中の検索語は残り、閉じて開き直すと前回の検索語が選択状態で戻ります。ファイルパレットは空のとき最近開いたファイルを並べ、結果が 50 件で切られたときはその旨を表示します。コード検索には正規表現(Alt+R)・大文字小文字の区別(Alt+C)・単語単位(Alt+W)の切り替えがあり、検索語の中の path:<ディレクトリ or glob> で対象を絞れます。大文字小文字は「区別する」を押さない限りどのエンジンでも区別しません。ヒットを開くと該当行の一致箇所が強調され、大きな仮想表示のファイルではファイル内検索バーに検索語が入ります。「固定」(または Ctrl+Enter)を押すと検索語が下パネルの「検索」タブに移り、ファイルを開いて回る間も結果一覧が残ります。検索語は URL(?results=)に載るのでリロードしても同じ検索が走ります。"
|
|
30692
|
+
},
|
|
30693
|
+
{
|
|
30694
|
+
kind: "paragraph",
|
|
30695
|
+
text: "サイドバーの絞り込みは文字列(パスの部分一致)、/pattern/(正規表現)、~text(あいまい一致)、*.ts や src/**(glob)を受け付け、絞り込み中は「一致 / 全体」の件数を表示します。"
|
|
30696
|
+
},
|
|
30697
|
+
{
|
|
30698
|
+
kind: "paragraph",
|
|
30699
|
+
text: '履歴画面の絞り込みは、語(メッセージ本文。"引用" で空白を含む句)、sha の前方一致、author:<名前>、path:<一部>、since:/after:<日付>、until:/before:<日付>、code:<文字列>(追加・削除された行)、merges:no / merges:only を解釈し、種類の違う条件は AND で組み合わさります。author: にはリポジトリの著者名が候補として出て、絞り込みは URL(?q=)に載るのでリロードや共有でも残ります。各行にはブランチ / タグのラベルとマージ印が付きます。選択したコミットは sha をコピーしたり GitHub で開いたりでき、別のコミットを Shift+クリックするとその区間全体の差分、マージコミットでは比較する親を選べます。↑ / ↓ は画面のどこでも、j / k はコミット一覧にフォーカスがあるときにコミットを送り、g h は見ている ref の履歴を開きます。フォルダページの「履歴」ボタンでそのフォルダに絞った履歴が開きます。ソースの行を選択すると行参照ピルに「この行の履歴」(git log -L)が出て、ファイルページには前後のリビジョンへ移るボタン、ref ピッカーには最近使った ref のチップが並びます。'
|
|
30700
|
+
}
|
|
30701
|
+
]
|
|
30702
|
+
},
|
|
30017
30703
|
{
|
|
30018
30704
|
title: "貼り付けたテキストを扱う",
|
|
30019
30705
|
blocks: [
|
|
@@ -33373,7 +34059,12 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33373
34059
|
githubCopy.type = "button";
|
|
33374
34060
|
githubCopy.innerHTML = `<span class="lrp-github-copy-icon">${iconSvg("octicon-copy", COPY_16_PATHS)}</span><span class="lrp-github-copy-label"></span>`;
|
|
33375
34061
|
githubActions.append(githubOpen, githubCopy);
|
|
33376
|
-
|
|
34062
|
+
const historyButton = document.createElement("button");
|
|
34063
|
+
historyButton.id = "line-ref-pill-history";
|
|
34064
|
+
historyButton.type = "button";
|
|
34065
|
+
historyButton.hidden = !deps.openLineHistory;
|
|
34066
|
+
historyButton.innerHTML = iconSvg("octicon-git-branch", GIT_BRANCH_16_PATH) + '<span class="lrp-history-label"></span>';
|
|
34067
|
+
pill.append(copyButton, githubActions, historyButton, closeButton);
|
|
33377
34068
|
document.body.appendChild(pill);
|
|
33378
34069
|
let refText = "";
|
|
33379
34070
|
let currentPath = "";
|
|
@@ -33382,6 +34073,14 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33382
34073
|
let githubUrl = "";
|
|
33383
34074
|
let feedbackTimer = null;
|
|
33384
34075
|
let githubFeedbackTimer = null;
|
|
34076
|
+
function renderHistoryAction() {
|
|
34077
|
+
if (!deps.openLineHistory) return;
|
|
34078
|
+
const title = deps.lineHistoryTitle?.() ?? "Line history";
|
|
34079
|
+
historyButton.title = title;
|
|
34080
|
+
historyButton.setAttribute("aria-label", title);
|
|
34081
|
+
const label = historyButton.querySelector(".lrp-history-label");
|
|
34082
|
+
if (label) label.textContent = title;
|
|
34083
|
+
}
|
|
33385
34084
|
function renderGithubActions() {
|
|
33386
34085
|
const openTitle = deps.githubOpenTitle();
|
|
33387
34086
|
const copyTitle = deps.githubCopyTitle();
|
|
@@ -33473,6 +34172,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33473
34172
|
if (icon) icon.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
33474
34173
|
}, 1200);
|
|
33475
34174
|
});
|
|
34175
|
+
historyButton.addEventListener("click", () => {
|
|
34176
|
+
if (!currentPath || !deps.openLineHistory) return;
|
|
34177
|
+
deps.openLineHistory(currentPath, currentStart, currentEnd);
|
|
34178
|
+
});
|
|
33476
34179
|
closeButton.addEventListener("click", () => {
|
|
33477
34180
|
deps.onClose();
|
|
33478
34181
|
});
|
|
@@ -33487,6 +34190,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33487
34190
|
currentEnd = Math.max(1, Math.floor(Math.max(start, end)));
|
|
33488
34191
|
githubUrl = deps.githubUrlForSelection(currentPath, currentStart, currentEnd) || "";
|
|
33489
34192
|
renderGithubActions();
|
|
34193
|
+
renderHistoryAction();
|
|
33490
34194
|
if (feedbackTimer) {
|
|
33491
34195
|
clearTimeout(feedbackTimer);
|
|
33492
34196
|
feedbackTimer = null;
|
|
@@ -33594,6 +34298,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33594
34298
|
}
|
|
33595
34299
|
|
|
33596
34300
|
// web-src/views/ref-picker.ts
|
|
34301
|
+
var QUICK_REF_VALUES = /* @__PURE__ */ new Set(["worktree", "HEAD", "--staged"]);
|
|
33597
34302
|
function createRefPicker(deps) {
|
|
33598
34303
|
function wireRefSelectorInput(input2, onPick) {
|
|
33599
34304
|
const wrap = input2.closest("[data-ref-selector]");
|
|
@@ -33613,6 +34318,37 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33613
34318
|
});
|
|
33614
34319
|
if (onPick)
|
|
33615
34320
|
input2.addEventListener("change", () => onPick(input2.value || "worktree"));
|
|
34321
|
+
input2.addEventListener("change", () => rememberRef(input2.value));
|
|
34322
|
+
}
|
|
34323
|
+
function rememberRef(value) {
|
|
34324
|
+
const ref = (value || "").trim();
|
|
34325
|
+
if (!ref || QUICK_REF_VALUES.has(ref)) return;
|
|
34326
|
+
deps.rememberRecentRef?.(ref);
|
|
34327
|
+
}
|
|
34328
|
+
function renderRecentChips(current) {
|
|
34329
|
+
let row = popover.querySelector(".rp-recent");
|
|
34330
|
+
const recent = (deps.getRecentRefs?.() ?? []).filter((ref) => ref && !QUICK_REF_VALUES.has(ref)).reverse();
|
|
34331
|
+
if (!row) {
|
|
34332
|
+
row = document.createElement("div");
|
|
34333
|
+
row.className = "rp-recent";
|
|
34334
|
+
const quick = popover.querySelector(".rp-quick");
|
|
34335
|
+
if (quick) quick.after(row);
|
|
34336
|
+
else popover.prepend(row);
|
|
34337
|
+
}
|
|
34338
|
+
row.replaceChildren();
|
|
34339
|
+
row.hidden = recent.length === 0;
|
|
34340
|
+
const title = deps.recentRefTitle?.() ?? "";
|
|
34341
|
+
for (const ref of recent) {
|
|
34342
|
+
const chip = document.createElement("button");
|
|
34343
|
+
chip.type = "button";
|
|
34344
|
+
chip.className = "rp-chip rp-chip-recent";
|
|
34345
|
+
chip.dataset.val = ref;
|
|
34346
|
+
chip.textContent = ref;
|
|
34347
|
+
if (title) chip.title = title;
|
|
34348
|
+
chip.classList.toggle("current", ref === current);
|
|
34349
|
+
chip.addEventListener("click", () => handlePicked(ref));
|
|
34350
|
+
row.appendChild(chip);
|
|
34351
|
+
}
|
|
33616
34352
|
}
|
|
33617
34353
|
const REFS = {
|
|
33618
34354
|
branches: [],
|
|
@@ -33837,6 +34573,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
33837
34573
|
popover.querySelectorAll(".rp-chip").forEach((c2) => {
|
|
33838
34574
|
c2.classList.toggle("current", c2.dataset.val === cur);
|
|
33839
34575
|
});
|
|
34576
|
+
renderRecentChips(cur);
|
|
33840
34577
|
popover.hidden = false;
|
|
33841
34578
|
const r2 = input2.getBoundingClientRect();
|
|
33842
34579
|
const popWidth = Math.min(560, Math.floor(window.innerWidth * 0.9));
|
|
@@ -34720,6 +35457,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
34720
35457
|
input2.title = invalid ? filter.error || "invalid regular expression" : "";
|
|
34721
35458
|
const filterActive = filter.kind !== "empty" && !invalid;
|
|
34722
35459
|
const matches2 = invalid ? () => true : filter.match;
|
|
35460
|
+
let totalFiles = 0;
|
|
35461
|
+
let visibleFiles = 0;
|
|
34723
35462
|
const walk = (node, depth) => {
|
|
34724
35463
|
let subtreeVisible = false;
|
|
34725
35464
|
const rows = [];
|
|
@@ -34744,7 +35483,9 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
34744
35483
|
} else {
|
|
34745
35484
|
const testHidden = STATE.hideTests && !isRepositorySidebarMode() && isTestPath(item.file.path || "");
|
|
34746
35485
|
const visible = !testHidden && matches2(item.file.path || "");
|
|
35486
|
+
if (!testHidden) totalFiles++;
|
|
34747
35487
|
if (visible) {
|
|
35488
|
+
visibleFiles++;
|
|
34748
35489
|
rows.push({
|
|
34749
35490
|
kind: "file",
|
|
34750
35491
|
path: item.file.path,
|
|
@@ -34759,6 +35500,31 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
34759
35500
|
return { visible: subtreeVisible, rows };
|
|
34760
35501
|
};
|
|
34761
35502
|
SIDEBAR_VISIBLE_ROWS = walk(SIDEBAR_TREE_ROOT, 0).rows;
|
|
35503
|
+
syncSidebarFilterCount(filterActive, visibleFiles, totalFiles);
|
|
35504
|
+
}
|
|
35505
|
+
let SIDEBAR_TOTALS_BASE = "";
|
|
35506
|
+
let SIDEBAR_TOTALS_FILTER_TEXT = "";
|
|
35507
|
+
function setSidebarTotals(text3) {
|
|
35508
|
+
SIDEBAR_TOTALS_BASE = text3;
|
|
35509
|
+
const el2 = $("#totals");
|
|
35510
|
+
if (el2.textContent === SIDEBAR_TOTALS_FILTER_TEXT) el2.textContent = text3;
|
|
35511
|
+
if (!SIDEBAR_TOTALS_FILTER_TEXT) el2.textContent = text3;
|
|
35512
|
+
}
|
|
35513
|
+
function syncSidebarFilterCount(active, visible, total) {
|
|
35514
|
+
const el2 = document.querySelector("#totals");
|
|
35515
|
+
if (!el2) return;
|
|
35516
|
+
if (!active) {
|
|
35517
|
+
if (SIDEBAR_TOTALS_FILTER_TEXT) {
|
|
35518
|
+
if (el2.textContent === SIDEBAR_TOTALS_FILTER_TEXT)
|
|
35519
|
+
el2.textContent = SIDEBAR_TOTALS_BASE;
|
|
35520
|
+
el2.removeAttribute("title");
|
|
35521
|
+
SIDEBAR_TOTALS_FILTER_TEXT = "";
|
|
35522
|
+
}
|
|
35523
|
+
return;
|
|
35524
|
+
}
|
|
35525
|
+
SIDEBAR_TOTALS_FILTER_TEXT = `${visible} / ${total}`;
|
|
35526
|
+
el2.textContent = SIDEBAR_TOTALS_FILTER_TEXT;
|
|
35527
|
+
el2.title = deps.filterCountTitle(visible, total);
|
|
34762
35528
|
}
|
|
34763
35529
|
function sidebarVirtualRange() {
|
|
34764
35530
|
const sidebar = document.querySelector("#sidebar");
|
|
@@ -35028,7 +35794,9 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
35028
35794
|
} else {
|
|
35029
35795
|
renderFlat(files, ul, onFileClick);
|
|
35030
35796
|
}
|
|
35031
|
-
|
|
35797
|
+
setSidebarTotals(
|
|
35798
|
+
!repoSidebar && files.length ? `${files.length} file${files.length === 1 ? "" : "s"}` : ""
|
|
35799
|
+
);
|
|
35032
35800
|
const effectiveView = treeMode ? "tree" : STATE.sbView;
|
|
35033
35801
|
$$(".sb-view-seg button").forEach((b2) => {
|
|
35034
35802
|
b2.classList.toggle("active", b2.dataset.view === effectiveView);
|
|
@@ -35143,10 +35911,16 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
35143
35911
|
input2.title = invalid ? filter.error || "invalid regular expression" : "";
|
|
35144
35912
|
const matches2 = invalid ? () => true : filter.match;
|
|
35145
35913
|
const filterActive = filter.kind !== "empty" && !invalid;
|
|
35914
|
+
let totalFiles = 0;
|
|
35915
|
+
let visibleFiles = 0;
|
|
35146
35916
|
$$("#filelist li[data-path]").forEach((li) => {
|
|
35147
35917
|
const match2 = matches2(li.dataset.path || "");
|
|
35148
35918
|
li.classList.toggle("hidden", !match2);
|
|
35919
|
+
if (li.classList.contains("hidden-by-tests")) return;
|
|
35920
|
+
totalFiles++;
|
|
35921
|
+
if (match2) visibleFiles++;
|
|
35149
35922
|
});
|
|
35923
|
+
syncSidebarFilterCount(filterActive, visibleFiles, totalFiles);
|
|
35150
35924
|
if (!isRepositorySidebarMode()) {
|
|
35151
35925
|
document.querySelectorAll(".gdp-file-shell").forEach((card) => {
|
|
35152
35926
|
const match2 = matches2(card.dataset.path || "");
|
|
@@ -35652,6 +36426,9 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
35652
36426
|
repositoryWebTarget,
|
|
35653
36427
|
openGithubLabel,
|
|
35654
36428
|
openRepositoryWebLabel,
|
|
36429
|
+
folderHistoryLabel,
|
|
36430
|
+
folderHistoryTitle,
|
|
36431
|
+
openFolderHistory,
|
|
35655
36432
|
fileBadge
|
|
35656
36433
|
} = deps;
|
|
35657
36434
|
let REPO_SORT = {
|
|
@@ -36068,6 +36845,15 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36068
36845
|
meta.ref
|
|
36069
36846
|
);
|
|
36070
36847
|
if (repositoryWebLink) toolbar.appendChild(repositoryWebLink);
|
|
36848
|
+
const historyButton = document.createElement("button");
|
|
36849
|
+
historyButton.type = "button";
|
|
36850
|
+
historyButton.className = "gdp-btn gdp-btn-sm gdp-repo-history-btn";
|
|
36851
|
+
historyButton.textContent = folderHistoryLabel();
|
|
36852
|
+
historyButton.title = folderHistoryTitle();
|
|
36853
|
+
historyButton.addEventListener("click", () => {
|
|
36854
|
+
openFolderHistory(meta.ref, meta.path || "");
|
|
36855
|
+
});
|
|
36856
|
+
toolbar.appendChild(historyButton);
|
|
36071
36857
|
if (canTrashWorktreeRef(meta.ref)) {
|
|
36072
36858
|
toolbar.appendChild(
|
|
36073
36859
|
createNewFolderButton(meta.path || "", () => loadRepo())
|
|
@@ -36633,294 +37419,12 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36633
37419
|
};
|
|
36634
37420
|
}
|
|
36635
37421
|
|
|
36636
|
-
// web-src/core/fuzzy-search.ts
|
|
36637
|
-
function basenameStart(path) {
|
|
36638
|
-
const slash = path.lastIndexOf("/");
|
|
36639
|
-
return slash < 0 ? 0 : slash + 1;
|
|
36640
|
-
}
|
|
36641
|
-
function isBoundary(path, index) {
|
|
36642
|
-
if (index <= 0) return true;
|
|
36643
|
-
const prev = path[index - 1];
|
|
36644
|
-
return prev === "/" || prev === "-" || prev === "_" || prev === "." || prev === " ";
|
|
36645
|
-
}
|
|
36646
|
-
function toRanges(indices) {
|
|
36647
|
-
const ranges = [];
|
|
36648
|
-
for (const index of indices) {
|
|
36649
|
-
const last = ranges[ranges.length - 1];
|
|
36650
|
-
if (last && last.end === index) {
|
|
36651
|
-
last.end = index + 1;
|
|
36652
|
-
} else {
|
|
36653
|
-
ranges.push({ start: index, end: index + 1 });
|
|
36654
|
-
}
|
|
36655
|
-
}
|
|
36656
|
-
return ranges;
|
|
36657
|
-
}
|
|
36658
|
-
function basenameMatchTier(loweredQuery, loweredBasename) {
|
|
36659
|
-
if (loweredBasename === loweredQuery) return 4;
|
|
36660
|
-
if (loweredBasename.startsWith(`${loweredQuery}.`)) return 3;
|
|
36661
|
-
if (loweredBasename.startsWith(loweredQuery)) return 2;
|
|
36662
|
-
if (loweredBasename.includes(loweredQuery)) return 1;
|
|
36663
|
-
return 0;
|
|
36664
|
-
}
|
|
36665
|
-
function pathMatchTier(loweredQuery, loweredPath, loweredBasename) {
|
|
36666
|
-
if (loweredQuery.includes("/") && (loweredPath === loweredQuery || loweredPath.endsWith(`/${loweredQuery}`)))
|
|
36667
|
-
return 4;
|
|
36668
|
-
return basenameMatchTier(loweredQuery, loweredBasename);
|
|
36669
|
-
}
|
|
36670
|
-
function contiguousPathRange(loweredQuery, loweredPath, baseStart) {
|
|
36671
|
-
const loweredBasename = loweredPath.slice(baseStart);
|
|
36672
|
-
const basenameMatchStart = loweredBasename.indexOf(loweredQuery);
|
|
36673
|
-
if (basenameMatchStart >= 0) {
|
|
36674
|
-
const start = baseStart + basenameMatchStart;
|
|
36675
|
-
return { start, end: start + loweredQuery.length };
|
|
36676
|
-
}
|
|
36677
|
-
if (loweredQuery.includes("/")) {
|
|
36678
|
-
const pathMatchStart = loweredPath.endsWith(`/${loweredQuery}`) ? loweredPath.length - loweredQuery.length : loweredPath === loweredQuery ? 0 : -1;
|
|
36679
|
-
if (pathMatchStart >= 0)
|
|
36680
|
-
return {
|
|
36681
|
-
start: pathMatchStart,
|
|
36682
|
-
end: pathMatchStart + loweredQuery.length
|
|
36683
|
-
};
|
|
36684
|
-
}
|
|
36685
|
-
return null;
|
|
36686
|
-
}
|
|
36687
|
-
function computeFuzzyMatch(query, path) {
|
|
36688
|
-
const q = query.trim().toLowerCase();
|
|
36689
|
-
if (!q) return { score: 0, ranges: [], tier: 0 };
|
|
36690
|
-
const lowerPath = path.toLowerCase();
|
|
36691
|
-
const baseStart = basenameStart(path);
|
|
36692
|
-
const indices = [];
|
|
36693
|
-
let from = 0;
|
|
36694
|
-
let score = 0;
|
|
36695
|
-
for (const ch of q) {
|
|
36696
|
-
const index = lowerPath.indexOf(ch, from);
|
|
36697
|
-
if (index < 0) return null;
|
|
36698
|
-
indices.push(index);
|
|
36699
|
-
score += 10;
|
|
36700
|
-
if (index >= baseStart) score += 8;
|
|
36701
|
-
if (isBoundary(path, index)) score += 6;
|
|
36702
|
-
const prev = indices[indices.length - 2];
|
|
36703
|
-
if (prev != null && prev + 1 === index) score += 12;
|
|
36704
|
-
from = index + 1;
|
|
36705
|
-
}
|
|
36706
|
-
const first = indices[0];
|
|
36707
|
-
score -= Math.min(first, 40);
|
|
36708
|
-
if (indices[0] >= baseStart) score += 20;
|
|
36709
|
-
const basename = lowerPath.slice(baseStart);
|
|
36710
|
-
const tier = pathMatchTier(q, lowerPath, basename);
|
|
36711
|
-
const contiguousRange = contiguousPathRange(q, lowerPath, baseStart);
|
|
36712
|
-
return {
|
|
36713
|
-
score,
|
|
36714
|
-
ranges: contiguousRange ? [contiguousRange] : toRanges(indices),
|
|
36715
|
-
tier
|
|
36716
|
-
};
|
|
36717
|
-
}
|
|
36718
|
-
function fuzzyMatchPath(query, path) {
|
|
36719
|
-
const match2 = computeFuzzyMatch(query, path);
|
|
36720
|
-
return match2 ? { score: match2.score, ranges: match2.ranges } : null;
|
|
36721
|
-
}
|
|
36722
|
-
function rankFuzzyPaths(query, items, limit) {
|
|
36723
|
-
const bounded = Number.isInteger(limit) && limit !== void 0 && limit > 0 ? Math.floor(limit) : 0;
|
|
36724
|
-
const compare = (a2, b2) => b2.tier - a2.tier || b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
36725
|
-
if (!bounded) {
|
|
36726
|
-
return items.map((item) => {
|
|
36727
|
-
const match2 = computeFuzzyMatch(query, item.path);
|
|
36728
|
-
return match2 ? { item, score: match2.score, ranges: match2.ranges, tier: match2.tier } : null;
|
|
36729
|
-
}).filter(
|
|
36730
|
-
(item) => item !== null
|
|
36731
|
-
).sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
36732
|
-
}
|
|
36733
|
-
const top = [];
|
|
36734
|
-
for (const item of items) {
|
|
36735
|
-
const match2 = computeFuzzyMatch(query, item.path);
|
|
36736
|
-
if (!match2) continue;
|
|
36737
|
-
const ranked = {
|
|
36738
|
-
item,
|
|
36739
|
-
score: match2.score,
|
|
36740
|
-
ranges: match2.ranges,
|
|
36741
|
-
tier: match2.tier
|
|
36742
|
-
};
|
|
36743
|
-
pushBoundedTop(top, ranked, bounded, compare);
|
|
36744
|
-
}
|
|
36745
|
-
return top.sort(compare).map(({ item, score, ranges }) => ({ item, score, ranges }));
|
|
36746
|
-
}
|
|
36747
|
-
function pushBoundedTop(heap, item, limit, compareBestFirst) {
|
|
36748
|
-
const isWorse = (a2, b2) => compareBestFirst(a2, b2) > 0;
|
|
36749
|
-
const siftUp = (index) => {
|
|
36750
|
-
while (index > 0) {
|
|
36751
|
-
const parent = Math.floor((index - 1) / 2);
|
|
36752
|
-
if (!isWorse(heap[index], heap[parent])) break;
|
|
36753
|
-
[heap[index], heap[parent]] = [heap[parent], heap[index]];
|
|
36754
|
-
index = parent;
|
|
36755
|
-
}
|
|
36756
|
-
};
|
|
36757
|
-
const siftDown = (index) => {
|
|
36758
|
-
while (true) {
|
|
36759
|
-
const left = index * 2 + 1;
|
|
36760
|
-
const right = left + 1;
|
|
36761
|
-
let worst = index;
|
|
36762
|
-
if (left < heap.length && isWorse(heap[left], heap[worst])) worst = left;
|
|
36763
|
-
if (right < heap.length && isWorse(heap[right], heap[worst]))
|
|
36764
|
-
worst = right;
|
|
36765
|
-
if (worst === index) break;
|
|
36766
|
-
[heap[index], heap[worst]] = [heap[worst], heap[index]];
|
|
36767
|
-
index = worst;
|
|
36768
|
-
}
|
|
36769
|
-
};
|
|
36770
|
-
if (heap.length < limit) {
|
|
36771
|
-
heap.push(item);
|
|
36772
|
-
siftUp(heap.length - 1);
|
|
36773
|
-
return;
|
|
36774
|
-
}
|
|
36775
|
-
if (compareBestFirst(item, heap[0]) >= 0) return;
|
|
36776
|
-
heap[0] = item;
|
|
36777
|
-
siftDown(0);
|
|
36778
|
-
}
|
|
36779
|
-
function rankGlobPathMatches(query, items, limit) {
|
|
36780
|
-
const matchPath = createGlobPathMatcher(query);
|
|
36781
|
-
if (!matchPath) return [];
|
|
36782
|
-
const bounded = Number.isInteger(limit) && limit !== void 0 && limit > 0 ? Math.floor(limit) : 0;
|
|
36783
|
-
const compare = (a2, b2) => b2.score - a2.score || a2.item.path.localeCompare(b2.item.path);
|
|
36784
|
-
if (!bounded) {
|
|
36785
|
-
return items.map((item) => {
|
|
36786
|
-
const match2 = matchPath(item.path);
|
|
36787
|
-
return match2 ? {
|
|
36788
|
-
item,
|
|
36789
|
-
score: match2.score,
|
|
36790
|
-
ranges: match2.ranges,
|
|
36791
|
-
mode: "glob"
|
|
36792
|
-
} : null;
|
|
36793
|
-
}).filter((item) => item !== null).sort(compare);
|
|
36794
|
-
}
|
|
36795
|
-
const top = [];
|
|
36796
|
-
for (const item of items) {
|
|
36797
|
-
const match2 = matchPath(item.path);
|
|
36798
|
-
if (!match2) continue;
|
|
36799
|
-
const ranked = {
|
|
36800
|
-
item,
|
|
36801
|
-
score: match2.score,
|
|
36802
|
-
ranges: match2.ranges,
|
|
36803
|
-
mode: "glob"
|
|
36804
|
-
};
|
|
36805
|
-
pushBoundedTop(top, ranked, bounded, compare);
|
|
36806
|
-
}
|
|
36807
|
-
return top.sort(compare);
|
|
36808
|
-
}
|
|
36809
|
-
function rankPathMatches(query, items, limit) {
|
|
36810
|
-
if (isGlobPathQuery(query)) {
|
|
36811
|
-
return rankGlobPathMatches(query, items, limit);
|
|
36812
|
-
}
|
|
36813
|
-
return rankFuzzyPaths(query, items, limit).map((item) => ({
|
|
36814
|
-
...item,
|
|
36815
|
-
mode: "fuzzy"
|
|
36816
|
-
}));
|
|
36817
|
-
}
|
|
36818
|
-
function isGlobPathQuery(query) {
|
|
36819
|
-
return /[*?]/.test(query.trim());
|
|
36820
|
-
}
|
|
36821
|
-
function escapeRegexChar(ch) {
|
|
36822
|
-
return /[\\^$+?.()|{}]/.test(ch) ? `\\${ch}` : ch;
|
|
36823
|
-
}
|
|
36824
|
-
function globToRegExp(query) {
|
|
36825
|
-
const pattern = query.trim();
|
|
36826
|
-
if (!pattern) return null;
|
|
36827
|
-
let source = "^";
|
|
36828
|
-
for (let i2 = 0; i2 < pattern.length; i2++) {
|
|
36829
|
-
const ch = pattern[i2];
|
|
36830
|
-
if (ch === "*") {
|
|
36831
|
-
if (pattern[i2 + 1] === "*") {
|
|
36832
|
-
source += ".*";
|
|
36833
|
-
i2++;
|
|
36834
|
-
} else {
|
|
36835
|
-
source += "[^/]*";
|
|
36836
|
-
}
|
|
36837
|
-
} else if (ch === "?") {
|
|
36838
|
-
source += "[^/]";
|
|
36839
|
-
} else if (ch === "[") {
|
|
36840
|
-
const close = pattern.indexOf("]", i2 + 1);
|
|
36841
|
-
if (close < 0) {
|
|
36842
|
-
source += "\\[";
|
|
36843
|
-
} else {
|
|
36844
|
-
const body = pattern.slice(i2 + 1, close).replace(/\\/g, "\\\\");
|
|
36845
|
-
source += `[${body}]`;
|
|
36846
|
-
i2 = close;
|
|
36847
|
-
}
|
|
36848
|
-
} else {
|
|
36849
|
-
source += escapeRegexChar(ch);
|
|
36850
|
-
}
|
|
36851
|
-
}
|
|
36852
|
-
source += "$";
|
|
36853
|
-
try {
|
|
36854
|
-
return new RegExp(source, "i");
|
|
36855
|
-
} catch {
|
|
36856
|
-
return null;
|
|
36857
|
-
}
|
|
36858
|
-
}
|
|
36859
|
-
function globMatchPath(query, path) {
|
|
36860
|
-
return createGlobPathMatcher(query)?.(path) ?? null;
|
|
36861
|
-
}
|
|
36862
|
-
function createGlobPathMatcher(query) {
|
|
36863
|
-
const regex = globToRegExp(query);
|
|
36864
|
-
if (!regex) return null;
|
|
36865
|
-
const literal = query.replace(/[*?[\]]+/g, " ").trim().split(/\s+/).filter(Boolean);
|
|
36866
|
-
const suffix = query.replace(/^\*+/, "").toLowerCase();
|
|
36867
|
-
return (path) => {
|
|
36868
|
-
const baseStart = basenameStart(path);
|
|
36869
|
-
const basename = path.slice(baseStart);
|
|
36870
|
-
if (!regex.test(path) && (query.includes("/") || !regex.test(basename)))
|
|
36871
|
-
return null;
|
|
36872
|
-
const ranges = [];
|
|
36873
|
-
const lowerPath = path.toLowerCase();
|
|
36874
|
-
for (const part of literal) {
|
|
36875
|
-
const start = lowerPath.indexOf(part.toLowerCase());
|
|
36876
|
-
if (start >= 0) ranges.push({ start, end: start + part.length });
|
|
36877
|
-
}
|
|
36878
|
-
ranges.sort((a2, b2) => a2.start - b2.start || a2.end - b2.end);
|
|
36879
|
-
const mergedRanges = [];
|
|
36880
|
-
for (const range of ranges) {
|
|
36881
|
-
const last = mergedRanges[mergedRanges.length - 1];
|
|
36882
|
-
if (last && last.end >= range.start) {
|
|
36883
|
-
last.end = Math.max(last.end, range.end);
|
|
36884
|
-
} else {
|
|
36885
|
-
mergedRanges.push({ ...range });
|
|
36886
|
-
}
|
|
36887
|
-
}
|
|
36888
|
-
const score = 1e3 - Math.min(path.length, 200) + (path.slice(baseStart).toLowerCase().endsWith(suffix) ? 50 : 0);
|
|
36889
|
-
return { score, ranges: mergedRanges };
|
|
36890
|
-
};
|
|
36891
|
-
}
|
|
36892
|
-
|
|
36893
|
-
// web-src/core/search-palette.ts
|
|
36894
|
-
var PALETTE_RESULT_LIMIT = 50;
|
|
36895
|
-
var GREP_SELECTION_HISTORY_LIMIT = 100;
|
|
36896
|
-
var MIN_GREP_PALETTE_WIDTH = 720;
|
|
36897
|
-
var MAX_GREP_PALETTE_WIDTH = 2400;
|
|
36898
|
-
var MIN_GREP_PALETTE_HEIGHT = 420;
|
|
36899
|
-
var MAX_GREP_PALETTE_HEIGHT = 1400;
|
|
36900
|
-
function limitPaletteResults(items) {
|
|
36901
|
-
return items.slice(0, PALETTE_RESULT_LIMIT);
|
|
36902
|
-
}
|
|
36903
|
-
function movePaletteSelection(index, count, direction) {
|
|
36904
|
-
if (count <= 0) return -1;
|
|
36905
|
-
if (index < 0) return direction > 0 ? 0 : count - 1;
|
|
36906
|
-
return Math.max(0, Math.min(count - 1, index + direction));
|
|
36907
|
-
}
|
|
36908
|
-
function rememberPaletteSelection(history2, path) {
|
|
36909
|
-
const next = history2.filter((entry) => entry !== path);
|
|
36910
|
-
next.push(path);
|
|
36911
|
-
return next.slice(-GREP_SELECTION_HISTORY_LIMIT);
|
|
36912
|
-
}
|
|
36913
|
-
function rankPaletteResultsByHistory(items, history2) {
|
|
36914
|
-
const priority = new Map(history2.map((path, index) => [path, index + 1]));
|
|
36915
|
-
return items.map((item, index) => ({ item, index })).sort(
|
|
36916
|
-
(a2, b2) => (priority.get(b2.item.path) ?? 0) - (priority.get(a2.item.path) ?? 0) || a2.index - b2.index
|
|
36917
|
-
).map(({ item }) => item);
|
|
36918
|
-
}
|
|
36919
|
-
|
|
36920
37422
|
// web-src/views/search-palette-i18n.ts
|
|
36921
37423
|
var EN2 = {
|
|
36922
37424
|
files: "Files",
|
|
36923
37425
|
grep: "Grep",
|
|
37426
|
+
switchToFiles: "Switch to file search (Ctrl+K)",
|
|
37427
|
+
switchToGrep: "Switch to text search (Ctrl+G)",
|
|
36924
37428
|
searchFiles: "Search files",
|
|
36925
37429
|
searchText: "Search text",
|
|
36926
37430
|
fileCodePreview: "File code preview",
|
|
@@ -36931,14 +37435,20 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36931
37435
|
fuzzyHint: "Fuzzy path search",
|
|
36932
37436
|
plain: "Plain",
|
|
36933
37437
|
regex: ".* Regex",
|
|
37438
|
+
matchCase: "Aa",
|
|
37439
|
+
matchCaseTitle: "Match case (Alt+C)",
|
|
37440
|
+
wholeWord: "Word",
|
|
37441
|
+
wholeWordTitle: "Match whole words only (Alt+W)",
|
|
36934
37442
|
excludeTests: "No test",
|
|
36935
37443
|
excludeTestsTitle: "Exclude test/spec files",
|
|
36936
37444
|
groupFiles: "Group files",
|
|
36937
37445
|
groupFilesTitle: "Group matching lines by file",
|
|
36938
|
-
|
|
37446
|
+
grepHint: "path:<dir or glob> narrows · Alt+R regex",
|
|
36939
37447
|
windowWidth: "window width",
|
|
36940
37448
|
windowHeight: "window height",
|
|
36941
37449
|
regexMode: "regex mode",
|
|
37450
|
+
caseSensitivity: "case sensitivity",
|
|
37451
|
+
wordMatching: "whole-word matching",
|
|
36942
37452
|
fileGrouping: "file grouping",
|
|
36943
37453
|
testExclusion: "test exclusion",
|
|
36944
37454
|
saveFailed: (label, error2) => `Failed to save ${label}: ${error2}`,
|
|
@@ -36952,22 +37462,42 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36952
37462
|
line: (line, column) => `Line ${line}:${column}`,
|
|
36953
37463
|
diffFiles: (count) => `${count} diff files`,
|
|
36954
37464
|
typeToSearchFiles: "Type to search repository files",
|
|
37465
|
+
recentFiles: (count) => `Recent files - ${count}`,
|
|
36955
37466
|
loadingFiles: "Loading files...",
|
|
36956
|
-
results: (count) => `${count} results
|
|
37467
|
+
results: (count, total, candidatesTruncated) => (total === void 0 ? `${count} results` : `${count} of ${total} results`) + (candidatesTruncated ? " · file list truncated" : ""),
|
|
36957
37468
|
noResults: "No results",
|
|
36958
37469
|
typeToGrep: "Type to grep",
|
|
36959
37470
|
invalidRegex: "Invalid regular expression",
|
|
36960
37471
|
searching: "Searching...",
|
|
36961
37472
|
repositoryChanged: "Repository changed; search again",
|
|
36962
|
-
grepSummary: ({
|
|
37473
|
+
grepSummary: ({
|
|
37474
|
+
engine,
|
|
37475
|
+
regex,
|
|
37476
|
+
caseSensitive,
|
|
37477
|
+
wholeWord,
|
|
37478
|
+
testsExcluded,
|
|
37479
|
+
truncated,
|
|
37480
|
+
count,
|
|
37481
|
+
paths
|
|
37482
|
+
}) => engine + (regex ? " regex" : " plain") + (caseSensitive ? " · match case" : "") + (wholeWord ? " · whole word" : "") + (testsExcluded ? " · tests excluded" : "") + (paths.length ? ` · in ${paths.join(" ")}` : "") + (truncated ? " truncated" : "") + ` - ${count} results`,
|
|
36963
37483
|
searchFailed: (error2) => `Search failed: ${error2}`,
|
|
36964
37484
|
savingSelection: "Saving selection...",
|
|
36965
37485
|
selectionSaveFailed: (error2) => `Failed to save selection: ${error2}`,
|
|
36966
|
-
unknownError: "unknown error"
|
|
37486
|
+
unknownError: "unknown error",
|
|
37487
|
+
pinResults: "Pin",
|
|
37488
|
+
pinResultsTitle: "Keep these results open in the bottom panel while you browse (Ctrl+Enter)",
|
|
37489
|
+
resultsTitle: "Search",
|
|
37490
|
+
resultsOpen: "Open the search results panel",
|
|
37491
|
+
resultsRun: "Search",
|
|
37492
|
+
resultsPlaceholder: "Search text (path:<dir or glob> narrows)",
|
|
37493
|
+
resultsIdle: "Type a search and press Enter",
|
|
37494
|
+
resultsScope: (ref) => `in ${ref}`
|
|
36967
37495
|
};
|
|
36968
37496
|
var JA2 = {
|
|
36969
37497
|
files: "ファイル",
|
|
36970
37498
|
grep: "GREP",
|
|
37499
|
+
switchToFiles: "ファイル名検索に切り替え (Ctrl+K)",
|
|
37500
|
+
switchToGrep: "コード検索に切り替え (Ctrl+G)",
|
|
36971
37501
|
searchFiles: "ファイルを検索",
|
|
36972
37502
|
searchText: "コードを検索",
|
|
36973
37503
|
fileCodePreview: "ファイルのコード表示",
|
|
@@ -36978,14 +37508,20 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36978
37508
|
fuzzyHint: "パスのあいまい検索",
|
|
36979
37509
|
plain: "通常",
|
|
36980
37510
|
regex: ".* 正規表現",
|
|
37511
|
+
matchCase: "Aa",
|
|
37512
|
+
matchCaseTitle: "大文字と小文字を区別 (Alt+C)",
|
|
37513
|
+
wholeWord: "単語",
|
|
37514
|
+
wholeWordTitle: "単語単位で一致 (Alt+W)",
|
|
36981
37515
|
excludeTests: "テスト除外",
|
|
36982
37516
|
excludeTestsTitle: "test/spec ファイルを除外",
|
|
36983
37517
|
groupFiles: "ファイル別",
|
|
36984
37518
|
groupFilesTitle: "一致した行をファイル別に表示",
|
|
36985
|
-
|
|
37519
|
+
grepHint: "path:<ディレクトリ or glob> で絞り込み · Alt+R 正規表現",
|
|
36986
37520
|
windowWidth: "ウィンドウの幅",
|
|
36987
37521
|
windowHeight: "ウィンドウの高さ",
|
|
36988
37522
|
regexMode: "正規表現モード",
|
|
37523
|
+
caseSensitivity: "大文字小文字の区別",
|
|
37524
|
+
wordMatching: "単語単位の一致",
|
|
36989
37525
|
fileGrouping: "ファイル別表示",
|
|
36990
37526
|
testExclusion: "テスト除外",
|
|
36991
37527
|
saveFailed: (label, error2) => `${label}を保存できませんでした: ${error2}`,
|
|
@@ -36999,23 +37535,92 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
36999
37535
|
line: (line, column) => `${line} 行:${column}`,
|
|
37000
37536
|
diffFiles: (count) => `差分ファイル ${count} 件`,
|
|
37001
37537
|
typeToSearchFiles: "リポジトリ内のファイル名を入力してください",
|
|
37538
|
+
recentFiles: (count) => `最近開いたファイル - ${count} 件`,
|
|
37002
37539
|
loadingFiles: "ファイルを読み込み中...",
|
|
37003
|
-
results: (count) => `${count}
|
|
37540
|
+
results: (count, total, candidatesTruncated) => (total === void 0 ? `${count} 件` : `${total} 件中 ${count} 件`) + (candidatesTruncated ? "・ファイル一覧は上限で打ち切り" : ""),
|
|
37004
37541
|
noResults: "該当なし",
|
|
37005
37542
|
typeToGrep: "検索するコードを入力してください",
|
|
37006
37543
|
invalidRegex: "正規表現が正しくありません",
|
|
37007
37544
|
searching: "検索中...",
|
|
37008
37545
|
repositoryChanged: "リポジトリが変更されました。もう一度検索してください",
|
|
37009
|
-
grepSummary: ({
|
|
37546
|
+
grepSummary: ({
|
|
37547
|
+
engine,
|
|
37548
|
+
regex,
|
|
37549
|
+
caseSensitive,
|
|
37550
|
+
wholeWord,
|
|
37551
|
+
testsExcluded,
|
|
37552
|
+
truncated,
|
|
37553
|
+
count,
|
|
37554
|
+
paths
|
|
37555
|
+
}) => engine + (regex ? "・正規表現" : "・通常") + (caseSensitive ? "・大文字小文字を区別" : "") + (wholeWord ? "・単語単位" : "") + (testsExcluded ? "・テスト除外" : "") + (paths.length ? `・${paths.join(" ")} 内` : "") + (truncated ? "・一部表示" : "") + ` - ${count} 件`,
|
|
37010
37556
|
searchFailed: (error2) => `検索に失敗しました: ${error2}`,
|
|
37011
37557
|
savingSelection: "選択履歴を保存中...",
|
|
37012
37558
|
selectionSaveFailed: (error2) => `選択履歴を保存できませんでした: ${error2}`,
|
|
37013
|
-
unknownError: "不明なエラー"
|
|
37559
|
+
unknownError: "不明なエラー",
|
|
37560
|
+
pinResults: "固定",
|
|
37561
|
+
pinResultsTitle: "この結果を下パネルに出したまま閲覧を続ける (Ctrl+Enter)",
|
|
37562
|
+
resultsTitle: "検索",
|
|
37563
|
+
resultsOpen: "検索結果パネルを開く",
|
|
37564
|
+
resultsRun: "検索",
|
|
37565
|
+
resultsPlaceholder: "検索するコード(path:<ディレクトリ or glob> で絞り込み)",
|
|
37566
|
+
resultsIdle: "検索語を入力して Enter",
|
|
37567
|
+
resultsScope: (ref) => `${ref} 内`
|
|
37014
37568
|
};
|
|
37015
37569
|
function searchPaletteText(language) {
|
|
37016
37570
|
return language === "ja" ? JA2 : EN2;
|
|
37017
37571
|
}
|
|
37018
37572
|
|
|
37573
|
+
// web-src/views/text-mark.ts
|
|
37574
|
+
function findTextRange(lineText, needle, options = {}) {
|
|
37575
|
+
if (!needle) return null;
|
|
37576
|
+
const haystack = options.caseSensitive ? lineText : lineText.toLowerCase();
|
|
37577
|
+
const target = options.caseSensitive ? needle : needle.toLowerCase();
|
|
37578
|
+
const expectedStart = Math.max(0, (options.nearColumn ?? 1) - 1);
|
|
37579
|
+
let bestStart = -1;
|
|
37580
|
+
let cursor = haystack.indexOf(target);
|
|
37581
|
+
while (cursor >= 0) {
|
|
37582
|
+
if (bestStart < 0 || Math.abs(cursor - expectedStart) < Math.abs(bestStart - expectedStart))
|
|
37583
|
+
bestStart = cursor;
|
|
37584
|
+
cursor = haystack.indexOf(target, cursor + Math.max(1, target.length));
|
|
37585
|
+
}
|
|
37586
|
+
return bestStart < 0 ? null : { start: bestStart, end: bestStart + needle.length };
|
|
37587
|
+
}
|
|
37588
|
+
function markTextRange(cell, start, end, className) {
|
|
37589
|
+
if (end <= start) return;
|
|
37590
|
+
const walker = document.createTreeWalker(cell, NodeFilter.SHOW_TEXT);
|
|
37591
|
+
const parts = [];
|
|
37592
|
+
let offset = 0;
|
|
37593
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
37594
|
+
const textNode = node;
|
|
37595
|
+
const nextOffset = offset + textNode.data.length;
|
|
37596
|
+
const partStart = Math.max(start, offset);
|
|
37597
|
+
const partEnd = Math.min(end, nextOffset);
|
|
37598
|
+
if (partStart < partEnd)
|
|
37599
|
+
parts.push({
|
|
37600
|
+
node: textNode,
|
|
37601
|
+
start: partStart - offset,
|
|
37602
|
+
end: partEnd - offset
|
|
37603
|
+
});
|
|
37604
|
+
offset = nextOffset;
|
|
37605
|
+
}
|
|
37606
|
+
for (const part of parts.reverse()) {
|
|
37607
|
+
const selected = part.node.splitText(part.start);
|
|
37608
|
+
selected.splitText(part.end - part.start);
|
|
37609
|
+
const mark = document.createElement("mark");
|
|
37610
|
+
mark.className = className;
|
|
37611
|
+
const parent = selected.parentNode;
|
|
37612
|
+
if (!parent) throw new Error("marked text is detached");
|
|
37613
|
+
parent.insertBefore(mark, selected);
|
|
37614
|
+
mark.appendChild(selected);
|
|
37615
|
+
}
|
|
37616
|
+
}
|
|
37617
|
+
function markNeedleInCell(cell, lineText, needle, className, options = {}) {
|
|
37618
|
+
const range = findTextRange(lineText, needle, options);
|
|
37619
|
+
if (!range) return false;
|
|
37620
|
+
markTextRange(cell, range.start, range.end, className);
|
|
37621
|
+
return true;
|
|
37622
|
+
}
|
|
37623
|
+
|
|
37019
37624
|
// web-src/views/search-palette-ui.ts
|
|
37020
37625
|
function createSearchPalette(deps) {
|
|
37021
37626
|
const {
|
|
@@ -37039,14 +37644,18 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37039
37644
|
getFileSelectionHistory,
|
|
37040
37645
|
getGrepSelectionHistory,
|
|
37041
37646
|
getGrepRegex,
|
|
37647
|
+
getGrepCaseSensitive,
|
|
37648
|
+
getGrepWholeWord,
|
|
37042
37649
|
getGrepHideTests,
|
|
37043
37650
|
getGrepGroupByFile,
|
|
37044
37651
|
getGrepPaletteWidth,
|
|
37045
37652
|
getGrepPaletteHeight,
|
|
37046
37653
|
persistGrepSettings,
|
|
37047
|
-
applyGrepHideTests
|
|
37654
|
+
applyGrepHideTests,
|
|
37655
|
+
openSearchResults
|
|
37048
37656
|
} = deps;
|
|
37049
37657
|
let PALETTE = null;
|
|
37658
|
+
const LAST_QUERY = { file: "", grep: "" };
|
|
37050
37659
|
let repoFileRequestGeneration = 0;
|
|
37051
37660
|
const GREP_CONTEXT_RADIUS = 5;
|
|
37052
37661
|
const FILE_PREVIEW_LINE_LIMIT = 200;
|
|
@@ -37083,6 +37692,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37083
37692
|
}
|
|
37084
37693
|
function closeSearchPalette() {
|
|
37085
37694
|
if (!PALETTE) return;
|
|
37695
|
+
LAST_QUERY[PALETTE.mode] = PALETTE.input.value;
|
|
37086
37696
|
const previousFocusScope = PALETTE.previousFocusScope;
|
|
37087
37697
|
PALETTE.controller?.abort();
|
|
37088
37698
|
PALETTE.previewController?.abort();
|
|
@@ -37094,6 +37704,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37094
37704
|
}
|
|
37095
37705
|
function createPalette(mode) {
|
|
37096
37706
|
const previousFocusScope = PALETTE ? PALETTE.previousFocusScope : getPanelFocusScope();
|
|
37707
|
+
const initialQuery = PALETTE ? PALETTE.input.value : LAST_QUERY[mode];
|
|
37097
37708
|
closeSearchPalette();
|
|
37098
37709
|
const root = document.createElement("div");
|
|
37099
37710
|
root.className = "gdp-palette-backdrop";
|
|
@@ -37112,7 +37723,19 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37112
37723
|
dialog.style.height = `${clampGrepPaletteHeight(savedHeight)}px`;
|
|
37113
37724
|
const label = document.createElement("div");
|
|
37114
37725
|
label.className = "gdp-palette-label";
|
|
37115
|
-
|
|
37726
|
+
for (const switchMode of ["file", "grep"]) {
|
|
37727
|
+
const button = document.createElement("button");
|
|
37728
|
+
button.type = "button";
|
|
37729
|
+
button.className = "gdp-palette-mode-button gdp-palette-mode-switch";
|
|
37730
|
+
button.setAttribute("aria-pressed", String(switchMode === mode));
|
|
37731
|
+
button.textContent = switchMode === "file" ? text3().files : text3().grep;
|
|
37732
|
+
button.title = switchMode === "file" ? text3().switchToFiles : text3().switchToGrep;
|
|
37733
|
+
button.addEventListener("mousedown", (event) => {
|
|
37734
|
+
event.preventDefault();
|
|
37735
|
+
if (switchMode !== mode) createPalette(switchMode);
|
|
37736
|
+
});
|
|
37737
|
+
label.appendChild(button);
|
|
37738
|
+
}
|
|
37116
37739
|
const input2 = document.createElement("input");
|
|
37117
37740
|
input2.className = "gdp-palette-input";
|
|
37118
37741
|
input2.type = "search";
|
|
@@ -37122,6 +37745,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37122
37745
|
input2.setAttribute("role", "combobox");
|
|
37123
37746
|
input2.setAttribute("aria-expanded", "true");
|
|
37124
37747
|
input2.setAttribute("aria-controls", "gdp-palette-list");
|
|
37748
|
+
input2.value = initialQuery;
|
|
37125
37749
|
const status = document.createElement("div");
|
|
37126
37750
|
status.className = "gdp-palette-status";
|
|
37127
37751
|
const controls = document.createElement("div");
|
|
@@ -37165,6 +37789,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37165
37789
|
preview,
|
|
37166
37790
|
mode,
|
|
37167
37791
|
grepRegex: getGrepRegex(),
|
|
37792
|
+
grepCaseSensitive: getGrepCaseSensitive(),
|
|
37793
|
+
grepWholeWord: getGrepWholeWord(),
|
|
37168
37794
|
grepHideTests: getGrepHideTests(),
|
|
37169
37795
|
grepGroupByFile: getGrepGroupByFile(),
|
|
37170
37796
|
grepPaletteWidth: clampGrepPaletteWidth(savedWidth ?? dialogRect.width),
|
|
@@ -37236,6 +37862,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37236
37862
|
input2.addEventListener("input", () => updatePaletteResults(state));
|
|
37237
37863
|
input2.addEventListener("keydown", (e2) => handlePaletteKeydown(e2, state));
|
|
37238
37864
|
input2.focus();
|
|
37865
|
+
if (input2.value) input2.select();
|
|
37239
37866
|
updatePaletteResults(state);
|
|
37240
37867
|
return state;
|
|
37241
37868
|
}
|
|
@@ -37283,6 +37910,38 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37283
37910
|
e2.preventDefault();
|
|
37284
37911
|
void updateGrepRegex(state, true);
|
|
37285
37912
|
});
|
|
37913
|
+
const matchCase = document.createElement("button");
|
|
37914
|
+
matchCase.type = "button";
|
|
37915
|
+
matchCase.className = "gdp-palette-mode-button";
|
|
37916
|
+
matchCase.setAttribute("aria-pressed", String(state.grepCaseSensitive));
|
|
37917
|
+
matchCase.textContent = text3().matchCase;
|
|
37918
|
+
matchCase.title = text3().matchCaseTitle;
|
|
37919
|
+
matchCase.disabled = state.settingsPending;
|
|
37920
|
+
matchCase.addEventListener("mousedown", (e2) => {
|
|
37921
|
+
e2.preventDefault();
|
|
37922
|
+
void updateGrepFlag(
|
|
37923
|
+
state,
|
|
37924
|
+
"grepCaseSensitive",
|
|
37925
|
+
!state.grepCaseSensitive,
|
|
37926
|
+
text3().caseSensitivity
|
|
37927
|
+
);
|
|
37928
|
+
});
|
|
37929
|
+
const wholeWord = document.createElement("button");
|
|
37930
|
+
wholeWord.type = "button";
|
|
37931
|
+
wholeWord.className = "gdp-palette-mode-button";
|
|
37932
|
+
wholeWord.setAttribute("aria-pressed", String(state.grepWholeWord));
|
|
37933
|
+
wholeWord.textContent = text3().wholeWord;
|
|
37934
|
+
wholeWord.title = text3().wholeWordTitle;
|
|
37935
|
+
wholeWord.disabled = state.settingsPending;
|
|
37936
|
+
wholeWord.addEventListener("mousedown", (e2) => {
|
|
37937
|
+
e2.preventDefault();
|
|
37938
|
+
void updateGrepFlag(
|
|
37939
|
+
state,
|
|
37940
|
+
"grepWholeWord",
|
|
37941
|
+
!state.grepWholeWord,
|
|
37942
|
+
text3().wordMatching
|
|
37943
|
+
);
|
|
37944
|
+
});
|
|
37286
37945
|
const excludeTests = createExcludeTestsButton(state);
|
|
37287
37946
|
const groupFiles = document.createElement("button");
|
|
37288
37947
|
groupFiles.type = "button";
|
|
@@ -37297,8 +37956,62 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37297
37956
|
});
|
|
37298
37957
|
const hint = document.createElement("span");
|
|
37299
37958
|
hint.className = "gdp-palette-mode-hint";
|
|
37300
|
-
hint.textContent = text3().
|
|
37301
|
-
state.controls.append(
|
|
37959
|
+
hint.textContent = text3().grepHint;
|
|
37960
|
+
state.controls.append(
|
|
37961
|
+
plain,
|
|
37962
|
+
regex,
|
|
37963
|
+
matchCase,
|
|
37964
|
+
wholeWord,
|
|
37965
|
+
excludeTests,
|
|
37966
|
+
groupFiles
|
|
37967
|
+
);
|
|
37968
|
+
if (openSearchResults) {
|
|
37969
|
+
const pin = document.createElement("button");
|
|
37970
|
+
pin.type = "button";
|
|
37971
|
+
pin.className = "gdp-palette-mode-button gdp-palette-pin";
|
|
37972
|
+
pin.textContent = text3().pinResults;
|
|
37973
|
+
pin.title = text3().pinResultsTitle;
|
|
37974
|
+
pin.addEventListener("mousedown", (e2) => {
|
|
37975
|
+
e2.preventDefault();
|
|
37976
|
+
pinResults(state);
|
|
37977
|
+
});
|
|
37978
|
+
state.controls.append(pin);
|
|
37979
|
+
}
|
|
37980
|
+
state.controls.append(hint);
|
|
37981
|
+
}
|
|
37982
|
+
function pinResults(state) {
|
|
37983
|
+
if (!openSearchResults) return;
|
|
37984
|
+
const query = state.input.value;
|
|
37985
|
+
closeSearchPalette();
|
|
37986
|
+
openSearchResults(query);
|
|
37987
|
+
}
|
|
37988
|
+
async function updateGrepFlag(state, flag, value, label) {
|
|
37989
|
+
if (state.settingsPending || value === state[flag]) return;
|
|
37990
|
+
const previous = state[flag];
|
|
37991
|
+
state[flag] = value;
|
|
37992
|
+
state.settingsPending = true;
|
|
37993
|
+
renderPaletteControls(state);
|
|
37994
|
+
try {
|
|
37995
|
+
await persistGrepSettings(
|
|
37996
|
+
flag === "grepCaseSensitive" ? { grepCaseSensitive: value } : { grepWholeWord: value }
|
|
37997
|
+
);
|
|
37998
|
+
if (PALETTE === state) updatePaletteResults(state);
|
|
37999
|
+
} catch (err) {
|
|
38000
|
+
console.error(`Failed to save grep ${label}`, err);
|
|
38001
|
+
state[flag] = previous;
|
|
38002
|
+
if (PALETTE === state) {
|
|
38003
|
+
state.status.textContent = text3().saveFailed(
|
|
38004
|
+
label,
|
|
38005
|
+
errorMessage2(err, text3().unknownError)
|
|
38006
|
+
);
|
|
38007
|
+
}
|
|
38008
|
+
} finally {
|
|
38009
|
+
state.settingsPending = false;
|
|
38010
|
+
if (PALETTE === state) {
|
|
38011
|
+
renderPaletteControls(state);
|
|
38012
|
+
state.input.focus();
|
|
38013
|
+
}
|
|
38014
|
+
}
|
|
37302
38015
|
}
|
|
37303
38016
|
function errorMessage2(err, fallback) {
|
|
37304
38017
|
return err instanceof Error && err.message ? err.message : fallback;
|
|
@@ -37423,51 +38136,16 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37423
38136
|
if (cursor < path.length)
|
|
37424
38137
|
parent.appendChild(document.createTextNode(path.slice(cursor)));
|
|
37425
38138
|
}
|
|
37426
|
-
function
|
|
37427
|
-
|
|
37428
|
-
if (!matchText) return null;
|
|
37429
|
-
const caseSensitive = item.regex || /[A-Z]/.test(item.query);
|
|
37430
|
-
const haystack = caseSensitive ? lineText : lineText.toLowerCase();
|
|
37431
|
-
const needle = caseSensitive ? matchText : matchText.toLowerCase();
|
|
37432
|
-
const expectedStart = Math.max(0, item.column - 1);
|
|
37433
|
-
let bestStart = -1;
|
|
37434
|
-
let cursor = haystack.indexOf(needle);
|
|
37435
|
-
while (cursor >= 0) {
|
|
37436
|
-
if (bestStart < 0 || Math.abs(cursor - expectedStart) < Math.abs(bestStart - expectedStart))
|
|
37437
|
-
bestStart = cursor;
|
|
37438
|
-
cursor = haystack.indexOf(needle, cursor + Math.max(1, needle.length));
|
|
37439
|
-
}
|
|
37440
|
-
return bestStart < 0 ? null : { start: bestStart, end: bestStart + matchText.length };
|
|
38139
|
+
function grepHighlightText(item) {
|
|
38140
|
+
return item.matchText || (item.regex ? "" : item.term);
|
|
37441
38141
|
}
|
|
37442
38142
|
function highlightGrepMatch(cell, lineText, item) {
|
|
37443
|
-
const
|
|
37444
|
-
if (!
|
|
37445
|
-
|
|
37446
|
-
|
|
37447
|
-
|
|
37448
|
-
|
|
37449
|
-
const textNode = node;
|
|
37450
|
-
const nextOffset = offset + textNode.data.length;
|
|
37451
|
-
const start = Math.max(match2.start, offset);
|
|
37452
|
-
const end = Math.min(match2.end, nextOffset);
|
|
37453
|
-
if (start < end)
|
|
37454
|
-
parts.push({
|
|
37455
|
-
node: textNode,
|
|
37456
|
-
start: start - offset,
|
|
37457
|
-
end: end - offset
|
|
37458
|
-
});
|
|
37459
|
-
offset = nextOffset;
|
|
37460
|
-
}
|
|
37461
|
-
for (const part of parts.reverse()) {
|
|
37462
|
-
const selected = part.node.splitText(part.start);
|
|
37463
|
-
selected.splitText(part.end - part.start);
|
|
37464
|
-
const mark = document.createElement("mark");
|
|
37465
|
-
mark.className = "gdp-grep-match";
|
|
37466
|
-
const parent = selected.parentNode;
|
|
37467
|
-
if (!parent) throw new Error("grep match text is detached");
|
|
37468
|
-
parent.insertBefore(mark, selected);
|
|
37469
|
-
mark.appendChild(selected);
|
|
37470
|
-
}
|
|
38143
|
+
const needle = grepHighlightText(item);
|
|
38144
|
+
if (!needle) return;
|
|
38145
|
+
markNeedleInCell(cell, lineText, needle, "gdp-grep-match", {
|
|
38146
|
+
caseSensitive: item.caseSensitive,
|
|
38147
|
+
nearColumn: item.column
|
|
38148
|
+
});
|
|
37471
38149
|
}
|
|
37472
38150
|
function palettePreviewTarget(item) {
|
|
37473
38151
|
return item.kind === "file" ? {
|
|
@@ -37769,27 +38447,73 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37769
38447
|
).sort(
|
|
37770
38448
|
(a2, b2) => b2.match.score - a2.match.score || a2.file.path.localeCompare(b2.file.path)
|
|
37771
38449
|
);
|
|
37772
|
-
return
|
|
37773
|
-
|
|
37774
|
-
|
|
37775
|
-
|
|
37776
|
-
|
|
37777
|
-
|
|
37778
|
-
|
|
37779
|
-
|
|
37780
|
-
|
|
37781
|
-
|
|
37782
|
-
|
|
37783
|
-
|
|
37784
|
-
|
|
37785
|
-
|
|
38450
|
+
return {
|
|
38451
|
+
total: candidates.length,
|
|
38452
|
+
items: limitPaletteResults(
|
|
38453
|
+
rankPaletteResultsByHistory(
|
|
38454
|
+
candidates.map((candidate) => ({
|
|
38455
|
+
kind: "file",
|
|
38456
|
+
path: candidate.file.path,
|
|
38457
|
+
old_path: candidate.file.old_path,
|
|
38458
|
+
displayPath: candidate.displayPath,
|
|
38459
|
+
ref: paletteRef("diff"),
|
|
38460
|
+
targetPath: fileSourceTarget(candidate.file).path,
|
|
38461
|
+
targetRef: fileSourceTarget(candidate.file).ref,
|
|
38462
|
+
source: "diff",
|
|
38463
|
+
ranges: candidate.match.ranges
|
|
38464
|
+
})),
|
|
38465
|
+
state.fileHistory
|
|
38466
|
+
)
|
|
37786
38467
|
)
|
|
38468
|
+
};
|
|
38469
|
+
}
|
|
38470
|
+
async function updateRecentFilePalette(state, source) {
|
|
38471
|
+
const recent = [...state.fileHistory].reverse();
|
|
38472
|
+
if (recent.length === 0) {
|
|
38473
|
+
state.items = [];
|
|
38474
|
+
state.selected = -1;
|
|
38475
|
+
state.status.textContent = text3().typeToSearchFiles;
|
|
38476
|
+
renderPalette(state);
|
|
38477
|
+
return;
|
|
38478
|
+
}
|
|
38479
|
+
state.status.textContent = text3().loadingFiles;
|
|
38480
|
+
const ref = paletteRef(source);
|
|
38481
|
+
const requestGeneration = ++repoFileRequestGeneration;
|
|
38482
|
+
let response;
|
|
38483
|
+
try {
|
|
38484
|
+
response = await repoPaletteFiles(ref);
|
|
38485
|
+
} catch (err) {
|
|
38486
|
+
if (requestGeneration !== repoFileRequestGeneration) return;
|
|
38487
|
+
throw err;
|
|
38488
|
+
}
|
|
38489
|
+
if (PALETTE !== state || state.input.value.trim() !== "" || requestGeneration !== repoFileRequestGeneration)
|
|
38490
|
+
return;
|
|
38491
|
+
REPO_FILE_CACHE.set(repoFileCacheKey(ref), response);
|
|
38492
|
+
const existing = new Set(response.files.map((file) => file.path));
|
|
38493
|
+
state.items = limitPaletteResults(
|
|
38494
|
+
recent.filter(
|
|
38495
|
+
(path) => existing.has(path) && (!state.grepHideTests || !isTestFilePath(path))
|
|
38496
|
+
).map((path) => ({
|
|
38497
|
+
kind: "file",
|
|
38498
|
+
path,
|
|
38499
|
+
displayPath: path,
|
|
38500
|
+
ref,
|
|
38501
|
+
source,
|
|
38502
|
+
ranges: []
|
|
38503
|
+
}))
|
|
37787
38504
|
);
|
|
38505
|
+
state.selected = state.items.length ? 0 : -1;
|
|
38506
|
+
state.status.textContent = state.items.length ? text3().recentFiles(state.items.length) : text3().typeToSearchFiles;
|
|
38507
|
+
renderPalette(state);
|
|
37788
38508
|
}
|
|
37789
38509
|
async function updateFilePalette(state, query) {
|
|
37790
38510
|
renderPaletteControls(state);
|
|
37791
38511
|
const source = paletteSource();
|
|
37792
38512
|
if (!query.trim()) {
|
|
38513
|
+
if (source === "repo") {
|
|
38514
|
+
await updateRecentFilePalette(state, source);
|
|
38515
|
+
return;
|
|
38516
|
+
}
|
|
37793
38517
|
const base2 = source === "diff" ? state.diffSnapshot.filter(
|
|
37794
38518
|
(file) => !state.grepHideTests || !isTestFilePath(file.path)
|
|
37795
38519
|
).map((file) => {
|
|
@@ -37814,8 +38538,12 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37814
38538
|
renderPalette(state);
|
|
37815
38539
|
return;
|
|
37816
38540
|
}
|
|
38541
|
+
let totalMatches = 0;
|
|
38542
|
+
let candidatesTruncated = false;
|
|
37817
38543
|
if (source === "diff") {
|
|
37818
|
-
|
|
38544
|
+
const ranked = diffFilePaletteItems(state, query);
|
|
38545
|
+
state.items = ranked.items;
|
|
38546
|
+
totalMatches = ranked.total;
|
|
37819
38547
|
} else {
|
|
37820
38548
|
state.status.textContent = text3().loadingFiles;
|
|
37821
38549
|
const ref = paletteRef(source);
|
|
@@ -37833,9 +38561,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37833
38561
|
const visibleFiles = response.files.filter(
|
|
37834
38562
|
(file) => !state.grepHideTests || !isTestFilePath(file.path)
|
|
37835
38563
|
);
|
|
38564
|
+
const stats = { total: 0 };
|
|
37836
38565
|
state.items = limitPaletteResults(
|
|
37837
38566
|
rankPaletteResultsByHistory(
|
|
37838
|
-
rankPathMatches(query, visibleFiles, PALETTE_RESULT_LIMIT).map(
|
|
38567
|
+
rankPathMatches(query, visibleFiles, PALETTE_RESULT_LIMIT, stats).map(
|
|
37839
38568
|
(match2) => ({
|
|
37840
38569
|
kind: "file",
|
|
37841
38570
|
path: match2.item.path,
|
|
@@ -37848,23 +38577,37 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37848
38577
|
state.fileHistory
|
|
37849
38578
|
)
|
|
37850
38579
|
);
|
|
38580
|
+
totalMatches = stats.total;
|
|
38581
|
+
candidatesTruncated = response.truncated;
|
|
37851
38582
|
}
|
|
37852
38583
|
state.selected = state.items.length ? 0 : -1;
|
|
37853
|
-
state.status.textContent = state.items.length ? text3().results(
|
|
38584
|
+
state.status.textContent = state.items.length ? text3().results(
|
|
38585
|
+
state.items.length,
|
|
38586
|
+
totalMatches > state.items.length ? totalMatches : void 0,
|
|
38587
|
+
candidatesTruncated
|
|
38588
|
+
) : text3().noResults;
|
|
37854
38589
|
renderPalette(state);
|
|
37855
38590
|
}
|
|
38591
|
+
function diffPathInScope(path, scopes) {
|
|
38592
|
+
if (scopes.length === 0) return true;
|
|
38593
|
+
return scopes.some(
|
|
38594
|
+
(scope) => isGlobPathQuery(scope) ? !!globMatchPath(scope, path) : path === scope || path.startsWith(`${scope.replace(/\/+$/, "")}/`)
|
|
38595
|
+
);
|
|
38596
|
+
}
|
|
37856
38597
|
function updateGrepPalette(state, query) {
|
|
37857
38598
|
renderPaletteControls(state);
|
|
37858
38599
|
state.controller?.abort();
|
|
37859
38600
|
if (state.debounce) window.clearTimeout(state.debounce);
|
|
37860
|
-
|
|
38601
|
+
const parsed = parseGrepQuery(query);
|
|
38602
|
+
const term = parsed.term;
|
|
38603
|
+
if (!term) {
|
|
37861
38604
|
state.items = [];
|
|
37862
38605
|
state.selected = -1;
|
|
37863
38606
|
state.status.textContent = text3().typeToGrep;
|
|
37864
38607
|
renderPalette(state);
|
|
37865
38608
|
return;
|
|
37866
38609
|
}
|
|
37867
|
-
if (state.grepRegex && !regexQueryIsValid(
|
|
38610
|
+
if (state.grepRegex && !regexQueryIsValid(term)) {
|
|
37868
38611
|
state.controller?.abort();
|
|
37869
38612
|
state.items = [];
|
|
37870
38613
|
state.selected = -1;
|
|
@@ -37880,16 +38623,30 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37880
38623
|
const source = paletteSource();
|
|
37881
38624
|
const ref = paletteRef(source);
|
|
37882
38625
|
const regex = state.grepRegex;
|
|
38626
|
+
const caseSensitive = state.grepCaseSensitive;
|
|
38627
|
+
const wholeWord = state.grepWholeWord;
|
|
37883
38628
|
const hideTests = state.grepHideTests;
|
|
37884
|
-
const params =
|
|
37885
|
-
|
|
37886
|
-
|
|
37887
|
-
|
|
37888
|
-
|
|
37889
|
-
|
|
38629
|
+
const params = buildGrepRequestParams({
|
|
38630
|
+
term,
|
|
38631
|
+
ref,
|
|
38632
|
+
regex,
|
|
38633
|
+
caseSensitive,
|
|
38634
|
+
wholeWord,
|
|
38635
|
+
hideTests,
|
|
38636
|
+
max: 200
|
|
38637
|
+
});
|
|
37890
38638
|
appendScopeParams(params);
|
|
37891
38639
|
if (source === "diff") {
|
|
37892
|
-
|
|
38640
|
+
const scoped = state.diffSnapshot.filter(
|
|
38641
|
+
(file) => diffPathInScope(file.path, parsed.paths)
|
|
38642
|
+
);
|
|
38643
|
+
if (scoped.length === 0) {
|
|
38644
|
+
state.status.textContent = text3().noResults;
|
|
38645
|
+
return;
|
|
38646
|
+
}
|
|
38647
|
+
for (const file of scoped) params.append("path", file.path);
|
|
38648
|
+
} else {
|
|
38649
|
+
for (const scope of parsed.paths) params.append("path", scope);
|
|
37893
38650
|
}
|
|
37894
38651
|
const controller = new AbortController();
|
|
37895
38652
|
state.controller = controller;
|
|
@@ -37904,7 +38661,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37904
38661
|
return r2.json();
|
|
37905
38662
|
})
|
|
37906
38663
|
).then((response) => {
|
|
37907
|
-
if (PALETTE !== state || controller.signal.aborted || state.input.value !== query || state.grepRegex !== regex || state.grepHideTests !== hideTests)
|
|
38664
|
+
if (PALETTE !== state || controller.signal.aborted || state.input.value !== query || state.grepRegex !== regex || state.grepCaseSensitive !== caseSensitive || state.grepWholeWord !== wholeWord || state.grepHideTests !== hideTests)
|
|
37908
38665
|
return;
|
|
37909
38666
|
if (responseGenerationIsStale(response.generation)) {
|
|
37910
38667
|
state.items = [];
|
|
@@ -37925,7 +38682,9 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37925
38682
|
preview: match2.preview,
|
|
37926
38683
|
matchText: match2.matchText,
|
|
37927
38684
|
query,
|
|
38685
|
+
term,
|
|
37928
38686
|
regex,
|
|
38687
|
+
caseSensitive,
|
|
37929
38688
|
ref,
|
|
37930
38689
|
source
|
|
37931
38690
|
}))
|
|
@@ -37934,9 +38693,12 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
37934
38693
|
state.status.textContent = text3().grepSummary({
|
|
37935
38694
|
engine: response.engine,
|
|
37936
38695
|
regex,
|
|
38696
|
+
caseSensitive,
|
|
38697
|
+
wholeWord,
|
|
37937
38698
|
testsExcluded: hideTests,
|
|
37938
38699
|
truncated: response.truncated,
|
|
37939
|
-
count: state.items.length
|
|
38700
|
+
count: state.items.length,
|
|
38701
|
+
paths: parsed.paths
|
|
37940
38702
|
});
|
|
37941
38703
|
renderPalette(state);
|
|
37942
38704
|
}).catch((err) => {
|
|
@@ -38027,12 +38789,14 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38027
38789
|
});
|
|
38028
38790
|
scrollToFile(item.path, item.line);
|
|
38029
38791
|
} else {
|
|
38792
|
+
const hl = grepHighlightText(item);
|
|
38030
38793
|
setRoute({
|
|
38031
38794
|
screen: "file",
|
|
38032
38795
|
path: item.path,
|
|
38033
38796
|
ref: item.ref,
|
|
38034
38797
|
view: "blob",
|
|
38035
38798
|
line: item.line,
|
|
38799
|
+
...hl ? { hl } : {},
|
|
38036
38800
|
range: currentRange()
|
|
38037
38801
|
});
|
|
38038
38802
|
void renderStandaloneSource({ path: item.path, ref: item.ref });
|
|
@@ -38048,6 +38812,10 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38048
38812
|
if (e2.key === "Enter") {
|
|
38049
38813
|
if (state.composing) return;
|
|
38050
38814
|
e2.preventDefault();
|
|
38815
|
+
if (state.mode === "grep" && (e2.ctrlKey || e2.metaKey) && openSearchResults) {
|
|
38816
|
+
pinResults(state);
|
|
38817
|
+
return;
|
|
38818
|
+
}
|
|
38051
38819
|
void selectPaletteItem(state);
|
|
38052
38820
|
return;
|
|
38053
38821
|
}
|
|
@@ -38056,6 +38824,26 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38056
38824
|
void updateGrepRegex(state, !state.grepRegex);
|
|
38057
38825
|
return;
|
|
38058
38826
|
}
|
|
38827
|
+
if (state.mode === "grep" && e2.altKey && e2.key.toLowerCase() === "c") {
|
|
38828
|
+
e2.preventDefault();
|
|
38829
|
+
void updateGrepFlag(
|
|
38830
|
+
state,
|
|
38831
|
+
"grepCaseSensitive",
|
|
38832
|
+
!state.grepCaseSensitive,
|
|
38833
|
+
text3().caseSensitivity
|
|
38834
|
+
);
|
|
38835
|
+
return;
|
|
38836
|
+
}
|
|
38837
|
+
if (state.mode === "grep" && e2.altKey && e2.key.toLowerCase() === "w") {
|
|
38838
|
+
e2.preventDefault();
|
|
38839
|
+
void updateGrepFlag(
|
|
38840
|
+
state,
|
|
38841
|
+
"grepWholeWord",
|
|
38842
|
+
!state.grepWholeWord,
|
|
38843
|
+
text3().wordMatching
|
|
38844
|
+
);
|
|
38845
|
+
return;
|
|
38846
|
+
}
|
|
38059
38847
|
const direction = e2.key === "ArrowDown" || e2.ctrlKey && e2.key.toLowerCase() === "n" ? 1 : e2.key === "ArrowUp" || e2.ctrlKey && e2.key.toLowerCase() === "p" ? -1 : 0;
|
|
38060
38848
|
if (direction) {
|
|
38061
38849
|
e2.preventDefault();
|
|
@@ -38088,6 +38876,317 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38088
38876
|
};
|
|
38089
38877
|
}
|
|
38090
38878
|
|
|
38879
|
+
// web-src/views/search-results-view.ts
|
|
38880
|
+
var RESULTS_MAX = 500;
|
|
38881
|
+
function createSearchResultsView(deps) {
|
|
38882
|
+
let mounted = false;
|
|
38883
|
+
let input2 = null;
|
|
38884
|
+
let runButton = null;
|
|
38885
|
+
let controls = null;
|
|
38886
|
+
let status = null;
|
|
38887
|
+
let list2 = null;
|
|
38888
|
+
let query = "";
|
|
38889
|
+
let controller = null;
|
|
38890
|
+
let generation = 0;
|
|
38891
|
+
let settingsPending = false;
|
|
38892
|
+
let lastResponse = null;
|
|
38893
|
+
let activeKey = "";
|
|
38894
|
+
const text3 = () => searchPaletteText(deps.getLanguage());
|
|
38895
|
+
function host() {
|
|
38896
|
+
return deps.$("#search-sheet");
|
|
38897
|
+
}
|
|
38898
|
+
function toggleButton(label, title, pressed, onToggle) {
|
|
38899
|
+
const button = document.createElement("button");
|
|
38900
|
+
button.type = "button";
|
|
38901
|
+
button.className = "gdp-palette-mode-button";
|
|
38902
|
+
button.textContent = label;
|
|
38903
|
+
button.title = title;
|
|
38904
|
+
button.setAttribute("aria-pressed", String(pressed));
|
|
38905
|
+
button.disabled = settingsPending;
|
|
38906
|
+
button.addEventListener("click", (event) => {
|
|
38907
|
+
event.preventDefault();
|
|
38908
|
+
onToggle();
|
|
38909
|
+
});
|
|
38910
|
+
return button;
|
|
38911
|
+
}
|
|
38912
|
+
async function updateFlag(patch) {
|
|
38913
|
+
if (settingsPending) return;
|
|
38914
|
+
settingsPending = true;
|
|
38915
|
+
renderControls();
|
|
38916
|
+
try {
|
|
38917
|
+
await deps.persistGrepSettings(patch);
|
|
38918
|
+
} catch (err) {
|
|
38919
|
+
console.error("Failed to save search option", err);
|
|
38920
|
+
if (status)
|
|
38921
|
+
status.textContent = text3().saveFailed(
|
|
38922
|
+
text3().regexMode,
|
|
38923
|
+
err instanceof Error && err.message ? err.message : text3().unknownError
|
|
38924
|
+
);
|
|
38925
|
+
} finally {
|
|
38926
|
+
settingsPending = false;
|
|
38927
|
+
renderControls();
|
|
38928
|
+
if (query) run();
|
|
38929
|
+
}
|
|
38930
|
+
}
|
|
38931
|
+
function renderControls() {
|
|
38932
|
+
if (!controls) return;
|
|
38933
|
+
const current = text3();
|
|
38934
|
+
controls.replaceChildren(
|
|
38935
|
+
toggleButton(
|
|
38936
|
+
current.plain,
|
|
38937
|
+
current.plain,
|
|
38938
|
+
!deps.getGrepRegex(),
|
|
38939
|
+
() => void updateFlag({ grepRegex: false })
|
|
38940
|
+
),
|
|
38941
|
+
toggleButton(
|
|
38942
|
+
current.regex,
|
|
38943
|
+
"Alt+R",
|
|
38944
|
+
deps.getGrepRegex(),
|
|
38945
|
+
() => void updateFlag({ grepRegex: true })
|
|
38946
|
+
),
|
|
38947
|
+
toggleButton(
|
|
38948
|
+
current.matchCase,
|
|
38949
|
+
current.matchCaseTitle,
|
|
38950
|
+
deps.getGrepCaseSensitive(),
|
|
38951
|
+
() => void updateFlag({ grepCaseSensitive: !deps.getGrepCaseSensitive() })
|
|
38952
|
+
),
|
|
38953
|
+
toggleButton(
|
|
38954
|
+
current.wholeWord,
|
|
38955
|
+
current.wholeWordTitle,
|
|
38956
|
+
deps.getGrepWholeWord(),
|
|
38957
|
+
() => void updateFlag({ grepWholeWord: !deps.getGrepWholeWord() })
|
|
38958
|
+
),
|
|
38959
|
+
toggleButton(
|
|
38960
|
+
current.excludeTests,
|
|
38961
|
+
current.excludeTestsTitle,
|
|
38962
|
+
deps.getGrepHideTests(),
|
|
38963
|
+
() => void updateFlag({ hideTests: !deps.getGrepHideTests() })
|
|
38964
|
+
)
|
|
38965
|
+
);
|
|
38966
|
+
}
|
|
38967
|
+
function mount() {
|
|
38968
|
+
const el2 = host();
|
|
38969
|
+
if (!el2 || mounted) return;
|
|
38970
|
+
mounted = true;
|
|
38971
|
+
el2.replaceChildren();
|
|
38972
|
+
const head = document.createElement("div");
|
|
38973
|
+
head.className = "search-results-head";
|
|
38974
|
+
input2 = document.createElement("input");
|
|
38975
|
+
input2.type = "search";
|
|
38976
|
+
input2.className = "search-results-input";
|
|
38977
|
+
input2.autocomplete = "off";
|
|
38978
|
+
input2.spellcheck = false;
|
|
38979
|
+
input2.addEventListener("keydown", (event) => {
|
|
38980
|
+
if (event.key === "Enter") {
|
|
38981
|
+
event.preventDefault();
|
|
38982
|
+
run(input2?.value ?? "");
|
|
38983
|
+
}
|
|
38984
|
+
});
|
|
38985
|
+
runButton = document.createElement("button");
|
|
38986
|
+
runButton.type = "button";
|
|
38987
|
+
runButton.className = "gdp-btn gdp-btn-sm search-results-run";
|
|
38988
|
+
runButton.addEventListener("click", () => run(input2?.value ?? ""));
|
|
38989
|
+
controls = document.createElement("div");
|
|
38990
|
+
controls.className = "gdp-palette-controls search-results-controls";
|
|
38991
|
+
status = document.createElement("div");
|
|
38992
|
+
status.className = "gdp-palette-status search-results-status";
|
|
38993
|
+
head.append(input2, runButton);
|
|
38994
|
+
list2 = document.createElement("div");
|
|
38995
|
+
list2.className = "gdp-palette-list search-results-list";
|
|
38996
|
+
list2.setAttribute("role", "listbox");
|
|
38997
|
+
el2.append(head, controls, status, list2);
|
|
38998
|
+
localize();
|
|
38999
|
+
}
|
|
39000
|
+
function renderResults() {
|
|
39001
|
+
if (!list2 || !status) return;
|
|
39002
|
+
list2.replaceChildren();
|
|
39003
|
+
if (!lastResponse) {
|
|
39004
|
+
status.textContent = text3().resultsIdle;
|
|
39005
|
+
return;
|
|
39006
|
+
}
|
|
39007
|
+
const { response, term } = lastResponse;
|
|
39008
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
39009
|
+
for (const match2 of response.matches) {
|
|
39010
|
+
const bucket = grouped.get(match2.path) ?? [];
|
|
39011
|
+
bucket.push(match2);
|
|
39012
|
+
grouped.set(match2.path, bucket);
|
|
39013
|
+
}
|
|
39014
|
+
for (const [path, matches2] of grouped) {
|
|
39015
|
+
const group = document.createElement("section");
|
|
39016
|
+
group.className = "gdp-palette-file-group";
|
|
39017
|
+
group.setAttribute("role", "group");
|
|
39018
|
+
group.setAttribute("aria-label", path);
|
|
39019
|
+
const heading2 = document.createElement("div");
|
|
39020
|
+
heading2.className = "gdp-palette-file-heading";
|
|
39021
|
+
const name = document.createElement("span");
|
|
39022
|
+
name.className = "gdp-palette-file-heading-name";
|
|
39023
|
+
name.textContent = path;
|
|
39024
|
+
name.title = path;
|
|
39025
|
+
const count = document.createElement("span");
|
|
39026
|
+
count.className = "gdp-palette-file-heading-count";
|
|
39027
|
+
count.textContent = String(matches2.length);
|
|
39028
|
+
heading2.append(name, count);
|
|
39029
|
+
const rows = document.createElement("div");
|
|
39030
|
+
rows.className = "gdp-palette-file-matches";
|
|
39031
|
+
for (const match2 of matches2) {
|
|
39032
|
+
const key = `${match2.path}\0${match2.line}`;
|
|
39033
|
+
const row = document.createElement("button");
|
|
39034
|
+
row.type = "button";
|
|
39035
|
+
row.className = "gdp-palette-row";
|
|
39036
|
+
row.setAttribute("role", "option");
|
|
39037
|
+
row.dataset.resultKey = key;
|
|
39038
|
+
row.setAttribute("aria-selected", String(key === activeKey));
|
|
39039
|
+
const title = document.createElement("span");
|
|
39040
|
+
title.className = "gdp-palette-row-title";
|
|
39041
|
+
title.textContent = text3().line(match2.line, match2.column);
|
|
39042
|
+
const detail = document.createElement("span");
|
|
39043
|
+
detail.className = "gdp-palette-row-detail";
|
|
39044
|
+
detail.textContent = match2.preview;
|
|
39045
|
+
row.append(title, detail);
|
|
39046
|
+
row.addEventListener("click", () => {
|
|
39047
|
+
setActiveRow(key);
|
|
39048
|
+
const hl = match2.matchText || (deps.getGrepRegex() ? "" : term);
|
|
39049
|
+
deps.openMatch({
|
|
39050
|
+
path: match2.path,
|
|
39051
|
+
line: match2.line,
|
|
39052
|
+
...hl ? { hl } : {}
|
|
39053
|
+
});
|
|
39054
|
+
});
|
|
39055
|
+
rows.appendChild(row);
|
|
39056
|
+
}
|
|
39057
|
+
group.append(heading2, rows);
|
|
39058
|
+
list2.appendChild(group);
|
|
39059
|
+
}
|
|
39060
|
+
}
|
|
39061
|
+
function setActiveRow(key) {
|
|
39062
|
+
activeKey = key;
|
|
39063
|
+
list2?.querySelectorAll(".gdp-palette-row").forEach((row) => {
|
|
39064
|
+
row.setAttribute("aria-selected", String(row.dataset.resultKey === key));
|
|
39065
|
+
});
|
|
39066
|
+
}
|
|
39067
|
+
function run(nextQuery) {
|
|
39068
|
+
if (!mounted) return;
|
|
39069
|
+
if (nextQuery !== void 0) query = nextQuery.trim();
|
|
39070
|
+
if (input2 && input2.value !== query) input2.value = query;
|
|
39071
|
+
controller?.abort();
|
|
39072
|
+
controller = null;
|
|
39073
|
+
const parsed = parseGrepQuery(query);
|
|
39074
|
+
deps.onQueryChange?.(query);
|
|
39075
|
+
if (!parsed.term) {
|
|
39076
|
+
lastResponse = null;
|
|
39077
|
+
renderResults();
|
|
39078
|
+
return;
|
|
39079
|
+
}
|
|
39080
|
+
const myGeneration = ++generation;
|
|
39081
|
+
if (status) status.textContent = text3().searching;
|
|
39082
|
+
const ref = deps.getRef();
|
|
39083
|
+
const regex = deps.getGrepRegex();
|
|
39084
|
+
const caseSensitive = deps.getGrepCaseSensitive();
|
|
39085
|
+
const wholeWord = deps.getGrepWholeWord();
|
|
39086
|
+
const hideTests = deps.getGrepHideTests();
|
|
39087
|
+
const params = buildGrepRequestParams({
|
|
39088
|
+
term: parsed.term,
|
|
39089
|
+
ref,
|
|
39090
|
+
regex,
|
|
39091
|
+
caseSensitive,
|
|
39092
|
+
wholeWord,
|
|
39093
|
+
hideTests,
|
|
39094
|
+
max: RESULTS_MAX
|
|
39095
|
+
});
|
|
39096
|
+
deps.appendScopeParams(params);
|
|
39097
|
+
for (const scope of parsed.paths) params.append("path", scope);
|
|
39098
|
+
const abort = new AbortController();
|
|
39099
|
+
controller = abort;
|
|
39100
|
+
void deps.trackLoad(
|
|
39101
|
+
fetch(`/_grep?${params.toString()}`, { signal: abort.signal }).then(
|
|
39102
|
+
async (r2) => {
|
|
39103
|
+
if (!r2.ok)
|
|
39104
|
+
throw new Error(
|
|
39105
|
+
`grep request failed (${r2.status}): ${await r2.text()}`
|
|
39106
|
+
);
|
|
39107
|
+
return r2.json();
|
|
39108
|
+
}
|
|
39109
|
+
)
|
|
39110
|
+
).then((response) => {
|
|
39111
|
+
if (myGeneration !== generation || abort.signal.aborted) return;
|
|
39112
|
+
const current = deps.getServerGeneration();
|
|
39113
|
+
if (response.generation !== void 0 && current > 0 && response.generation < current) {
|
|
39114
|
+
lastResponse = null;
|
|
39115
|
+
renderResults();
|
|
39116
|
+
if (status) status.textContent = text3().repositoryChanged;
|
|
39117
|
+
return;
|
|
39118
|
+
}
|
|
39119
|
+
lastResponse = { response, term: parsed.term };
|
|
39120
|
+
renderResults();
|
|
39121
|
+
if (status)
|
|
39122
|
+
status.textContent = `${text3().grepSummary({
|
|
39123
|
+
engine: response.engine,
|
|
39124
|
+
regex,
|
|
39125
|
+
caseSensitive,
|
|
39126
|
+
wholeWord,
|
|
39127
|
+
testsExcluded: hideTests,
|
|
39128
|
+
truncated: response.truncated,
|
|
39129
|
+
count: response.matches.length,
|
|
39130
|
+
paths: parsed.paths
|
|
39131
|
+
})} · ${text3().resultsScope(ref)}`;
|
|
39132
|
+
}).catch((err) => {
|
|
39133
|
+
if (deps.isAbortError(err) || abort.signal.aborted) return;
|
|
39134
|
+
if (myGeneration !== generation) return;
|
|
39135
|
+
console.error("Search results request failed", err);
|
|
39136
|
+
lastResponse = null;
|
|
39137
|
+
renderResults();
|
|
39138
|
+
if (status)
|
|
39139
|
+
status.textContent = text3().searchFailed(
|
|
39140
|
+
err instanceof Error && err.message ? err.message : text3().unknownError
|
|
39141
|
+
);
|
|
39142
|
+
});
|
|
39143
|
+
}
|
|
39144
|
+
function localize() {
|
|
39145
|
+
if (!mounted) return;
|
|
39146
|
+
const current = text3();
|
|
39147
|
+
if (input2) input2.placeholder = current.resultsPlaceholder;
|
|
39148
|
+
if (runButton) {
|
|
39149
|
+
runButton.textContent = current.resultsRun;
|
|
39150
|
+
runButton.title = current.resultsRun;
|
|
39151
|
+
}
|
|
39152
|
+
host()?.setAttribute("aria-label", current.resultsTitle);
|
|
39153
|
+
renderControls();
|
|
39154
|
+
renderResults();
|
|
39155
|
+
}
|
|
39156
|
+
function isOpen() {
|
|
39157
|
+
const el2 = host();
|
|
39158
|
+
return !!el2 && !el2.hidden;
|
|
39159
|
+
}
|
|
39160
|
+
return {
|
|
39161
|
+
open(nextQuery) {
|
|
39162
|
+
const el2 = host();
|
|
39163
|
+
if (!el2) return;
|
|
39164
|
+
mount();
|
|
39165
|
+
el2.hidden = false;
|
|
39166
|
+
el2.setAttribute("aria-hidden", "false");
|
|
39167
|
+
el2.removeAttribute("inert");
|
|
39168
|
+
document.body.classList.add("search-sheet-open");
|
|
39169
|
+
if (nextQuery !== void 0 && nextQuery !== query) run(nextQuery);
|
|
39170
|
+
else if (nextQuery === void 0 && !lastResponse && query) run(query);
|
|
39171
|
+
else renderResults();
|
|
39172
|
+
input2?.focus();
|
|
39173
|
+
},
|
|
39174
|
+
close() {
|
|
39175
|
+
const el2 = host();
|
|
39176
|
+
if (!el2) return;
|
|
39177
|
+
el2.hidden = true;
|
|
39178
|
+
el2.setAttribute("aria-hidden", "true");
|
|
39179
|
+
el2.setAttribute("inert", "");
|
|
39180
|
+
document.body.classList.remove("search-sheet-open");
|
|
39181
|
+
controller?.abort();
|
|
39182
|
+
controller = null;
|
|
39183
|
+
},
|
|
39184
|
+
isOpen,
|
|
39185
|
+
getQuery: () => query,
|
|
39186
|
+
localize
|
|
39187
|
+
};
|
|
39188
|
+
}
|
|
39189
|
+
|
|
38091
39190
|
// web-src/views/source-view.ts
|
|
38092
39191
|
function createSourceView(deps) {
|
|
38093
39192
|
const {
|
|
@@ -38106,6 +39205,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38106
39205
|
placeSidebarToggle,
|
|
38107
39206
|
createFileBreadcrumb,
|
|
38108
39207
|
createRepositoryWebLink: createRepositoryWebLink2,
|
|
39208
|
+
createRevisionNav,
|
|
38109
39209
|
createFileDetailMeta,
|
|
38110
39210
|
createOpenPathButton,
|
|
38111
39211
|
createMoveToTrashButton,
|
|
@@ -38396,10 +39496,17 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38396
39496
|
const cells = table2.querySelectorAll(
|
|
38397
39497
|
".gdp-source-line-code"
|
|
38398
39498
|
);
|
|
39499
|
+
const sourceLines = textValue.split("\n");
|
|
38399
39500
|
cells.forEach((cell, index) => {
|
|
38400
39501
|
if (highlightedLines[index] == null) return;
|
|
38401
39502
|
cell.innerHTML = highlightedLines[index] || " ";
|
|
38402
39503
|
cell.classList.add("shiki");
|
|
39504
|
+
markSourceHighlightTerm(
|
|
39505
|
+
cell,
|
|
39506
|
+
sourceLines[index] ?? "",
|
|
39507
|
+
index + 1,
|
|
39508
|
+
target
|
|
39509
|
+
);
|
|
38403
39510
|
});
|
|
38404
39511
|
}).catch((err) => {
|
|
38405
39512
|
console.error("Failed to apply source syntax highlighting", err);
|
|
@@ -38814,6 +39921,7 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38814
39921
|
const code2 = document.createElement("td");
|
|
38815
39922
|
code2.className = "gdp-source-line-code";
|
|
38816
39923
|
code2.textContent = line || " ";
|
|
39924
|
+
markSourceHighlightTerm(code2, line, index + 1, target);
|
|
38817
39925
|
tr.appendChild(num);
|
|
38818
39926
|
tr.appendChild(code2);
|
|
38819
39927
|
tbody.appendChild(tr);
|
|
@@ -38959,6 +40067,45 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
38959
40067
|
const routeTarget = sourceTargetFromRoute();
|
|
38960
40068
|
return sourceTargetsEqual(routeTarget, target) && STATE.route.screen === "file" ? STATE.route.line : void 0;
|
|
38961
40069
|
}
|
|
40070
|
+
function currentSourceHighlightTerm(target) {
|
|
40071
|
+
const routeTarget = sourceTargetFromRoute();
|
|
40072
|
+
return sourceTargetsEqual(routeTarget, target) && STATE.route.screen === "file" && STATE.route.line && STATE.route.hl ? STATE.route.hl : void 0;
|
|
40073
|
+
}
|
|
40074
|
+
function syncSourceHighlightMarks(card, target) {
|
|
40075
|
+
card.querySelectorAll("mark.gdp-grep-match").forEach((mark) => {
|
|
40076
|
+
const parent = mark.parentElement;
|
|
40077
|
+
if (!parent) return;
|
|
40078
|
+
while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
|
|
40079
|
+
parent.removeChild(mark);
|
|
40080
|
+
parent.normalize();
|
|
40081
|
+
});
|
|
40082
|
+
const term = currentSourceHighlightTerm(target);
|
|
40083
|
+
const virtual = card.querySelector(
|
|
40084
|
+
".gdp-source-virtual"
|
|
40085
|
+
);
|
|
40086
|
+
if (virtual?.__gdpVirtualSourceSearch) {
|
|
40087
|
+
if (term) virtual.__gdpVirtualSourceSearch.open(term);
|
|
40088
|
+
return;
|
|
40089
|
+
}
|
|
40090
|
+
if (!term) return;
|
|
40091
|
+
card.querySelectorAll(".gdp-source-table tr[data-line]").forEach((row) => {
|
|
40092
|
+
const cell = row.querySelector(".gdp-source-line-code");
|
|
40093
|
+
if (!cell) return;
|
|
40094
|
+
markSourceHighlightTerm(
|
|
40095
|
+
cell,
|
|
40096
|
+
cell.textContent ?? "",
|
|
40097
|
+
Number(row.dataset.line || "0"),
|
|
40098
|
+
target
|
|
40099
|
+
);
|
|
40100
|
+
});
|
|
40101
|
+
}
|
|
40102
|
+
function markSourceHighlightTerm(cell, lineText, lineNumber, target) {
|
|
40103
|
+
const term = currentSourceHighlightTerm(target);
|
|
40104
|
+
if (!term) return;
|
|
40105
|
+
if (!lineInSourceTarget(lineNumber, currentSourceLineTarget(target)))
|
|
40106
|
+
return;
|
|
40107
|
+
markNeedleInCell(cell, lineText, term, "gdp-grep-match");
|
|
40108
|
+
}
|
|
38962
40109
|
function lineTargetStart(line) {
|
|
38963
40110
|
if (!line) return void 0;
|
|
38964
40111
|
return typeof line === "number" ? line : line.start;
|
|
@@ -39166,8 +40313,9 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
39166
40313
|
next.addEventListener("click", () => move(1));
|
|
39167
40314
|
close.addEventListener("click", hide);
|
|
39168
40315
|
return {
|
|
39169
|
-
open: () => {
|
|
40316
|
+
open: (query) => {
|
|
39170
40317
|
bar.hidden = false;
|
|
40318
|
+
if (query !== void 0) input2.value = query;
|
|
39171
40319
|
input2.focus();
|
|
39172
40320
|
input2.select();
|
|
39173
40321
|
sync();
|
|
@@ -39335,6 +40483,13 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
39335
40483
|
render
|
|
39336
40484
|
);
|
|
39337
40485
|
wrap.__gdpVirtualSourceSearch = search;
|
|
40486
|
+
const initialHighlightTerm = currentSourceHighlightTerm(target);
|
|
40487
|
+
if (initialHighlightTerm) {
|
|
40488
|
+
const searchHandle = search;
|
|
40489
|
+
setTimeout(() => {
|
|
40490
|
+
if (wrap.isConnected) searchHandle.open(initialHighlightTerm);
|
|
40491
|
+
}, 0);
|
|
40492
|
+
}
|
|
39338
40493
|
let resizeObserver = null;
|
|
39339
40494
|
resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(() => {
|
|
39340
40495
|
if (!scroller.isConnected) {
|
|
@@ -39588,6 +40743,13 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
39588
40743
|
render
|
|
39589
40744
|
);
|
|
39590
40745
|
wrap.__gdpVirtualSourceSearch = search;
|
|
40746
|
+
const initialHighlightTerm = currentSourceHighlightTerm(target);
|
|
40747
|
+
if (initialHighlightTerm) {
|
|
40748
|
+
const searchHandle = search;
|
|
40749
|
+
setTimeout(() => {
|
|
40750
|
+
if (wrap.isConnected) searchHandle.open(initialHighlightTerm);
|
|
40751
|
+
}, 0);
|
|
40752
|
+
}
|
|
39591
40753
|
let resizeObserver = null;
|
|
39592
40754
|
resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(() => {
|
|
39593
40755
|
if (!scroller.isConnected) {
|
|
@@ -39737,6 +40899,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
39737
40899
|
const mounted = mountedStandaloneSourceCard(target);
|
|
39738
40900
|
const state = mounted?.dataset.sourceState;
|
|
39739
40901
|
if (mounted && state === "done") {
|
|
40902
|
+
syncRenderedSourceLineHighlights(mounted, target);
|
|
40903
|
+
syncSourceHighlightMarks(mounted, target);
|
|
39740
40904
|
scrollStandaloneSourceLine(
|
|
39741
40905
|
mounted,
|
|
39742
40906
|
lineTargetStart(
|
|
@@ -39772,7 +40936,8 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
39772
40936
|
setRoute,
|
|
39773
40937
|
setPreferredSourceTab,
|
|
39774
40938
|
createFileBreadcrumb,
|
|
39775
|
-
createRepositoryWebLink: createRepositoryWebLink2
|
|
40939
|
+
createRepositoryWebLink: createRepositoryWebLink2,
|
|
40940
|
+
createRevisionNav
|
|
39776
40941
|
},
|
|
39777
40942
|
target,
|
|
39778
40943
|
activeTab,
|
|
@@ -45455,6 +46620,7 @@ ${t2.files.overlapTitle(others)}`;
|
|
|
45455
46620
|
if (name) name.textContent = branch;
|
|
45456
46621
|
el2.title = branch ? `Current branch: ${branch}` : "";
|
|
45457
46622
|
}
|
|
46623
|
+
const MAX_RECENT_REFS = 8;
|
|
45458
46624
|
function mergeLocalSettings(patch) {
|
|
45459
46625
|
const next = { ...APP_SETTINGS };
|
|
45460
46626
|
for (const [key, value] of Object.entries(patch)) {
|
|
@@ -46021,7 +47187,20 @@ ${error2.stack}` : ""}`
|
|
|
46021
47187
|
copyReferenceLabel: () => uiText().global.copyLineReference,
|
|
46022
47188
|
lineCountLabel: (count) => uiText().global.selectedLineCount(count),
|
|
46023
47189
|
githubOpenTitle: () => uiText().global.githubSelectionOpen,
|
|
46024
|
-
githubCopyTitle: () => uiText().global.githubSelectionCopy
|
|
47190
|
+
githubCopyTitle: () => uiText().global.githubSelectionCopy,
|
|
47191
|
+
lineHistoryTitle: () => uiText().global.lineHistory,
|
|
47192
|
+
openLineHistory: (path, start, end) => {
|
|
47193
|
+
const route = STATE.route;
|
|
47194
|
+
const ref = route.screen === "file" ? route.commit || route.ref || "worktree" : route.screen === "diff" && route.range.to ? route.range.to : "worktree";
|
|
47195
|
+
navigateToRoute({
|
|
47196
|
+
screen: "file",
|
|
47197
|
+
path,
|
|
47198
|
+
ref,
|
|
47199
|
+
view: "history",
|
|
47200
|
+
lines: { start, end },
|
|
47201
|
+
range: currentRange()
|
|
47202
|
+
});
|
|
47203
|
+
}
|
|
46025
47204
|
});
|
|
46026
47205
|
const DIFF_LINE_SELECT = createDiffLineSelect({ pill: LINE_REF_PILL });
|
|
46027
47206
|
function clearRenderedSourceLineTargets() {
|
|
@@ -46091,6 +47270,7 @@ ${error2.stack}` : ""}`
|
|
|
46091
47270
|
REPO_SIDEBAR_REF = ref;
|
|
46092
47271
|
},
|
|
46093
47272
|
isTestPath: isTestFilePath,
|
|
47273
|
+
filterCountTitle: (visible, total) => uiText().sidebar.filterCountTitle(visible, total),
|
|
46094
47274
|
sidebarToggleTitle: (hidden) => hidden ? uiText().sidebar.show : uiText().sidebar.hide,
|
|
46095
47275
|
openDirectoryInOsTitle: () => uiText().sidebar.openDirectoryInOs,
|
|
46096
47276
|
omittedDirectoryBadge: (reason) => {
|
|
@@ -46169,6 +47349,7 @@ ${error2.stack}` : ""}`
|
|
|
46169
47349
|
placeSidebarToggle,
|
|
46170
47350
|
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref),
|
|
46171
47351
|
createRepositoryWebLink: createFileRepositoryWebLink,
|
|
47352
|
+
createRevisionNav: createFileRevisionNav,
|
|
46172
47353
|
createFileDetailMeta: (target, meta) => REPO_VIEW.createFileDetailMeta(target, meta),
|
|
46173
47354
|
createOpenPathButton,
|
|
46174
47355
|
createMoveToTrashButton: (path, onDeleted) => REPO_VIEW.createMoveToTrashButton(path, onDeleted),
|
|
@@ -46212,6 +47393,7 @@ ${error2.stack}` : ""}`
|
|
|
46212
47393
|
setPreferredSourceTab: (tab) => SOURCE_VIEW.setPreferredSourceTab(tab),
|
|
46213
47394
|
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref),
|
|
46214
47395
|
createRepositoryWebLink: createFileRepositoryWebLink,
|
|
47396
|
+
createRevisionNav: createFileRevisionNav,
|
|
46215
47397
|
removeStandaloneSource,
|
|
46216
47398
|
placeSidebarToggle,
|
|
46217
47399
|
escapeHtml: escapeHtml3,
|
|
@@ -46295,6 +47477,17 @@ ${error2.stack}` : ""}`
|
|
|
46295
47477
|
}),
|
|
46296
47478
|
openGithubLabel: () => uiText().repo.openGithub,
|
|
46297
47479
|
openRepositoryWebLabel: () => uiText().repo.openRepositoryWeb,
|
|
47480
|
+
folderHistoryLabel: () => uiText().repo.folderHistory,
|
|
47481
|
+
folderHistoryTitle: () => uiText().repo.folderHistoryTitle,
|
|
47482
|
+
openFolderHistory: (ref, path) => {
|
|
47483
|
+
const dir = path.replace(/\/+$/, "");
|
|
47484
|
+
navigateToRoute({
|
|
47485
|
+
screen: "history",
|
|
47486
|
+
ref: ref && ref !== "worktree" ? ref : "HEAD",
|
|
47487
|
+
...dir ? { path: `${dir}/` } : {},
|
|
47488
|
+
range: currentRange()
|
|
47489
|
+
});
|
|
47490
|
+
},
|
|
46298
47491
|
fileBadge: (status) => DIFF_VIEW.fileBadge(status)
|
|
46299
47492
|
});
|
|
46300
47493
|
const {
|
|
@@ -46328,6 +47521,8 @@ ${error2.stack}` : ""}`
|
|
|
46328
47521
|
getFileSelectionHistory: () => APP_SETTINGS.fileSelectionHistory || [],
|
|
46329
47522
|
getGrepSelectionHistory: () => APP_SETTINGS.grepSelectionHistory || [],
|
|
46330
47523
|
getGrepRegex: () => APP_SETTINGS.grepRegex === true,
|
|
47524
|
+
getGrepCaseSensitive: () => APP_SETTINGS.grepCaseSensitive === true,
|
|
47525
|
+
getGrepWholeWord: () => APP_SETTINGS.grepWholeWord === true,
|
|
46331
47526
|
getGrepHideTests: () => STATE.hideTests,
|
|
46332
47527
|
getGrepGroupByFile: () => APP_SETTINGS.grepGroupByFile === true,
|
|
46333
47528
|
getGrepPaletteWidth: () => APP_SETTINGS.grepPaletteWidth,
|
|
@@ -46336,7 +47531,8 @@ ${error2.stack}` : ""}`
|
|
|
46336
47531
|
applyGrepHideTests: (hidden) => {
|
|
46337
47532
|
STATE.hideTests = hidden;
|
|
46338
47533
|
applyHideTests();
|
|
46339
|
-
}
|
|
47534
|
+
},
|
|
47535
|
+
openSearchResults: (query) => openSearchSheet(query)
|
|
46340
47536
|
});
|
|
46341
47537
|
const { openSearchPalette, isPaletteOpen, paletteMode, clearRepoFileCache } = SEARCH_PALETTE;
|
|
46342
47538
|
const UI_TEXT = {
|
|
@@ -46366,6 +47562,11 @@ ${error2.stack}` : ""}`
|
|
|
46366
47562
|
queryHistory: "query history",
|
|
46367
47563
|
settings: "viewer settings",
|
|
46368
47564
|
theme: "toggle theme",
|
|
47565
|
+
search: "Search files (Ctrl+K) · Shift+click: grep (Ctrl+G)",
|
|
47566
|
+
lineHistory: "Line history",
|
|
47567
|
+
recentRef: "Recently used ref",
|
|
47568
|
+
olderRevision: "Older revision of this file",
|
|
47569
|
+
newerRevision: "Newer revision of this file",
|
|
46369
47570
|
copyAiContext: "Copy AI context (Shift+Click to include code)",
|
|
46370
47571
|
copyAiContextCopied: "Copied AI context",
|
|
46371
47572
|
copyAiContextCopiedWithCode: (lines) => `Copied AI context + code (${lines} line${lines === 1 ? "" : "s"})`,
|
|
@@ -46454,7 +47655,8 @@ ${error2.stack}` : ""}`
|
|
|
46454
47655
|
treeTitle: "tree view",
|
|
46455
47656
|
flatTitle: "flat list",
|
|
46456
47657
|
filter: "Filter files… / ⌘K",
|
|
46457
|
-
filterTitle: "Filter files.
|
|
47658
|
+
filterTitle: "Filter files. Plain text matches anywhere in the path; /pattern/ is a regex, ~text is a fuzzy match, *.ts or src/** is a glob. Press / to focus this field, Cmd/Ctrl+K for the full-file palette, Ctrl+G for grep, ? for help.",
|
|
47659
|
+
filterCountTitle: (visible, total) => `${visible} of ${total} files match the filter`,
|
|
46458
47660
|
filterClear: "Clear",
|
|
46459
47661
|
filterClearTitle: "Clear file filter",
|
|
46460
47662
|
hide: "hide sidebar",
|
|
@@ -46490,7 +47692,9 @@ ${error2.stack}` : ""}`
|
|
|
46490
47692
|
submoduleLabel: "submodule",
|
|
46491
47693
|
submoduleTitle: "Git submodule pinned to a commit",
|
|
46492
47694
|
openGithub: "Open on GitHub",
|
|
46493
|
-
openRepositoryWeb: "Open repository web page"
|
|
47695
|
+
openRepositoryWeb: "Open repository web page",
|
|
47696
|
+
folderHistory: "History",
|
|
47697
|
+
folderHistoryTitle: "Commits that touched this folder"
|
|
46494
47698
|
},
|
|
46495
47699
|
history: {
|
|
46496
47700
|
title: "Commits",
|
|
@@ -46702,6 +47906,11 @@ ${error2.stack}` : ""}`
|
|
|
46702
47906
|
queryHistory: "クエリ履歴",
|
|
46703
47907
|
settings: "ビューア設定",
|
|
46704
47908
|
theme: "テーマ切り替え",
|
|
47909
|
+
search: "ファイルを検索 (Ctrl+K)・Shift+クリックで grep (Ctrl+G)",
|
|
47910
|
+
lineHistory: "この行の履歴",
|
|
47911
|
+
recentRef: "最近使った ref",
|
|
47912
|
+
olderRevision: "このファイルの 1 つ前のリビジョン",
|
|
47913
|
+
newerRevision: "このファイルの 1 つ後のリビジョン",
|
|
46705
47914
|
copyAiContext: "AI 用コンテキストをコピー(Shift+Click でコードも添付)",
|
|
46706
47915
|
copyAiContextCopied: "コピーしました",
|
|
46707
47916
|
copyAiContextCopiedWithCode: (lines) => `コピーしました(コード付き・${lines}行)`,
|
|
@@ -46790,7 +47999,8 @@ ${error2.stack}` : ""}`
|
|
|
46790
47999
|
treeTitle: "ツリー表示",
|
|
46791
48000
|
flatTitle: "一覧表示",
|
|
46792
48001
|
filter: "ファイル絞り込み… / ⌘K",
|
|
46793
|
-
filterTitle: "
|
|
48002
|
+
filterTitle: "ファイルを絞り込みます。文字列はパスの部分一致、/pattern/ は正規表現、~text はあいまい一致、*.ts や src/** は glob。/ でこの欄にフォーカス、Cmd/Ctrl+K で全ファイルパレット、Ctrl+G で grep、? でヘルプ。",
|
|
48003
|
+
filterCountTitle: (visible, total) => `${total} ファイル中 ${visible} 件が一致`,
|
|
46794
48004
|
filterClear: "解除",
|
|
46795
48005
|
filterClearTitle: "ファイル絞り込みを解除",
|
|
46796
48006
|
hide: "サイドバーを隠す",
|
|
@@ -46826,7 +48036,9 @@ ${error2.stack}` : ""}`
|
|
|
46826
48036
|
submoduleLabel: "サブモジュール",
|
|
46827
48037
|
submoduleTitle: "Git サブモジュール: 特定のコミットに固定されています。直接は開けません。",
|
|
46828
48038
|
openGithub: "GitHubで開く",
|
|
46829
|
-
openRepositoryWeb: "リポジトリのウェブページを開く"
|
|
48039
|
+
openRepositoryWeb: "リポジトリのウェブページを開く",
|
|
48040
|
+
folderHistory: "履歴",
|
|
48041
|
+
folderHistoryTitle: "このフォルダを変更したコミット"
|
|
46830
48042
|
},
|
|
46831
48043
|
history: {
|
|
46832
48044
|
title: "コミット",
|
|
@@ -47054,6 +48266,11 @@ ${error2.stack}` : ""}`
|
|
|
47054
48266
|
quickHelpBtn.title = text3.quickHelp.buttonTitle;
|
|
47055
48267
|
quickHelpBtn.setAttribute("aria-label", text3.quickHelp.buttonTitle);
|
|
47056
48268
|
}
|
|
48269
|
+
const searchBtn = document.querySelector("#search-btn");
|
|
48270
|
+
if (searchBtn) {
|
|
48271
|
+
searchBtn.title = text3.global.search;
|
|
48272
|
+
searchBtn.setAttribute("aria-label", text3.global.search);
|
|
48273
|
+
}
|
|
47057
48274
|
QUICK_HELP?.localize();
|
|
47058
48275
|
const doctorTitle = doctorText(STATE.language).title;
|
|
47059
48276
|
const doctorBtn = document.querySelector("#doctor-btn");
|
|
@@ -47080,6 +48297,13 @@ ${error2.stack}` : ""}`
|
|
|
47080
48297
|
}
|
|
47081
48298
|
document.querySelector("#terminal-sheet")?.setAttribute("aria-label", terminalChrome.title);
|
|
47082
48299
|
relocalizeTerminal?.();
|
|
48300
|
+
const searchChrome = searchPaletteText(STATE.language);
|
|
48301
|
+
const searchTabBtn = document.querySelector("#panel-tab-search");
|
|
48302
|
+
if (searchTabBtn) {
|
|
48303
|
+
searchTabBtn.textContent = searchChrome.resultsTitle;
|
|
48304
|
+
searchTabBtn.title = searchChrome.resultsOpen;
|
|
48305
|
+
}
|
|
48306
|
+
relocalizeSearchResults?.();
|
|
47083
48307
|
document.querySelector(".app-panel-tabs")?.setAttribute("aria-label", text3.appPanel.tabs);
|
|
47084
48308
|
const panelLayout = document.querySelector(
|
|
47085
48309
|
".app-panel-layout-switch"
|
|
@@ -47242,6 +48466,7 @@ ${error2.stack}` : ""}`
|
|
|
47242
48466
|
let relocalizeTools = null;
|
|
47243
48467
|
let relocalizeViewerSettings = null;
|
|
47244
48468
|
let relocalizeTerminal = null;
|
|
48469
|
+
let relocalizeSearchResults = null;
|
|
47245
48470
|
let relocalizeDatabase = null;
|
|
47246
48471
|
let QUICK_HELP = null;
|
|
47247
48472
|
function setViewerLanguage(language, persist = true) {
|
|
@@ -47592,6 +48817,18 @@ ${error2.stack}` : ""}`
|
|
|
47592
48817
|
function isHistoryPanelRoute(route) {
|
|
47593
48818
|
return route.screen === "history" || isFileHistoryRoute(route);
|
|
47594
48819
|
}
|
|
48820
|
+
function historyRefForCurrentView() {
|
|
48821
|
+
const route = STATE.route;
|
|
48822
|
+
if (route.screen === "history") return route.ref || "HEAD";
|
|
48823
|
+
if (route.screen === "repo" || route.screen === "file") {
|
|
48824
|
+
return route.ref && route.ref !== "worktree" ? route.ref : "HEAD";
|
|
48825
|
+
}
|
|
48826
|
+
if (route.screen === "diff") {
|
|
48827
|
+
const to = route.range.to;
|
|
48828
|
+
return to && to !== "worktree" ? to : "HEAD";
|
|
48829
|
+
}
|
|
48830
|
+
return "HEAD";
|
|
48831
|
+
}
|
|
47595
48832
|
function normalizeInternalFileRoute(route) {
|
|
47596
48833
|
if (route.screen !== "file") return route;
|
|
47597
48834
|
if (sourceInternalPathKind(route.path) === null) return route;
|
|
@@ -47640,6 +48877,7 @@ ${error2.stack}` : ""}`
|
|
|
47640
48877
|
setPreferredSourceTab: (tab) => SOURCE_VIEW.setPreferredSourceTab(tab),
|
|
47641
48878
|
createFileBreadcrumb: (path, ref) => DIFF_VIEW.createFileBreadcrumb(path, ref),
|
|
47642
48879
|
createRepositoryWebLink: createFileRepositoryWebLink,
|
|
48880
|
+
createRevisionNav: createFileRevisionNav,
|
|
47643
48881
|
emptyText: () => uiText().diff
|
|
47644
48882
|
},
|
|
47645
48883
|
historyRoute,
|
|
@@ -47659,15 +48897,21 @@ ${error2.stack}` : ""}`
|
|
|
47659
48897
|
return ANNOTATIONS_UI ? ANNOTATIONS_UI.withSessionParam(rawUrl) : rawUrl;
|
|
47660
48898
|
}
|
|
47661
48899
|
function withOverlayState(url) {
|
|
47662
|
-
return
|
|
47663
|
-
|
|
47664
|
-
|
|
47665
|
-
|
|
47666
|
-
|
|
48900
|
+
return withSearchResultsOverlay(
|
|
48901
|
+
withTerminalOverlay(
|
|
48902
|
+
withToolsOverlay(
|
|
48903
|
+
withDoctorOverlay(
|
|
48904
|
+
url,
|
|
48905
|
+
parseDoctorOverlay(
|
|
48906
|
+
window.location.pathname,
|
|
48907
|
+
window.location.search
|
|
48908
|
+
)
|
|
48909
|
+
),
|
|
48910
|
+
parseToolsOverlay(window.location.search)
|
|
47667
48911
|
),
|
|
47668
|
-
|
|
48912
|
+
parseTerminalOverlay(window.location.search)
|
|
47669
48913
|
),
|
|
47670
|
-
|
|
48914
|
+
parseSearchResultsOverlay(window.location.search)
|
|
47671
48915
|
);
|
|
47672
48916
|
}
|
|
47673
48917
|
function urlForRoute(route) {
|
|
@@ -48058,6 +49302,61 @@ ${error2.stack}` : ""}`
|
|
|
48058
49302
|
});
|
|
48059
49303
|
return button;
|
|
48060
49304
|
}
|
|
49305
|
+
function createFileRevisionNav(target, activeTab) {
|
|
49306
|
+
if (activeTab === "history") return null;
|
|
49307
|
+
const nav = document.createElement("span");
|
|
49308
|
+
nav.className = "gdp-file-revision-nav";
|
|
49309
|
+
const text3 = uiText().global;
|
|
49310
|
+
const make = (title, paths) => {
|
|
49311
|
+
const button = document.createElement("button");
|
|
49312
|
+
button.type = "button";
|
|
49313
|
+
button.className = "gdp-file-header-icon gdp-file-revision-btn";
|
|
49314
|
+
button.title = title;
|
|
49315
|
+
button.setAttribute("aria-label", title);
|
|
49316
|
+
button.disabled = true;
|
|
49317
|
+
button.innerHTML = iconSvg("octicon-revision", paths);
|
|
49318
|
+
return button;
|
|
49319
|
+
};
|
|
49320
|
+
const older = make(text3.olderRevision, PREVIOUS_16_PATHS);
|
|
49321
|
+
const newer = make(text3.newerRevision, NEXT_16_PATHS);
|
|
49322
|
+
nav.append(older, newer);
|
|
49323
|
+
const goTo = (sha) => {
|
|
49324
|
+
const view = STATE.route.screen === "file" && STATE.route.view === "blame" ? "blame" : "blob";
|
|
49325
|
+
navigateToRoute({
|
|
49326
|
+
screen: "file",
|
|
49327
|
+
path: target.path,
|
|
49328
|
+
ref: sha,
|
|
49329
|
+
view,
|
|
49330
|
+
range: currentRange()
|
|
49331
|
+
});
|
|
49332
|
+
};
|
|
49333
|
+
const params = new URLSearchParams({
|
|
49334
|
+
path: target.path,
|
|
49335
|
+
ref: target.ref || "worktree"
|
|
49336
|
+
});
|
|
49337
|
+
void trackLoad(
|
|
49338
|
+
fetch(`/_file_revisions?${params.toString()}`).then(async (r2) => {
|
|
49339
|
+
if (!r2.ok) throw new Error(await r2.text());
|
|
49340
|
+
return r2.json();
|
|
49341
|
+
})
|
|
49342
|
+
).then((neighbors) => {
|
|
49343
|
+
if (!nav.isConnected) return;
|
|
49344
|
+
if (neighbors.previous) {
|
|
49345
|
+
const sha = neighbors.previous;
|
|
49346
|
+
older.disabled = false;
|
|
49347
|
+
older.addEventListener("click", () => goTo(sha));
|
|
49348
|
+
}
|
|
49349
|
+
if (neighbors.next) {
|
|
49350
|
+
const sha = neighbors.next;
|
|
49351
|
+
newer.disabled = false;
|
|
49352
|
+
newer.addEventListener("click", () => goTo(sha));
|
|
49353
|
+
}
|
|
49354
|
+
}).catch((err) => {
|
|
49355
|
+
if (isAbortError3(err)) return;
|
|
49356
|
+
console.error("Failed to load file revision neighbours", err);
|
|
49357
|
+
});
|
|
49358
|
+
return nav;
|
|
49359
|
+
}
|
|
48061
49360
|
function createFileRepositoryWebLink(target) {
|
|
48062
49361
|
const webTarget = buildRepositoryWebTarget(REPO_WEB_URL, {
|
|
48063
49362
|
ref: target.ref,
|
|
@@ -48259,6 +49558,12 @@ ${error2.stack}` : ""}`
|
|
|
48259
49558
|
if (quickHelpIcon) {
|
|
48260
49559
|
quickHelpIcon.innerHTML = iconSvg("octicon-question", QUESTION_16_PATH);
|
|
48261
49560
|
}
|
|
49561
|
+
const searchIcon = document.querySelector(
|
|
49562
|
+
"#search-btn .goi-icon"
|
|
49563
|
+
);
|
|
49564
|
+
if (searchIcon) {
|
|
49565
|
+
searchIcon.innerHTML = iconSvg("octicon-search", SEARCH_16_PATH);
|
|
49566
|
+
}
|
|
48262
49567
|
const branchIcon = document.querySelector(
|
|
48263
49568
|
"#project-branch .goi-icon"
|
|
48264
49569
|
);
|
|
@@ -48313,6 +49618,10 @@ ${error2.stack}` : ""}`
|
|
|
48313
49618
|
event.preventDefault();
|
|
48314
49619
|
openTerminalSheet();
|
|
48315
49620
|
});
|
|
49621
|
+
$("#panel-tab-search")?.addEventListener("click", (event) => {
|
|
49622
|
+
event.preventDefault();
|
|
49623
|
+
openSearchSheet();
|
|
49624
|
+
});
|
|
48316
49625
|
$("#app-panel-close")?.addEventListener("click", (event) => {
|
|
48317
49626
|
event.preventDefault();
|
|
48318
49627
|
closeAppPanel();
|
|
@@ -48548,6 +49857,9 @@ ${error2.stack}` : ""}`
|
|
|
48548
49857
|
syncSidebarFilterClearButton();
|
|
48549
49858
|
sbFilterClear.addEventListener("click", clearSidebarFilter);
|
|
48550
49859
|
}
|
|
49860
|
+
document.querySelector("#search-btn")?.addEventListener("click", (event) => {
|
|
49861
|
+
openSearchPalette(event.shiftKey ? "grep" : "file");
|
|
49862
|
+
});
|
|
48551
49863
|
function focusFileFilter() {
|
|
48552
49864
|
const input2 = $("#sb-filter");
|
|
48553
49865
|
input2.focus();
|
|
@@ -48738,11 +50050,18 @@ ${error2.stack}` : ""}`
|
|
|
48738
50050
|
if (action === "goto-history") {
|
|
48739
50051
|
navigateToRoute({
|
|
48740
50052
|
screen: "history",
|
|
48741
|
-
ref:
|
|
50053
|
+
ref: historyRefForCurrentView(),
|
|
48742
50054
|
range: currentRange()
|
|
48743
50055
|
});
|
|
48744
50056
|
return true;
|
|
48745
50057
|
}
|
|
50058
|
+
if (action === "history-next-commit" || action === "history-previous-commit") {
|
|
50059
|
+
if (!isHistoryPanelRoute(STATE.route)) return false;
|
|
50060
|
+
void HISTORY_VIEW.moveCommitSelection(
|
|
50061
|
+
action === "history-next-commit" ? 1 : -1
|
|
50062
|
+
);
|
|
50063
|
+
return true;
|
|
50064
|
+
}
|
|
48746
50065
|
if (action === "goto-repo") {
|
|
48747
50066
|
navigateToRoute({
|
|
48748
50067
|
screen: "repo",
|
|
@@ -49060,6 +50379,7 @@ ${error2.stack}` : ""}`
|
|
|
49060
50379
|
syncDoctorSheetFromUrl();
|
|
49061
50380
|
syncToolsSheetFromUrl();
|
|
49062
50381
|
syncTerminalSheetFromUrl();
|
|
50382
|
+
syncSearchSheetFromUrl();
|
|
49063
50383
|
});
|
|
49064
50384
|
function syncRefInputs() {
|
|
49065
50385
|
const fi = $("#ref-from"), ti = $("#ref-to");
|
|
@@ -49151,7 +50471,19 @@ ${error2.stack}` : ""}`
|
|
|
49151
50471
|
},
|
|
49152
50472
|
getSyntaxHighlight: () => STATE.syntaxHighlight,
|
|
49153
50473
|
getLanguage: () => STATE.language,
|
|
49154
|
-
trackLoad
|
|
50474
|
+
trackLoad,
|
|
50475
|
+
commitWebLink: (sha) => {
|
|
50476
|
+
const target = buildRepositoryWebTarget(REPO_WEB_URL, {
|
|
50477
|
+
ref: sha,
|
|
50478
|
+
kind: "commit"
|
|
50479
|
+
});
|
|
50480
|
+
if (!target) return null;
|
|
50481
|
+
return createRepositoryWebLink(
|
|
50482
|
+
target,
|
|
50483
|
+
target.provider === "github" ? uiText().repo.openGithub : uiText().repo.openRepositoryWeb
|
|
50484
|
+
);
|
|
50485
|
+
},
|
|
50486
|
+
copyText: (text3) => navigator.clipboard.writeText(text3)
|
|
49155
50487
|
});
|
|
49156
50488
|
relocalizeHistory = () => HISTORY_VIEW.localize();
|
|
49157
50489
|
function helpSectionDeps() {
|
|
@@ -49252,14 +50584,16 @@ ${error2.stack}` : ""}`
|
|
|
49252
50584
|
function syncAppPanel() {
|
|
49253
50585
|
const tools = parseToolsOverlay(window.location.search) !== null;
|
|
49254
50586
|
const terminal = parseTerminalOverlay(window.location.search) !== null;
|
|
49255
|
-
const
|
|
50587
|
+
const search = parseSearchResultsOverlay(window.location.search) !== null;
|
|
50588
|
+
const open2 = tools || terminal || search;
|
|
49256
50589
|
const panel = document.getElementById("app-panel");
|
|
49257
50590
|
if (panel) {
|
|
49258
50591
|
panel.classList.toggle("app-panel-open", open2);
|
|
49259
50592
|
}
|
|
49260
50593
|
for (const [id, selected] of [
|
|
49261
50594
|
["#panel-tab-tools", tools],
|
|
49262
|
-
["#panel-tab-terminal", terminal]
|
|
50595
|
+
["#panel-tab-terminal", terminal],
|
|
50596
|
+
["#panel-tab-search", search]
|
|
49263
50597
|
]) {
|
|
49264
50598
|
const tab = document.querySelector(id);
|
|
49265
50599
|
if (!tab) continue;
|
|
@@ -49284,6 +50618,8 @@ ${error2.stack}` : ""}`
|
|
|
49284
50618
|
syncAppPanelLayout();
|
|
49285
50619
|
}
|
|
49286
50620
|
function closeAppPanel() {
|
|
50621
|
+
if (parseSearchResultsOverlay(window.location.search) !== null || SEARCH_RESULTS_VIEW.isOpen())
|
|
50622
|
+
closeSearchSheet();
|
|
49287
50623
|
if (parseToolsOverlay(window.location.search) !== null || TOOLS_VIEW.isOpen())
|
|
49288
50624
|
closeToolsSheet();
|
|
49289
50625
|
if (parseTerminalOverlay(window.location.search) !== null || TERMINAL_VIEW.isOpen())
|
|
@@ -49332,6 +50668,8 @@ ${error2.stack}` : ""}`
|
|
|
49332
50668
|
function openToolsSheet(tool) {
|
|
49333
50669
|
if (parseTerminalOverlay(window.location.search) !== null || TERMINAL_VIEW.isOpen())
|
|
49334
50670
|
closeTerminalSheet();
|
|
50671
|
+
if (parseSearchResultsOverlay(window.location.search) !== null || SEARCH_RESULTS_VIEW.isOpen())
|
|
50672
|
+
closeSearchSheet();
|
|
49335
50673
|
updateUrlForToolsOverlay(tool ?? TOOLS_VIEW.getActiveTool());
|
|
49336
50674
|
void TOOLS_VIEW.open(tool);
|
|
49337
50675
|
syncAppPanel();
|
|
@@ -49349,6 +50687,77 @@ ${error2.stack}` : ""}`
|
|
|
49349
50687
|
else if (!tool && open2) TOOLS_VIEW.close();
|
|
49350
50688
|
syncAppPanel();
|
|
49351
50689
|
}
|
|
50690
|
+
const SEARCH_RESULTS_VIEW = createSearchResultsView({
|
|
50691
|
+
$: (sel) => document.querySelector(sel),
|
|
50692
|
+
trackLoad,
|
|
50693
|
+
getLanguage: () => STATE.language,
|
|
50694
|
+
appendScopeParams,
|
|
50695
|
+
getRef: () => {
|
|
50696
|
+
const route = STATE.route;
|
|
50697
|
+
if (route.screen === "repo" || route.screen === "file")
|
|
50698
|
+
return route.ref || "worktree";
|
|
50699
|
+
return STATE.repoRef || "worktree";
|
|
50700
|
+
},
|
|
50701
|
+
getServerGeneration: () => SERVER_GENERATION,
|
|
50702
|
+
isAbortError: isAbortError3,
|
|
50703
|
+
getGrepRegex: () => APP_SETTINGS.grepRegex === true,
|
|
50704
|
+
getGrepCaseSensitive: () => APP_SETTINGS.grepCaseSensitive === true,
|
|
50705
|
+
getGrepWholeWord: () => APP_SETTINGS.grepWholeWord === true,
|
|
50706
|
+
getGrepHideTests: () => STATE.hideTests,
|
|
50707
|
+
persistGrepSettings: async (patch) => {
|
|
50708
|
+
await persistSettingsPatch(patch);
|
|
50709
|
+
if (patch.hideTests !== void 0) {
|
|
50710
|
+
STATE.hideTests = patch.hideTests;
|
|
50711
|
+
applyHideTests();
|
|
50712
|
+
}
|
|
50713
|
+
},
|
|
50714
|
+
openMatch: ({ path, line, hl }) => {
|
|
50715
|
+
const route = STATE.route;
|
|
50716
|
+
const ref = route.screen === "repo" || route.screen === "file" ? route.ref || "worktree" : STATE.repoRef || "worktree";
|
|
50717
|
+
setRoute({
|
|
50718
|
+
screen: "file",
|
|
50719
|
+
path,
|
|
50720
|
+
ref,
|
|
50721
|
+
view: "blob",
|
|
50722
|
+
line,
|
|
50723
|
+
...hl ? { hl } : {},
|
|
50724
|
+
range: currentRange()
|
|
50725
|
+
});
|
|
50726
|
+
void renderStandaloneSource({ path, ref });
|
|
50727
|
+
},
|
|
50728
|
+
onQueryChange: (query) => updateUrlForSearchResultsOverlay(query)
|
|
50729
|
+
});
|
|
50730
|
+
relocalizeSearchResults = () => SEARCH_RESULTS_VIEW.localize();
|
|
50731
|
+
function updateUrlForSearchResultsOverlay(query) {
|
|
50732
|
+
const current = window.location.pathname + window.location.search;
|
|
50733
|
+
const next = withSearchResultsOverlay(current, query);
|
|
50734
|
+
if (next !== current) {
|
|
50735
|
+
history.replaceState(history.state, "", next + window.location.hash);
|
|
50736
|
+
}
|
|
50737
|
+
syncHeaderMenu();
|
|
50738
|
+
}
|
|
50739
|
+
function openSearchSheet(query) {
|
|
50740
|
+
if (parseTerminalOverlay(window.location.search) !== null || TERMINAL_VIEW.isOpen())
|
|
50741
|
+
closeTerminalSheet();
|
|
50742
|
+
if (parseToolsOverlay(window.location.search) !== null || TOOLS_VIEW.isOpen())
|
|
50743
|
+
closeToolsSheet();
|
|
50744
|
+
updateUrlForSearchResultsOverlay(query ?? SEARCH_RESULTS_VIEW.getQuery());
|
|
50745
|
+
SEARCH_RESULTS_VIEW.open(query);
|
|
50746
|
+
syncAppPanel();
|
|
50747
|
+
}
|
|
50748
|
+
function closeSearchSheet() {
|
|
50749
|
+
SEARCH_RESULTS_VIEW.close();
|
|
50750
|
+
updateUrlForSearchResultsOverlay(null);
|
|
50751
|
+
syncAppPanel();
|
|
50752
|
+
}
|
|
50753
|
+
function syncSearchSheetFromUrl() {
|
|
50754
|
+
const query = parseSearchResultsOverlay(window.location.search);
|
|
50755
|
+
const open2 = SEARCH_RESULTS_VIEW.isOpen();
|
|
50756
|
+
if (query !== null && (!open2 || SEARCH_RESULTS_VIEW.getQuery() !== query))
|
|
50757
|
+
SEARCH_RESULTS_VIEW.open(query);
|
|
50758
|
+
else if (query === null && open2) SEARCH_RESULTS_VIEW.close();
|
|
50759
|
+
syncAppPanel();
|
|
50760
|
+
}
|
|
49352
50761
|
const TERMINAL_VIEW = createTerminalView({
|
|
49353
50762
|
$: (sel) => document.querySelector(sel),
|
|
49354
50763
|
trackLoad,
|
|
@@ -49377,6 +50786,8 @@ ${error2.stack}` : ""}`
|
|
|
49377
50786
|
function openTerminalSheet(id) {
|
|
49378
50787
|
if (parseToolsOverlay(window.location.search) !== null || TOOLS_VIEW.isOpen())
|
|
49379
50788
|
closeToolsSheet();
|
|
50789
|
+
if (parseSearchResultsOverlay(window.location.search) !== null || SEARCH_RESULTS_VIEW.isOpen())
|
|
50790
|
+
closeSearchSheet();
|
|
49380
50791
|
const target = id ?? TERMINAL_VIEW.getActiveTarget();
|
|
49381
50792
|
updateUrlForTerminalOverlay(target ?? "open");
|
|
49382
50793
|
void TERMINAL_VIEW.open(target);
|
|
@@ -49454,7 +50865,17 @@ ${error2.stack}` : ""}`
|
|
|
49454
50865
|
getFrom: () => STATE.from,
|
|
49455
50866
|
getTo: () => STATE.to,
|
|
49456
50867
|
getRepoRef: () => STATE.repoRef,
|
|
49457
|
-
getRoute: () => STATE.route
|
|
50868
|
+
getRoute: () => STATE.route,
|
|
50869
|
+
getRecentRefs: () => APP_SETTINGS.recentRefs || [],
|
|
50870
|
+
rememberRecentRef: (ref) => {
|
|
50871
|
+
const current = APP_SETTINGS.recentRefs || [];
|
|
50872
|
+
const next = rememberPaletteSelection(current, ref).slice(
|
|
50873
|
+
-MAX_RECENT_REFS
|
|
50874
|
+
);
|
|
50875
|
+
if (next.join("\0") === current.join("\0")) return;
|
|
50876
|
+
patchSettings({ recentRefs: next });
|
|
50877
|
+
},
|
|
50878
|
+
recentRefTitle: () => uiText().global.recentRef
|
|
49458
50879
|
});
|
|
49459
50880
|
if (REF_PICKER) {
|
|
49460
50881
|
const historyRefInput = document.querySelector("#history-ref");
|
|
@@ -49511,6 +50932,7 @@ ${error2.stack}` : ""}`
|
|
|
49511
50932
|
syncDoctorSheetFromUrl();
|
|
49512
50933
|
syncToolsSheetFromUrl();
|
|
49513
50934
|
syncTerminalSheetFromUrl();
|
|
50935
|
+
syncSearchSheetFromUrl();
|
|
49514
50936
|
if (isSameBlobFileRoute(previousRoute, STATE.route) && routeBlobPreview(previousRoute) !== routeBlobPreview(STATE.route) && switchSourceTab(routeBlobPreview(STATE.route) ? "preview" : "code", {
|
|
49515
50937
|
updateRoute: false
|
|
49516
50938
|
})) {
|