@youtyan/code-viewer 0.6.0 → 0.6.1
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 +14 -11
- package/dist/code-viewer.js +411 -65
- package/package.json +1 -1
- package/skills/code-viewer-snapshot/SKILL.md +6 -0
- package/web/app.js +1104 -564
- package/web/index.html +7 -3
- package/web/style.css +153 -5
package/web/app.js
CHANGED
|
@@ -21,6 +21,122 @@
|
|
|
21
21
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
// web-src/core/file-path-copy.ts
|
|
25
|
+
function filePathClipboardText(path) {
|
|
26
|
+
return path || "";
|
|
27
|
+
}
|
|
28
|
+
function fileNameClipboardText(path) {
|
|
29
|
+
if (!path)
|
|
30
|
+
return "";
|
|
31
|
+
const parts = path.split("/").filter(Boolean);
|
|
32
|
+
return parts[parts.length - 1] || "";
|
|
33
|
+
}
|
|
34
|
+
function fileReferenceClipboardText(path, start, end) {
|
|
35
|
+
if (!path)
|
|
36
|
+
return "";
|
|
37
|
+
const a = Math.max(1, Math.floor(Math.min(start, end)));
|
|
38
|
+
const b = Math.max(1, Math.floor(Math.max(start, end)));
|
|
39
|
+
return a === b ? `@${path}#${a}` : `@${path}#${a}-${b}`;
|
|
40
|
+
}
|
|
41
|
+
function fileReferenceWithCodeClipboardText(path, start, end, lines, lang) {
|
|
42
|
+
const ref = fileReferenceClipboardText(path, start, end);
|
|
43
|
+
if (!ref)
|
|
44
|
+
return "";
|
|
45
|
+
if (!lines || lines.length === 0)
|
|
46
|
+
return ref;
|
|
47
|
+
const fence = (lang || "").trim();
|
|
48
|
+
return `${ref}
|
|
49
|
+
|
|
50
|
+
\`\`\`${fence}
|
|
51
|
+
${lines.join(`
|
|
52
|
+
`)}
|
|
53
|
+
\`\`\``;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// web-src/core/ai-context-copy.ts
|
|
57
|
+
var AI_CONTEXT_LARGE_SELECTION_LINE_THRESHOLD = 300;
|
|
58
|
+
function lineRange(line) {
|
|
59
|
+
return typeof line === "number" ? { start: line, end: line } : { start: line.start, end: line.end };
|
|
60
|
+
}
|
|
61
|
+
function resolveSelectionTarget(route) {
|
|
62
|
+
const path = route.screen === "file" || route.screen === "diff" ? route.path : undefined;
|
|
63
|
+
const line = route.screen === "file" || route.screen === "diff" ? route.line : undefined;
|
|
64
|
+
if (!path || !line)
|
|
65
|
+
return null;
|
|
66
|
+
return { path, ...lineRange(line) };
|
|
67
|
+
}
|
|
68
|
+
function activePath(route) {
|
|
69
|
+
if (route.screen === "file")
|
|
70
|
+
return route.path;
|
|
71
|
+
if (route.screen === "repo")
|
|
72
|
+
return route.path || undefined;
|
|
73
|
+
if (route.screen === "diff")
|
|
74
|
+
return route.path;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
function commitOrRefSuffix(route) {
|
|
78
|
+
const commit = "commit" in route ? route.commit : undefined;
|
|
79
|
+
if (commit)
|
|
80
|
+
return ` (commit: ${commit})`;
|
|
81
|
+
const ref = "ref" in route ? route.ref : undefined;
|
|
82
|
+
if (ref && ref !== "worktree" && ref !== "HEAD")
|
|
83
|
+
return ` (ref: ${ref})`;
|
|
84
|
+
return "";
|
|
85
|
+
}
|
|
86
|
+
function referenceLine(route, code) {
|
|
87
|
+
const target = resolveSelectionTarget(route);
|
|
88
|
+
const path = target?.path ?? activePath(route);
|
|
89
|
+
if (!path)
|
|
90
|
+
return "";
|
|
91
|
+
const suffix = commitOrRefSuffix(route);
|
|
92
|
+
if (!target)
|
|
93
|
+
return `@${path}${suffix}`;
|
|
94
|
+
const ref = fileReferenceClipboardText(target.path, target.start, target.end);
|
|
95
|
+
const withSuffix = `${ref}${suffix}`;
|
|
96
|
+
const lines = code?.lines ?? [];
|
|
97
|
+
if (lines.length === 0)
|
|
98
|
+
return withSuffix;
|
|
99
|
+
const lang = (code?.lang || "").trim();
|
|
100
|
+
return `${withSuffix}
|
|
101
|
+
|
|
102
|
+
\`\`\`${lang}
|
|
103
|
+
${lines.join(`
|
|
104
|
+
`)}
|
|
105
|
+
\`\`\``;
|
|
106
|
+
}
|
|
107
|
+
function historyLine(route) {
|
|
108
|
+
if (!route.commit)
|
|
109
|
+
return "";
|
|
110
|
+
const ref = route.ref && route.ref !== "worktree" && route.ref !== "HEAD" ? ` (ref: ${route.ref})` : "";
|
|
111
|
+
return `commit: ${route.commit}${ref}`;
|
|
112
|
+
}
|
|
113
|
+
function databaseLine(route) {
|
|
114
|
+
const parts = [];
|
|
115
|
+
if (route.db)
|
|
116
|
+
parts.push(`db=${route.db}`);
|
|
117
|
+
if (route.schema)
|
|
118
|
+
parts.push(`schema=${route.schema}`);
|
|
119
|
+
if (route.table)
|
|
120
|
+
parts.push(`table=${route.table}`);
|
|
121
|
+
if (route.tab)
|
|
122
|
+
parts.push(`tab=${route.tab}`);
|
|
123
|
+
if (route.diffBefore && route.diffAfter) {
|
|
124
|
+
parts.push(`snapshot=${route.diffBefore}..${route.diffAfter}`);
|
|
125
|
+
}
|
|
126
|
+
return parts.length > 0 ? `database: ${parts.join(", ")}` : "";
|
|
127
|
+
}
|
|
128
|
+
function aiContextClipboardText(snapshot) {
|
|
129
|
+
const { route } = snapshot;
|
|
130
|
+
if (route.screen === "database")
|
|
131
|
+
return databaseLine(route);
|
|
132
|
+
if (route.screen === "history")
|
|
133
|
+
return historyLine(route);
|
|
134
|
+
if (route.screen === "diff" && !route.path) {
|
|
135
|
+
return `Diff: ${snapshot.diffFrom}..${snapshot.diffTo}`;
|
|
136
|
+
}
|
|
137
|
+
return referenceLine(route, snapshot.selectionCode);
|
|
138
|
+
}
|
|
139
|
+
|
|
24
140
|
// web-src/core/catch-up.ts
|
|
25
141
|
function shouldAutoLoadForRoute(route, options = {}) {
|
|
26
142
|
if (route.screen === "history")
|
|
@@ -290,6 +406,9 @@
|
|
|
290
406
|
return '<svg class="octicon ' + className + '" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true">' + pathList.map((path) => `<path fill="currentColor" d="${path}"></path>`).join("") + "</svg>";
|
|
291
407
|
}
|
|
292
408
|
var PENCIL_16_PATH = "M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.609Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z";
|
|
409
|
+
var COMMENT_DISCUSSION_16_PATH = "M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z";
|
|
410
|
+
var PULSE_16_PATH = "M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z";
|
|
411
|
+
var MOON_16_PATH = "M9.598 1.591a.749.749 0 0 1 .785-.175 7.001 7.001 0 1 1-8.967 8.967.75.75 0 0 1 .961-.96 5.5 5.5 0 0 0 7.046-7.046.75.75 0 0 1 .175-.786Zm1.616 1.945a7 7 0 0 1-7.678 7.678 5.499 5.499 0 1 0 7.678-7.678Z";
|
|
293
412
|
|
|
294
413
|
// web-src/core/keyboard.ts
|
|
295
414
|
function isImeComposing(event) {
|
|
@@ -401,7 +520,9 @@
|
|
|
401
520
|
{ action: "layout-unified", key: "u" },
|
|
402
521
|
{ action: "layout-split", key: "s" },
|
|
403
522
|
{ action: "toggle-theme", key: "t" },
|
|
404
|
-
{ action: "open-help", key: "?", shift: true }
|
|
523
|
+
{ action: "open-help", key: "?", shift: true },
|
|
524
|
+
{ action: "copy-ai-context", key: "y" },
|
|
525
|
+
{ action: "copy-ai-context-with-code", key: "y", shift: true }
|
|
405
526
|
];
|
|
406
527
|
function resolveKeymapAction(event, context) {
|
|
407
528
|
const key = event.key.toLowerCase();
|
|
@@ -792,6 +913,486 @@
|
|
|
792
913
|
return qs ? `${base}?${qs}` : base;
|
|
793
914
|
}
|
|
794
915
|
|
|
916
|
+
// web-src/views/media-embed.ts
|
|
917
|
+
var MEDIA_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico|mp4|webm|mov|mp3|wav|ogg|flac|m4a|aac|opus)(\?.*)?$/i;
|
|
918
|
+
var IMAGE_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)(\?.*)?$/i;
|
|
919
|
+
var VIDEO_RE = /\.(mp4|webm|mov)$/i;
|
|
920
|
+
var AUDIO_RE = /\.(mp3|wav|ogg|flac|m4a|aac|opus)$/i;
|
|
921
|
+
function isMedia(p) {
|
|
922
|
+
return MEDIA_RE.test(p);
|
|
923
|
+
}
|
|
924
|
+
function isImage(p) {
|
|
925
|
+
return IMAGE_RE.test(p);
|
|
926
|
+
}
|
|
927
|
+
function isVideo(p) {
|
|
928
|
+
return VIDEO_RE.test(p);
|
|
929
|
+
}
|
|
930
|
+
function isAudio(p) {
|
|
931
|
+
return AUDIO_RE.test(p);
|
|
932
|
+
}
|
|
933
|
+
function fileURL(path, ref) {
|
|
934
|
+
return `/_file?path=${encodeURIComponent(path)}&ref=${ref}`;
|
|
935
|
+
}
|
|
936
|
+
function mediaTag(path, ref) {
|
|
937
|
+
const url = fileURL(path, ref);
|
|
938
|
+
if (isVideo(path)) {
|
|
939
|
+
return `<video src="${url}" controls preload="metadata"></video>`;
|
|
940
|
+
}
|
|
941
|
+
if (isAudio(path)) {
|
|
942
|
+
return `<audio src="${url}" controls preload="metadata"></audio>`;
|
|
943
|
+
}
|
|
944
|
+
return `<img src="${url}" alt="" loading="lazy">`;
|
|
945
|
+
}
|
|
946
|
+
function enhanceMediaCard(file, card) {
|
|
947
|
+
const path = file.path;
|
|
948
|
+
if (!file.media_kind && !isMedia(path))
|
|
949
|
+
return;
|
|
950
|
+
const wrapper = card.querySelector(".d2h-file-wrapper");
|
|
951
|
+
if (!wrapper)
|
|
952
|
+
return;
|
|
953
|
+
const body = wrapper.querySelector(".d2h-files-diff") || wrapper.querySelector(".d2h-file-diff");
|
|
954
|
+
if (!body)
|
|
955
|
+
return;
|
|
956
|
+
const container = document.createElement("div");
|
|
957
|
+
container.className = "gdp-media";
|
|
958
|
+
let leftHTML;
|
|
959
|
+
let rightHTML;
|
|
960
|
+
if (file.status === "A") {
|
|
961
|
+
leftHTML = '<div class="media-empty">Not in HEAD</div>';
|
|
962
|
+
rightHTML = mediaTag(path, "worktree");
|
|
963
|
+
} else if (file.status === "D") {
|
|
964
|
+
leftHTML = mediaTag(path, "HEAD");
|
|
965
|
+
rightHTML = '<div class="media-empty">Deleted</div>';
|
|
966
|
+
} else {
|
|
967
|
+
leftHTML = mediaTag(path, "HEAD");
|
|
968
|
+
rightHTML = mediaTag(path, "worktree");
|
|
969
|
+
}
|
|
970
|
+
container.innerHTML = '<div class="media-side"><div class="media-label del">Before</div>' + leftHTML + "</div>" + '<div class="media-side"><div class="media-label add">After</div>' + rightHTML + "</div>";
|
|
971
|
+
body.replaceWith(container);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// web-src/core/source-meta.ts
|
|
975
|
+
var SOURCE_SHIKI_LANG_ALIASES = {
|
|
976
|
+
makefile: "make",
|
|
977
|
+
objectivec: "c",
|
|
978
|
+
"objective-c": "c",
|
|
979
|
+
"objective-cpp": "cpp",
|
|
980
|
+
starlark: "python"
|
|
981
|
+
};
|
|
982
|
+
function normalizeSourceShikiLang(lang) {
|
|
983
|
+
if (!lang)
|
|
984
|
+
return null;
|
|
985
|
+
return SOURCE_SHIKI_LANG_ALIASES[lang] || lang;
|
|
986
|
+
}
|
|
987
|
+
function isPreviewableSource(path) {
|
|
988
|
+
return /\.(md|markdown|mdown|mkdn|mdx|html|htm)$/i.test(path);
|
|
989
|
+
}
|
|
990
|
+
function sourceInternalPathKind(path) {
|
|
991
|
+
for (const part of path.split(/[\\/]+/)) {
|
|
992
|
+
const lower = part.toLowerCase();
|
|
993
|
+
if (lower === ".code-viewer")
|
|
994
|
+
return "code-viewer";
|
|
995
|
+
if (lower === ".git")
|
|
996
|
+
return "git";
|
|
997
|
+
}
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
function sourcePreviewKind(path) {
|
|
1001
|
+
if (/\.(md|markdown|mdown|mkdn|mdx)$/i.test(path))
|
|
1002
|
+
return "markdown";
|
|
1003
|
+
if (/\.(html|htm)$/i.test(path))
|
|
1004
|
+
return "html";
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
var EXT_TO_LANG = {
|
|
1008
|
+
js: "javascript",
|
|
1009
|
+
mjs: "javascript",
|
|
1010
|
+
cjs: "javascript",
|
|
1011
|
+
ts: "typescript",
|
|
1012
|
+
tsx: "typescript",
|
|
1013
|
+
jsx: "javascript",
|
|
1014
|
+
py: "python",
|
|
1015
|
+
rb: "ruby",
|
|
1016
|
+
go: "go",
|
|
1017
|
+
rs: "rust",
|
|
1018
|
+
java: "java",
|
|
1019
|
+
kt: "kotlin",
|
|
1020
|
+
swift: "swift",
|
|
1021
|
+
c: "c",
|
|
1022
|
+
h: "c",
|
|
1023
|
+
cc: "cpp",
|
|
1024
|
+
cpp: "cpp",
|
|
1025
|
+
hpp: "cpp",
|
|
1026
|
+
cs: "csharp",
|
|
1027
|
+
php: "php",
|
|
1028
|
+
lua: "lua",
|
|
1029
|
+
sh: "bash",
|
|
1030
|
+
bash: "bash",
|
|
1031
|
+
zsh: "bash",
|
|
1032
|
+
fish: "bash",
|
|
1033
|
+
sql: "sql",
|
|
1034
|
+
json: "json",
|
|
1035
|
+
yaml: "yaml",
|
|
1036
|
+
yml: "yaml",
|
|
1037
|
+
toml: "toml",
|
|
1038
|
+
tf: "terraform",
|
|
1039
|
+
tfvars: "terraform",
|
|
1040
|
+
hcl: "terraform",
|
|
1041
|
+
xml: "xml",
|
|
1042
|
+
html: "xml",
|
|
1043
|
+
vue: "xml",
|
|
1044
|
+
css: "css",
|
|
1045
|
+
scss: "scss",
|
|
1046
|
+
md: "markdown",
|
|
1047
|
+
dockerfile: "dockerfile",
|
|
1048
|
+
proto: "protobuf",
|
|
1049
|
+
gradle: "gradle",
|
|
1050
|
+
properties: "properties",
|
|
1051
|
+
patch: "diff",
|
|
1052
|
+
diff: "diff",
|
|
1053
|
+
nix: "nix",
|
|
1054
|
+
cue: "cue",
|
|
1055
|
+
rego: "rego",
|
|
1056
|
+
bicep: "bicep",
|
|
1057
|
+
bazel: "starlark",
|
|
1058
|
+
bzl: "starlark",
|
|
1059
|
+
cmake: "cmake",
|
|
1060
|
+
groovy: "groovy",
|
|
1061
|
+
dart: "dart",
|
|
1062
|
+
scala: "scala",
|
|
1063
|
+
clj: "clojure",
|
|
1064
|
+
cljs: "clojure",
|
|
1065
|
+
cljc: "clojure",
|
|
1066
|
+
edn: "clojure",
|
|
1067
|
+
ex: "elixir",
|
|
1068
|
+
exs: "elixir",
|
|
1069
|
+
erl: "erlang",
|
|
1070
|
+
hrl: "erlang",
|
|
1071
|
+
hs: "haskell",
|
|
1072
|
+
lhs: "haskell",
|
|
1073
|
+
ml: "ocaml",
|
|
1074
|
+
mli: "ocaml",
|
|
1075
|
+
jl: "julia",
|
|
1076
|
+
r: "r",
|
|
1077
|
+
rmd: "r",
|
|
1078
|
+
pl: "perl",
|
|
1079
|
+
pm: "perl",
|
|
1080
|
+
tcl: "tcl",
|
|
1081
|
+
vim: "vim",
|
|
1082
|
+
f: "fortran",
|
|
1083
|
+
f90: "fortran",
|
|
1084
|
+
m: "objective-c",
|
|
1085
|
+
mm: "objective-cpp",
|
|
1086
|
+
tex: "tex",
|
|
1087
|
+
bib: "bibtex",
|
|
1088
|
+
rst: "rst"
|
|
1089
|
+
};
|
|
1090
|
+
var TEXT_SOURCE_EXTENSIONS = new Set([
|
|
1091
|
+
...Object.keys(EXT_TO_LANG),
|
|
1092
|
+
"txt",
|
|
1093
|
+
"md",
|
|
1094
|
+
"markdown",
|
|
1095
|
+
"mdown",
|
|
1096
|
+
"mkdn",
|
|
1097
|
+
"mdx",
|
|
1098
|
+
"json",
|
|
1099
|
+
"jsonc",
|
|
1100
|
+
"csv",
|
|
1101
|
+
"tsv",
|
|
1102
|
+
"yaml",
|
|
1103
|
+
"yml",
|
|
1104
|
+
"toml",
|
|
1105
|
+
"hcl",
|
|
1106
|
+
"tf",
|
|
1107
|
+
"tfvars",
|
|
1108
|
+
"tfstate",
|
|
1109
|
+
"xml",
|
|
1110
|
+
"html",
|
|
1111
|
+
"htm",
|
|
1112
|
+
"css",
|
|
1113
|
+
"scss",
|
|
1114
|
+
"sass",
|
|
1115
|
+
"less",
|
|
1116
|
+
"js",
|
|
1117
|
+
"jsx",
|
|
1118
|
+
"mjs",
|
|
1119
|
+
"cjs",
|
|
1120
|
+
"ts",
|
|
1121
|
+
"tsx",
|
|
1122
|
+
"mts",
|
|
1123
|
+
"cts",
|
|
1124
|
+
"vue",
|
|
1125
|
+
"svelte",
|
|
1126
|
+
"astro",
|
|
1127
|
+
"rs",
|
|
1128
|
+
"go",
|
|
1129
|
+
"py",
|
|
1130
|
+
"rb",
|
|
1131
|
+
"php",
|
|
1132
|
+
"java",
|
|
1133
|
+
"kt",
|
|
1134
|
+
"kts",
|
|
1135
|
+
"c",
|
|
1136
|
+
"cc",
|
|
1137
|
+
"cpp",
|
|
1138
|
+
"cxx",
|
|
1139
|
+
"h",
|
|
1140
|
+
"hpp",
|
|
1141
|
+
"cs",
|
|
1142
|
+
"swift",
|
|
1143
|
+
"sh",
|
|
1144
|
+
"bash",
|
|
1145
|
+
"zsh",
|
|
1146
|
+
"fish",
|
|
1147
|
+
"ps1",
|
|
1148
|
+
"sql",
|
|
1149
|
+
"graphql",
|
|
1150
|
+
"graphqls",
|
|
1151
|
+
"gql",
|
|
1152
|
+
"ini",
|
|
1153
|
+
"conf",
|
|
1154
|
+
"env",
|
|
1155
|
+
"properties",
|
|
1156
|
+
"rules",
|
|
1157
|
+
"rule",
|
|
1158
|
+
"prompt",
|
|
1159
|
+
"prompts",
|
|
1160
|
+
"instructions",
|
|
1161
|
+
"gitignore",
|
|
1162
|
+
"dockerignore",
|
|
1163
|
+
"editorconfig",
|
|
1164
|
+
"lock",
|
|
1165
|
+
"log",
|
|
1166
|
+
"patch",
|
|
1167
|
+
"diff",
|
|
1168
|
+
"sum",
|
|
1169
|
+
"mk",
|
|
1170
|
+
"proto",
|
|
1171
|
+
"thrift",
|
|
1172
|
+
"prisma",
|
|
1173
|
+
"gradle",
|
|
1174
|
+
"cmake",
|
|
1175
|
+
"nix",
|
|
1176
|
+
"cue",
|
|
1177
|
+
"rego",
|
|
1178
|
+
"bicep",
|
|
1179
|
+
"bazel",
|
|
1180
|
+
"bzl",
|
|
1181
|
+
"dart",
|
|
1182
|
+
"scala",
|
|
1183
|
+
"clj",
|
|
1184
|
+
"cljs",
|
|
1185
|
+
"cljc",
|
|
1186
|
+
"edn",
|
|
1187
|
+
"ex",
|
|
1188
|
+
"exs",
|
|
1189
|
+
"erl",
|
|
1190
|
+
"hrl",
|
|
1191
|
+
"hs",
|
|
1192
|
+
"lhs",
|
|
1193
|
+
"ml",
|
|
1194
|
+
"mli",
|
|
1195
|
+
"jl",
|
|
1196
|
+
"r",
|
|
1197
|
+
"rmd",
|
|
1198
|
+
"pl",
|
|
1199
|
+
"pm",
|
|
1200
|
+
"tcl",
|
|
1201
|
+
"vim",
|
|
1202
|
+
"groovy",
|
|
1203
|
+
"f",
|
|
1204
|
+
"f90",
|
|
1205
|
+
"m",
|
|
1206
|
+
"mm",
|
|
1207
|
+
"pas",
|
|
1208
|
+
"tex",
|
|
1209
|
+
"bib",
|
|
1210
|
+
"rst",
|
|
1211
|
+
"adoc",
|
|
1212
|
+
"org",
|
|
1213
|
+
"ipynb",
|
|
1214
|
+
"ejs",
|
|
1215
|
+
"hbs",
|
|
1216
|
+
"mustache",
|
|
1217
|
+
"liquid",
|
|
1218
|
+
"pug"
|
|
1219
|
+
]);
|
|
1220
|
+
var TEXT_SOURCE_FILENAMES = new Set([
|
|
1221
|
+
"readme",
|
|
1222
|
+
"license",
|
|
1223
|
+
"copying",
|
|
1224
|
+
"authors",
|
|
1225
|
+
"contributors",
|
|
1226
|
+
"notice",
|
|
1227
|
+
"changelog",
|
|
1228
|
+
"todo",
|
|
1229
|
+
"manifest",
|
|
1230
|
+
"version",
|
|
1231
|
+
"codeowners",
|
|
1232
|
+
"go.mod",
|
|
1233
|
+
"build.bazel",
|
|
1234
|
+
"workspace.bazel",
|
|
1235
|
+
"module.bazel",
|
|
1236
|
+
"gemfile",
|
|
1237
|
+
"rakefile",
|
|
1238
|
+
"procfile",
|
|
1239
|
+
"brewfile",
|
|
1240
|
+
"gnumakefile",
|
|
1241
|
+
"bsdmakefile",
|
|
1242
|
+
".gitattributes",
|
|
1243
|
+
".gitmodules",
|
|
1244
|
+
".npmrc",
|
|
1245
|
+
".nvmrc",
|
|
1246
|
+
".yarnrc",
|
|
1247
|
+
".prettierrc",
|
|
1248
|
+
".eslintrc",
|
|
1249
|
+
".babelrc",
|
|
1250
|
+
".stylelintrc"
|
|
1251
|
+
]);
|
|
1252
|
+
var FILENAME_TO_LANG = {
|
|
1253
|
+
dockerfile: "dockerfile",
|
|
1254
|
+
makefile: "makefile",
|
|
1255
|
+
gnumakefile: "makefile",
|
|
1256
|
+
bsdmakefile: "makefile",
|
|
1257
|
+
"go.mod": "go",
|
|
1258
|
+
"build.bazel": "starlark",
|
|
1259
|
+
"workspace.bazel": "starlark",
|
|
1260
|
+
"module.bazel": "starlark"
|
|
1261
|
+
};
|
|
1262
|
+
function sourceFileName(path) {
|
|
1263
|
+
return (path.split("/").pop() || path).toLowerCase();
|
|
1264
|
+
}
|
|
1265
|
+
function sourceFileExtension(name) {
|
|
1266
|
+
const index = name.lastIndexOf(".");
|
|
1267
|
+
return index >= 0 ? name.slice(index + 1) : "";
|
|
1268
|
+
}
|
|
1269
|
+
function isDockerfileName(name) {
|
|
1270
|
+
return /^dockerfile(?:[.-].+)?$/i.test(name);
|
|
1271
|
+
}
|
|
1272
|
+
function isMakefileName(name) {
|
|
1273
|
+
return /^makefile(?:[.-].+)?$/i.test(name);
|
|
1274
|
+
}
|
|
1275
|
+
function isDotenvName(name) {
|
|
1276
|
+
return /^(?:\.?env|.*\.env)(?:[.-].+)?$/i.test(name);
|
|
1277
|
+
}
|
|
1278
|
+
function sourceDisplayKind(path) {
|
|
1279
|
+
if (isVideo(path))
|
|
1280
|
+
return "video";
|
|
1281
|
+
if (isAudio(path))
|
|
1282
|
+
return "audio";
|
|
1283
|
+
if (isImage(path))
|
|
1284
|
+
return "image";
|
|
1285
|
+
if (/\.pdf$/i.test(path))
|
|
1286
|
+
return "pdf";
|
|
1287
|
+
const name = sourceFileName(path);
|
|
1288
|
+
const ext = sourceFileExtension(name);
|
|
1289
|
+
if (TEXT_SOURCE_EXTENSIONS.has(ext))
|
|
1290
|
+
return "text";
|
|
1291
|
+
if (TEXT_SOURCE_FILENAMES.has(name))
|
|
1292
|
+
return "text";
|
|
1293
|
+
if (isDotenvName(name))
|
|
1294
|
+
return "text";
|
|
1295
|
+
if (isDockerfileName(name) || isMakefileName(name))
|
|
1296
|
+
return "text";
|
|
1297
|
+
return "unsupported";
|
|
1298
|
+
}
|
|
1299
|
+
function isLikelyTextBytes(bytes) {
|
|
1300
|
+
if (bytes.length === 0)
|
|
1301
|
+
return true;
|
|
1302
|
+
if (bytes.includes(0))
|
|
1303
|
+
return false;
|
|
1304
|
+
let text = "";
|
|
1305
|
+
try {
|
|
1306
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
1307
|
+
} catch {
|
|
1308
|
+
return false;
|
|
1309
|
+
}
|
|
1310
|
+
if (!text)
|
|
1311
|
+
return true;
|
|
1312
|
+
let controlCount = 0;
|
|
1313
|
+
for (const char of text) {
|
|
1314
|
+
const code = char.charCodeAt(0);
|
|
1315
|
+
const allowed = code === 9 || code === 10 || code === 12 || code === 13 || code >= 32;
|
|
1316
|
+
if (!allowed)
|
|
1317
|
+
controlCount++;
|
|
1318
|
+
}
|
|
1319
|
+
return controlCount / text.length <= 0.02;
|
|
1320
|
+
}
|
|
1321
|
+
function formatBytes(bytes) {
|
|
1322
|
+
if (!Number.isFinite(bytes) || bytes < 0)
|
|
1323
|
+
return "";
|
|
1324
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
1325
|
+
let value = bytes;
|
|
1326
|
+
let unit = 0;
|
|
1327
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
1328
|
+
value /= 1024;
|
|
1329
|
+
unit++;
|
|
1330
|
+
}
|
|
1331
|
+
return (unit === 0 ? String(value) : value.toFixed(value >= 10 ? 1 : 2).replace(/\.0+$/, "")) + " " + units[unit];
|
|
1332
|
+
}
|
|
1333
|
+
function formatFileDate(value) {
|
|
1334
|
+
if (!value)
|
|
1335
|
+
return "";
|
|
1336
|
+
const date = new Date(value);
|
|
1337
|
+
if (Number.isNaN(date.getTime()))
|
|
1338
|
+
return "";
|
|
1339
|
+
return date.toLocaleString(undefined, {
|
|
1340
|
+
year: "numeric",
|
|
1341
|
+
month: "short",
|
|
1342
|
+
day: "numeric",
|
|
1343
|
+
hour: "2-digit",
|
|
1344
|
+
minute: "2-digit"
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
function humanFileKind(path, mime, fallback) {
|
|
1348
|
+
const ext = (path.split(".").pop() || "").toLowerCase();
|
|
1349
|
+
if (ext === "png")
|
|
1350
|
+
return "PNG image";
|
|
1351
|
+
if (ext === "jpg" || ext === "jpeg")
|
|
1352
|
+
return "JPEG image";
|
|
1353
|
+
if (ext === "gif")
|
|
1354
|
+
return "GIF image";
|
|
1355
|
+
if (ext === "webp")
|
|
1356
|
+
return "WebP image";
|
|
1357
|
+
if (ext === "svg")
|
|
1358
|
+
return "SVG image";
|
|
1359
|
+
if (ext === "pdf")
|
|
1360
|
+
return "PDF document";
|
|
1361
|
+
if (ext === "zip")
|
|
1362
|
+
return "ZIP archive";
|
|
1363
|
+
if (ext === "mp4")
|
|
1364
|
+
return "MP4 video";
|
|
1365
|
+
if (ext === "webm")
|
|
1366
|
+
return "WebM video";
|
|
1367
|
+
if (ext === "mp3")
|
|
1368
|
+
return "MP3 audio";
|
|
1369
|
+
if (ext === "wav")
|
|
1370
|
+
return "WAV audio";
|
|
1371
|
+
if (ext === "ogg")
|
|
1372
|
+
return "Ogg audio";
|
|
1373
|
+
if (ext === "flac")
|
|
1374
|
+
return "FLAC audio";
|
|
1375
|
+
if (ext === "m4a")
|
|
1376
|
+
return "M4A audio";
|
|
1377
|
+
if (ext === "aac")
|
|
1378
|
+
return "AAC audio";
|
|
1379
|
+
if (ext === "opus")
|
|
1380
|
+
return "Opus audio";
|
|
1381
|
+
if (ext === "mid" || ext === "midi")
|
|
1382
|
+
return "MIDI file";
|
|
1383
|
+
if (mime?.startsWith("image/"))
|
|
1384
|
+
return "Image";
|
|
1385
|
+
if (mime?.startsWith("video/"))
|
|
1386
|
+
return "Video";
|
|
1387
|
+
if (mime?.startsWith("audio/"))
|
|
1388
|
+
return "Audio";
|
|
1389
|
+
if (mime === "application/pdf")
|
|
1390
|
+
return "PDF document";
|
|
1391
|
+
if (fallback === "unsupported file")
|
|
1392
|
+
return "Binary file";
|
|
1393
|
+
return fallback.charAt(0).toUpperCase() + fallback.slice(1);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
795
1396
|
// web-src/core/annotation-player-core.ts
|
|
796
1397
|
function createAnnotationPlayerCore(deps) {
|
|
797
1398
|
let status = "idle";
|
|
@@ -7619,6 +8220,7 @@ ${frontmatter.yaml}
|
|
|
7619
8220
|
document.body.classList.remove("query-history-panel-open");
|
|
7620
8221
|
}
|
|
7621
8222
|
deps.setAnnotationPanelOpenState(open);
|
|
8223
|
+
applyInlineAnnotations();
|
|
7622
8224
|
}
|
|
7623
8225
|
function annotationLineTarget(entry) {
|
|
7624
8226
|
if (!entry.line)
|
|
@@ -7783,6 +8385,10 @@ ${frontmatter.yaml}
|
|
|
7783
8385
|
row.remove();
|
|
7784
8386
|
});
|
|
7785
8387
|
const session = ANNOTATIONS.sessions.find((s2) => s2.id === activeSessionId);
|
|
8388
|
+
if (!annotationPanel.hidden) {
|
|
8389
|
+
applyDatabaseAnnotations(undefined);
|
|
8390
|
+
return;
|
|
8391
|
+
}
|
|
7786
8392
|
applyDatabaseAnnotations(session);
|
|
7787
8393
|
if (!session)
|
|
7788
8394
|
return;
|
|
@@ -7964,7 +8570,7 @@ ${frontmatter.yaml}
|
|
|
7964
8570
|
} catch {}
|
|
7965
8571
|
await refreshAnnotations();
|
|
7966
8572
|
}
|
|
7967
|
-
function
|
|
8573
|
+
function annotationTimeLabel(createdAt) {
|
|
7968
8574
|
const date = new Date(createdAt);
|
|
7969
8575
|
if (Number.isNaN(date.getTime()))
|
|
7970
8576
|
return "";
|
|
@@ -7993,6 +8599,9 @@ ${frontmatter.yaml}
|
|
|
7993
8599
|
}
|
|
7994
8600
|
function openDatabaseCaptureForm(target) {
|
|
7995
8601
|
$("#annotation-detail-session").textContent = activeSessionId || "Datastore annotations";
|
|
8602
|
+
const detailTime = $("#annotation-detail-time");
|
|
8603
|
+
detailTime.textContent = "";
|
|
8604
|
+
detailTime.title = "";
|
|
7996
8605
|
$("#annotation-detail-step").textContent = "new";
|
|
7997
8606
|
const location2 = $("#annotation-detail-location");
|
|
7998
8607
|
location2.textContent = databaseAnnotationTitle(target);
|
|
@@ -8103,7 +8712,7 @@ ${frontmatter.yaml}
|
|
|
8103
8712
|
title.title = session.created_at;
|
|
8104
8713
|
const time = document.createElement("span");
|
|
8105
8714
|
time.className = "annotation-session-time";
|
|
8106
|
-
time.textContent =
|
|
8715
|
+
time.textContent = annotationTimeLabel(session.created_at);
|
|
8107
8716
|
time.title = session.created_at;
|
|
8108
8717
|
title.addEventListener("click", () => {
|
|
8109
8718
|
setActiveSession(session.id === activeSessionId ? null : session.id);
|
|
@@ -8158,6 +8767,14 @@ ${frontmatter.yaml}
|
|
|
8158
8767
|
summary.className = "annotation-entry-summary";
|
|
8159
8768
|
summary.textContent = annotationEntrySummary(entry);
|
|
8160
8769
|
open.append(location2, summary);
|
|
8770
|
+
const entryTimeLabel = annotationTimeLabel(entry.created_at);
|
|
8771
|
+
if (entryTimeLabel) {
|
|
8772
|
+
const time2 = document.createElement("span");
|
|
8773
|
+
time2.className = "annotation-entry-time";
|
|
8774
|
+
time2.textContent = entryTimeLabel;
|
|
8775
|
+
time2.title = entry.created_at;
|
|
8776
|
+
open.appendChild(time2);
|
|
8777
|
+
}
|
|
8161
8778
|
open.addEventListener("click", () => {
|
|
8162
8779
|
openAnnotationEntry(entry.id);
|
|
8163
8780
|
});
|
|
@@ -8197,6 +8814,9 @@ ${frontmatter.yaml}
|
|
|
8197
8814
|
function showAnnotationDetail(session, entry, index) {
|
|
8198
8815
|
activeAnnotationId = entry.id;
|
|
8199
8816
|
$("#annotation-detail-session").textContent = session.title;
|
|
8817
|
+
const detailTime = $("#annotation-detail-time");
|
|
8818
|
+
detailTime.textContent = annotationTimeLabel(entry.created_at);
|
|
8819
|
+
detailTime.title = entry.created_at;
|
|
8200
8820
|
$("#annotation-detail-step").textContent = `${index + 1}/${session.entries.length}`;
|
|
8201
8821
|
const location2 = $("#annotation-detail-location");
|
|
8202
8822
|
location2.textContent = annotationLocationLabel(entry);
|
|
@@ -8409,8 +9029,21 @@ ${frontmatter.yaml}
|
|
|
8409
9029
|
}
|
|
8410
9030
|
});
|
|
8411
9031
|
}
|
|
9032
|
+
const ANNOTATION_PANEL_DEFAULT_WIDTH = 380;
|
|
9033
|
+
const ANNOTATION_PANEL_MIN_WIDTH = 260;
|
|
9034
|
+
const ANNOTATION_PANEL_MAX_WIDTH = 720;
|
|
9035
|
+
function annotationPanelMaxWidth() {
|
|
9036
|
+
return Math.max(ANNOTATION_PANEL_MIN_WIDTH, Math.min(ANNOTATION_PANEL_MAX_WIDTH, window.innerWidth - 32));
|
|
9037
|
+
}
|
|
9038
|
+
function applyAnnotationPanelWidth(width, persist = true) {
|
|
9039
|
+
const clamped = Math.max(ANNOTATION_PANEL_MIN_WIDTH, Math.min(annotationPanelMaxWidth(), width));
|
|
9040
|
+
document.documentElement.style.setProperty("--annotation-panel-w", `${clamped}px`);
|
|
9041
|
+
if (persist)
|
|
9042
|
+
deps.setAnnotationPanelWidth(clamped);
|
|
9043
|
+
}
|
|
8412
9044
|
if (deps.getAnnotationPanelOpen())
|
|
8413
9045
|
setAnnotationPanelOpen(true);
|
|
9046
|
+
applyAnnotationPanelWidth(deps.getAnnotationPanelWidth() ?? ANNOTATION_PANEL_DEFAULT_WIDTH, false);
|
|
8414
9047
|
updateDatabaseCaptureButton();
|
|
8415
9048
|
$("#annotations-toggle").addEventListener("click", () => {
|
|
8416
9049
|
setAnnotationPanelOpen(annotationPanel.hidden);
|
|
@@ -8464,6 +9097,7 @@ ${frontmatter.yaml}
|
|
|
8464
9097
|
restoreSessionFromUrl,
|
|
8465
9098
|
openAnnotationEntry,
|
|
8466
9099
|
setAnnotationPanelOpen,
|
|
9100
|
+
applyAnnotationPanelWidth,
|
|
8467
9101
|
getActiveSessionEntries() {
|
|
8468
9102
|
const session = ANNOTATIONS.sessions.find((s2) => s2.id === activeSessionId);
|
|
8469
9103
|
return session ? session.entries : [];
|
|
@@ -8575,449 +9209,6 @@ ${frontmatter.yaml}
|
|
|
8575
9209
|
return sha.slice(0, 7);
|
|
8576
9210
|
}
|
|
8577
9211
|
|
|
8578
|
-
// web-src/views/media-embed.ts
|
|
8579
|
-
var MEDIA_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico|mp4|webm|mov|mp3|wav|ogg|flac|m4a|aac|opus)(\?.*)?$/i;
|
|
8580
|
-
var IMAGE_RE = /\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)(\?.*)?$/i;
|
|
8581
|
-
var VIDEO_RE = /\.(mp4|webm|mov)$/i;
|
|
8582
|
-
var AUDIO_RE = /\.(mp3|wav|ogg|flac|m4a|aac|opus)$/i;
|
|
8583
|
-
function isMedia(p2) {
|
|
8584
|
-
return MEDIA_RE.test(p2);
|
|
8585
|
-
}
|
|
8586
|
-
function isImage(p2) {
|
|
8587
|
-
return IMAGE_RE.test(p2);
|
|
8588
|
-
}
|
|
8589
|
-
function isVideo(p2) {
|
|
8590
|
-
return VIDEO_RE.test(p2);
|
|
8591
|
-
}
|
|
8592
|
-
function isAudio(p2) {
|
|
8593
|
-
return AUDIO_RE.test(p2);
|
|
8594
|
-
}
|
|
8595
|
-
function fileURL(path, ref) {
|
|
8596
|
-
return `/_file?path=${encodeURIComponent(path)}&ref=${ref}`;
|
|
8597
|
-
}
|
|
8598
|
-
function mediaTag(path, ref) {
|
|
8599
|
-
const url = fileURL(path, ref);
|
|
8600
|
-
if (isVideo(path)) {
|
|
8601
|
-
return `<video src="${url}" controls preload="metadata"></video>`;
|
|
8602
|
-
}
|
|
8603
|
-
if (isAudio(path)) {
|
|
8604
|
-
return `<audio src="${url}" controls preload="metadata"></audio>`;
|
|
8605
|
-
}
|
|
8606
|
-
return `<img src="${url}" alt="" loading="lazy">`;
|
|
8607
|
-
}
|
|
8608
|
-
function enhanceMediaCard(file, card) {
|
|
8609
|
-
const path = file.path;
|
|
8610
|
-
if (!file.media_kind && !isMedia(path))
|
|
8611
|
-
return;
|
|
8612
|
-
const wrapper = card.querySelector(".d2h-file-wrapper");
|
|
8613
|
-
if (!wrapper)
|
|
8614
|
-
return;
|
|
8615
|
-
const body = wrapper.querySelector(".d2h-files-diff") || wrapper.querySelector(".d2h-file-diff");
|
|
8616
|
-
if (!body)
|
|
8617
|
-
return;
|
|
8618
|
-
const container = document.createElement("div");
|
|
8619
|
-
container.className = "gdp-media";
|
|
8620
|
-
let leftHTML;
|
|
8621
|
-
let rightHTML;
|
|
8622
|
-
if (file.status === "A") {
|
|
8623
|
-
leftHTML = '<div class="media-empty">Not in HEAD</div>';
|
|
8624
|
-
rightHTML = mediaTag(path, "worktree");
|
|
8625
|
-
} else if (file.status === "D") {
|
|
8626
|
-
leftHTML = mediaTag(path, "HEAD");
|
|
8627
|
-
rightHTML = '<div class="media-empty">Deleted</div>';
|
|
8628
|
-
} else {
|
|
8629
|
-
leftHTML = mediaTag(path, "HEAD");
|
|
8630
|
-
rightHTML = mediaTag(path, "worktree");
|
|
8631
|
-
}
|
|
8632
|
-
container.innerHTML = '<div class="media-side"><div class="media-label del">Before</div>' + leftHTML + "</div>" + '<div class="media-side"><div class="media-label add">After</div>' + rightHTML + "</div>";
|
|
8633
|
-
body.replaceWith(container);
|
|
8634
|
-
}
|
|
8635
|
-
|
|
8636
|
-
// web-src/core/source-meta.ts
|
|
8637
|
-
var SOURCE_SHIKI_LANG_ALIASES = {
|
|
8638
|
-
makefile: "make",
|
|
8639
|
-
objectivec: "c",
|
|
8640
|
-
"objective-c": "c",
|
|
8641
|
-
"objective-cpp": "cpp",
|
|
8642
|
-
starlark: "python"
|
|
8643
|
-
};
|
|
8644
|
-
function normalizeSourceShikiLang(lang) {
|
|
8645
|
-
if (!lang)
|
|
8646
|
-
return null;
|
|
8647
|
-
return SOURCE_SHIKI_LANG_ALIASES[lang] || lang;
|
|
8648
|
-
}
|
|
8649
|
-
function isPreviewableSource(path) {
|
|
8650
|
-
return /\.(md|markdown|mdown|mkdn|mdx|html|htm)$/i.test(path);
|
|
8651
|
-
}
|
|
8652
|
-
function sourcePreviewKind(path) {
|
|
8653
|
-
if (/\.(md|markdown|mdown|mkdn|mdx)$/i.test(path))
|
|
8654
|
-
return "markdown";
|
|
8655
|
-
if (/\.(html|htm)$/i.test(path))
|
|
8656
|
-
return "html";
|
|
8657
|
-
return null;
|
|
8658
|
-
}
|
|
8659
|
-
var EXT_TO_LANG = {
|
|
8660
|
-
js: "javascript",
|
|
8661
|
-
mjs: "javascript",
|
|
8662
|
-
cjs: "javascript",
|
|
8663
|
-
ts: "typescript",
|
|
8664
|
-
tsx: "typescript",
|
|
8665
|
-
jsx: "javascript",
|
|
8666
|
-
py: "python",
|
|
8667
|
-
rb: "ruby",
|
|
8668
|
-
go: "go",
|
|
8669
|
-
rs: "rust",
|
|
8670
|
-
java: "java",
|
|
8671
|
-
kt: "kotlin",
|
|
8672
|
-
swift: "swift",
|
|
8673
|
-
c: "c",
|
|
8674
|
-
h: "c",
|
|
8675
|
-
cc: "cpp",
|
|
8676
|
-
cpp: "cpp",
|
|
8677
|
-
hpp: "cpp",
|
|
8678
|
-
cs: "csharp",
|
|
8679
|
-
php: "php",
|
|
8680
|
-
lua: "lua",
|
|
8681
|
-
sh: "bash",
|
|
8682
|
-
bash: "bash",
|
|
8683
|
-
zsh: "bash",
|
|
8684
|
-
fish: "bash",
|
|
8685
|
-
sql: "sql",
|
|
8686
|
-
json: "json",
|
|
8687
|
-
yaml: "yaml",
|
|
8688
|
-
yml: "yaml",
|
|
8689
|
-
toml: "toml",
|
|
8690
|
-
tf: "terraform",
|
|
8691
|
-
tfvars: "terraform",
|
|
8692
|
-
hcl: "terraform",
|
|
8693
|
-
xml: "xml",
|
|
8694
|
-
html: "xml",
|
|
8695
|
-
vue: "xml",
|
|
8696
|
-
css: "css",
|
|
8697
|
-
scss: "scss",
|
|
8698
|
-
md: "markdown",
|
|
8699
|
-
dockerfile: "dockerfile",
|
|
8700
|
-
proto: "protobuf",
|
|
8701
|
-
gradle: "gradle",
|
|
8702
|
-
properties: "properties",
|
|
8703
|
-
patch: "diff",
|
|
8704
|
-
diff: "diff",
|
|
8705
|
-
nix: "nix",
|
|
8706
|
-
cue: "cue",
|
|
8707
|
-
rego: "rego",
|
|
8708
|
-
bicep: "bicep",
|
|
8709
|
-
bazel: "starlark",
|
|
8710
|
-
bzl: "starlark",
|
|
8711
|
-
cmake: "cmake",
|
|
8712
|
-
groovy: "groovy",
|
|
8713
|
-
dart: "dart",
|
|
8714
|
-
scala: "scala",
|
|
8715
|
-
clj: "clojure",
|
|
8716
|
-
cljs: "clojure",
|
|
8717
|
-
cljc: "clojure",
|
|
8718
|
-
edn: "clojure",
|
|
8719
|
-
ex: "elixir",
|
|
8720
|
-
exs: "elixir",
|
|
8721
|
-
erl: "erlang",
|
|
8722
|
-
hrl: "erlang",
|
|
8723
|
-
hs: "haskell",
|
|
8724
|
-
lhs: "haskell",
|
|
8725
|
-
ml: "ocaml",
|
|
8726
|
-
mli: "ocaml",
|
|
8727
|
-
jl: "julia",
|
|
8728
|
-
r: "r",
|
|
8729
|
-
rmd: "r",
|
|
8730
|
-
pl: "perl",
|
|
8731
|
-
pm: "perl",
|
|
8732
|
-
tcl: "tcl",
|
|
8733
|
-
vim: "vim",
|
|
8734
|
-
f: "fortran",
|
|
8735
|
-
f90: "fortran",
|
|
8736
|
-
m: "objective-c",
|
|
8737
|
-
mm: "objective-cpp",
|
|
8738
|
-
tex: "tex",
|
|
8739
|
-
bib: "bibtex",
|
|
8740
|
-
rst: "rst"
|
|
8741
|
-
};
|
|
8742
|
-
var TEXT_SOURCE_EXTENSIONS = new Set([
|
|
8743
|
-
...Object.keys(EXT_TO_LANG),
|
|
8744
|
-
"txt",
|
|
8745
|
-
"md",
|
|
8746
|
-
"markdown",
|
|
8747
|
-
"mdown",
|
|
8748
|
-
"mkdn",
|
|
8749
|
-
"mdx",
|
|
8750
|
-
"json",
|
|
8751
|
-
"jsonc",
|
|
8752
|
-
"csv",
|
|
8753
|
-
"tsv",
|
|
8754
|
-
"yaml",
|
|
8755
|
-
"yml",
|
|
8756
|
-
"toml",
|
|
8757
|
-
"hcl",
|
|
8758
|
-
"tf",
|
|
8759
|
-
"tfvars",
|
|
8760
|
-
"tfstate",
|
|
8761
|
-
"xml",
|
|
8762
|
-
"html",
|
|
8763
|
-
"htm",
|
|
8764
|
-
"css",
|
|
8765
|
-
"scss",
|
|
8766
|
-
"sass",
|
|
8767
|
-
"less",
|
|
8768
|
-
"js",
|
|
8769
|
-
"jsx",
|
|
8770
|
-
"mjs",
|
|
8771
|
-
"cjs",
|
|
8772
|
-
"ts",
|
|
8773
|
-
"tsx",
|
|
8774
|
-
"mts",
|
|
8775
|
-
"cts",
|
|
8776
|
-
"vue",
|
|
8777
|
-
"svelte",
|
|
8778
|
-
"astro",
|
|
8779
|
-
"rs",
|
|
8780
|
-
"go",
|
|
8781
|
-
"py",
|
|
8782
|
-
"rb",
|
|
8783
|
-
"php",
|
|
8784
|
-
"java",
|
|
8785
|
-
"kt",
|
|
8786
|
-
"kts",
|
|
8787
|
-
"c",
|
|
8788
|
-
"cc",
|
|
8789
|
-
"cpp",
|
|
8790
|
-
"cxx",
|
|
8791
|
-
"h",
|
|
8792
|
-
"hpp",
|
|
8793
|
-
"cs",
|
|
8794
|
-
"swift",
|
|
8795
|
-
"sh",
|
|
8796
|
-
"bash",
|
|
8797
|
-
"zsh",
|
|
8798
|
-
"fish",
|
|
8799
|
-
"ps1",
|
|
8800
|
-
"sql",
|
|
8801
|
-
"graphql",
|
|
8802
|
-
"graphqls",
|
|
8803
|
-
"gql",
|
|
8804
|
-
"ini",
|
|
8805
|
-
"conf",
|
|
8806
|
-
"env",
|
|
8807
|
-
"properties",
|
|
8808
|
-
"gitignore",
|
|
8809
|
-
"dockerignore",
|
|
8810
|
-
"editorconfig",
|
|
8811
|
-
"lock",
|
|
8812
|
-
"log",
|
|
8813
|
-
"patch",
|
|
8814
|
-
"diff",
|
|
8815
|
-
"sum",
|
|
8816
|
-
"mk",
|
|
8817
|
-
"proto",
|
|
8818
|
-
"thrift",
|
|
8819
|
-
"prisma",
|
|
8820
|
-
"gradle",
|
|
8821
|
-
"cmake",
|
|
8822
|
-
"nix",
|
|
8823
|
-
"cue",
|
|
8824
|
-
"rego",
|
|
8825
|
-
"bicep",
|
|
8826
|
-
"bazel",
|
|
8827
|
-
"bzl",
|
|
8828
|
-
"dart",
|
|
8829
|
-
"scala",
|
|
8830
|
-
"clj",
|
|
8831
|
-
"cljs",
|
|
8832
|
-
"cljc",
|
|
8833
|
-
"edn",
|
|
8834
|
-
"ex",
|
|
8835
|
-
"exs",
|
|
8836
|
-
"erl",
|
|
8837
|
-
"hrl",
|
|
8838
|
-
"hs",
|
|
8839
|
-
"lhs",
|
|
8840
|
-
"ml",
|
|
8841
|
-
"mli",
|
|
8842
|
-
"jl",
|
|
8843
|
-
"r",
|
|
8844
|
-
"rmd",
|
|
8845
|
-
"pl",
|
|
8846
|
-
"pm",
|
|
8847
|
-
"tcl",
|
|
8848
|
-
"vim",
|
|
8849
|
-
"groovy",
|
|
8850
|
-
"f",
|
|
8851
|
-
"f90",
|
|
8852
|
-
"m",
|
|
8853
|
-
"mm",
|
|
8854
|
-
"pas",
|
|
8855
|
-
"tex",
|
|
8856
|
-
"bib",
|
|
8857
|
-
"rst",
|
|
8858
|
-
"adoc",
|
|
8859
|
-
"org",
|
|
8860
|
-
"ipynb",
|
|
8861
|
-
"ejs",
|
|
8862
|
-
"hbs",
|
|
8863
|
-
"mustache",
|
|
8864
|
-
"liquid",
|
|
8865
|
-
"pug"
|
|
8866
|
-
]);
|
|
8867
|
-
var TEXT_SOURCE_FILENAMES = new Set([
|
|
8868
|
-
"readme",
|
|
8869
|
-
"license",
|
|
8870
|
-
"copying",
|
|
8871
|
-
"authors",
|
|
8872
|
-
"contributors",
|
|
8873
|
-
"notice",
|
|
8874
|
-
"changelog",
|
|
8875
|
-
"todo",
|
|
8876
|
-
"manifest",
|
|
8877
|
-
"version",
|
|
8878
|
-
"codeowners",
|
|
8879
|
-
"go.mod",
|
|
8880
|
-
"build.bazel",
|
|
8881
|
-
"workspace.bazel",
|
|
8882
|
-
"module.bazel",
|
|
8883
|
-
"gemfile",
|
|
8884
|
-
"rakefile",
|
|
8885
|
-
"procfile",
|
|
8886
|
-
"brewfile",
|
|
8887
|
-
"gnumakefile",
|
|
8888
|
-
"bsdmakefile",
|
|
8889
|
-
".gitattributes",
|
|
8890
|
-
".gitmodules",
|
|
8891
|
-
".npmrc",
|
|
8892
|
-
".nvmrc",
|
|
8893
|
-
".yarnrc",
|
|
8894
|
-
".prettierrc",
|
|
8895
|
-
".eslintrc",
|
|
8896
|
-
".babelrc",
|
|
8897
|
-
".stylelintrc"
|
|
8898
|
-
]);
|
|
8899
|
-
var FILENAME_TO_LANG = {
|
|
8900
|
-
dockerfile: "dockerfile",
|
|
8901
|
-
makefile: "makefile",
|
|
8902
|
-
gnumakefile: "makefile",
|
|
8903
|
-
bsdmakefile: "makefile",
|
|
8904
|
-
"go.mod": "go",
|
|
8905
|
-
"build.bazel": "starlark",
|
|
8906
|
-
"workspace.bazel": "starlark",
|
|
8907
|
-
"module.bazel": "starlark"
|
|
8908
|
-
};
|
|
8909
|
-
function sourceFileName(path) {
|
|
8910
|
-
return (path.split("/").pop() || path).toLowerCase();
|
|
8911
|
-
}
|
|
8912
|
-
function sourceFileExtension(name) {
|
|
8913
|
-
const index = name.lastIndexOf(".");
|
|
8914
|
-
return index >= 0 ? name.slice(index + 1) : "";
|
|
8915
|
-
}
|
|
8916
|
-
function isDockerfileName(name) {
|
|
8917
|
-
return /^dockerfile(?:[.-].+)?$/i.test(name);
|
|
8918
|
-
}
|
|
8919
|
-
function isMakefileName(name) {
|
|
8920
|
-
return /^makefile(?:[.-].+)?$/i.test(name);
|
|
8921
|
-
}
|
|
8922
|
-
function isDotenvName(name) {
|
|
8923
|
-
return /^(?:\.?env|.*\.env)(?:[.-].+)?$/i.test(name);
|
|
8924
|
-
}
|
|
8925
|
-
function sourceDisplayKind(path) {
|
|
8926
|
-
if (isVideo(path))
|
|
8927
|
-
return "video";
|
|
8928
|
-
if (isAudio(path))
|
|
8929
|
-
return "audio";
|
|
8930
|
-
if (isImage(path))
|
|
8931
|
-
return "image";
|
|
8932
|
-
if (/\.pdf$/i.test(path))
|
|
8933
|
-
return "pdf";
|
|
8934
|
-
const name = sourceFileName(path);
|
|
8935
|
-
const ext = sourceFileExtension(name);
|
|
8936
|
-
if (TEXT_SOURCE_EXTENSIONS.has(ext))
|
|
8937
|
-
return "text";
|
|
8938
|
-
if (TEXT_SOURCE_FILENAMES.has(name))
|
|
8939
|
-
return "text";
|
|
8940
|
-
if (isDotenvName(name))
|
|
8941
|
-
return "text";
|
|
8942
|
-
if (isDockerfileName(name) || isMakefileName(name))
|
|
8943
|
-
return "text";
|
|
8944
|
-
return "unsupported";
|
|
8945
|
-
}
|
|
8946
|
-
function formatBytes(bytes) {
|
|
8947
|
-
if (!Number.isFinite(bytes) || bytes < 0)
|
|
8948
|
-
return "";
|
|
8949
|
-
const units = ["B", "KB", "MB", "GB"];
|
|
8950
|
-
let value = bytes;
|
|
8951
|
-
let unit = 0;
|
|
8952
|
-
while (value >= 1024 && unit < units.length - 1) {
|
|
8953
|
-
value /= 1024;
|
|
8954
|
-
unit++;
|
|
8955
|
-
}
|
|
8956
|
-
return (unit === 0 ? String(value) : value.toFixed(value >= 10 ? 1 : 2).replace(/\.0+$/, "")) + " " + units[unit];
|
|
8957
|
-
}
|
|
8958
|
-
function formatFileDate(value) {
|
|
8959
|
-
if (!value)
|
|
8960
|
-
return "";
|
|
8961
|
-
const date = new Date(value);
|
|
8962
|
-
if (Number.isNaN(date.getTime()))
|
|
8963
|
-
return "";
|
|
8964
|
-
return date.toLocaleString(undefined, {
|
|
8965
|
-
year: "numeric",
|
|
8966
|
-
month: "short",
|
|
8967
|
-
day: "numeric",
|
|
8968
|
-
hour: "2-digit",
|
|
8969
|
-
minute: "2-digit"
|
|
8970
|
-
});
|
|
8971
|
-
}
|
|
8972
|
-
function humanFileKind(path, mime, fallback) {
|
|
8973
|
-
const ext = (path.split(".").pop() || "").toLowerCase();
|
|
8974
|
-
if (ext === "png")
|
|
8975
|
-
return "PNG image";
|
|
8976
|
-
if (ext === "jpg" || ext === "jpeg")
|
|
8977
|
-
return "JPEG image";
|
|
8978
|
-
if (ext === "gif")
|
|
8979
|
-
return "GIF image";
|
|
8980
|
-
if (ext === "webp")
|
|
8981
|
-
return "WebP image";
|
|
8982
|
-
if (ext === "svg")
|
|
8983
|
-
return "SVG image";
|
|
8984
|
-
if (ext === "pdf")
|
|
8985
|
-
return "PDF document";
|
|
8986
|
-
if (ext === "zip")
|
|
8987
|
-
return "ZIP archive";
|
|
8988
|
-
if (ext === "mp4")
|
|
8989
|
-
return "MP4 video";
|
|
8990
|
-
if (ext === "webm")
|
|
8991
|
-
return "WebM video";
|
|
8992
|
-
if (ext === "mp3")
|
|
8993
|
-
return "MP3 audio";
|
|
8994
|
-
if (ext === "wav")
|
|
8995
|
-
return "WAV audio";
|
|
8996
|
-
if (ext === "ogg")
|
|
8997
|
-
return "Ogg audio";
|
|
8998
|
-
if (ext === "flac")
|
|
8999
|
-
return "FLAC audio";
|
|
9000
|
-
if (ext === "m4a")
|
|
9001
|
-
return "M4A audio";
|
|
9002
|
-
if (ext === "aac")
|
|
9003
|
-
return "AAC audio";
|
|
9004
|
-
if (ext === "opus")
|
|
9005
|
-
return "Opus audio";
|
|
9006
|
-
if (ext === "mid" || ext === "midi")
|
|
9007
|
-
return "MIDI file";
|
|
9008
|
-
if (mime?.startsWith("image/"))
|
|
9009
|
-
return "Image";
|
|
9010
|
-
if (mime?.startsWith("video/"))
|
|
9011
|
-
return "Video";
|
|
9012
|
-
if (mime?.startsWith("audio/"))
|
|
9013
|
-
return "Audio";
|
|
9014
|
-
if (mime === "application/pdf")
|
|
9015
|
-
return "PDF document";
|
|
9016
|
-
if (fallback === "unsupported file")
|
|
9017
|
-
return "Binary file";
|
|
9018
|
-
return fallback.charAt(0).toUpperCase() + fallback.slice(1);
|
|
9019
|
-
}
|
|
9020
|
-
|
|
9021
9212
|
// web-src/views/file-shell.ts
|
|
9022
9213
|
function isBlobOrBlameFileRoute(route) {
|
|
9023
9214
|
return route.screen === "file" && (route.view === "blob" || route.view === "blame");
|
|
@@ -9113,7 +9304,7 @@ ${frontmatter.yaml}
|
|
|
9113
9304
|
});
|
|
9114
9305
|
return copy;
|
|
9115
9306
|
}
|
|
9116
|
-
function createFileShellSticky(deps, target, activeTab) {
|
|
9307
|
+
function createFileShellSticky(deps, target, activeTab, options = {}) {
|
|
9117
9308
|
const sticky = document.createElement("div");
|
|
9118
9309
|
sticky.className = "gdp-file-detail-sticky";
|
|
9119
9310
|
const header = document.createElement("div");
|
|
@@ -9126,7 +9317,7 @@ ${frontmatter.yaml}
|
|
|
9126
9317
|
sticky.appendChild(header);
|
|
9127
9318
|
const tabsHost = document.createElement("div");
|
|
9128
9319
|
tabsHost.className = "gdp-file-detail-tabs";
|
|
9129
|
-
tabsHost.appendChild(createFileViewTabs(deps, target, activeTab));
|
|
9320
|
+
tabsHost.appendChild(createFileViewTabs(deps, target, activeTab, options));
|
|
9130
9321
|
sticky.appendChild(tabsHost);
|
|
9131
9322
|
return { sticky, header, tabsHost };
|
|
9132
9323
|
}
|
|
@@ -20173,8 +20364,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20173
20364
|
deps.pill.show(next.path, start, end);
|
|
20174
20365
|
}
|
|
20175
20366
|
function clear() {
|
|
20367
|
+
const hadSelection = !!selection || !!drag;
|
|
20176
20368
|
drag = null;
|
|
20177
20369
|
applySelection(null);
|
|
20370
|
+
return hadSelection;
|
|
20178
20371
|
}
|
|
20179
20372
|
const diff = document.querySelector("#diff");
|
|
20180
20373
|
if (!diff)
|
|
@@ -20213,44 +20406,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
|
|
|
20213
20406
|
document.addEventListener("keydown", (e2) => {
|
|
20214
20407
|
if (isImeComposing(e2))
|
|
20215
20408
|
return;
|
|
20216
|
-
if (e2.key === "Escape" && selection && !drag)
|
|
20409
|
+
if (e2.key === "Escape" && selection && !drag && !isEditableKeyTarget(e2.target)) {
|
|
20217
20410
|
clear();
|
|
20411
|
+
}
|
|
20218
20412
|
});
|
|
20219
20413
|
return { clear };
|
|
20220
20414
|
}
|
|
20221
20415
|
|
|
20222
|
-
// web-src/core/file-path-copy.ts
|
|
20223
|
-
function filePathClipboardText(path) {
|
|
20224
|
-
return path || "";
|
|
20225
|
-
}
|
|
20226
|
-
function fileNameClipboardText(path) {
|
|
20227
|
-
if (!path)
|
|
20228
|
-
return "";
|
|
20229
|
-
const parts = path.split("/").filter(Boolean);
|
|
20230
|
-
return parts[parts.length - 1] || "";
|
|
20231
|
-
}
|
|
20232
|
-
function fileReferenceClipboardText(path, start, end) {
|
|
20233
|
-
if (!path)
|
|
20234
|
-
return "";
|
|
20235
|
-
const a2 = Math.max(1, Math.floor(Math.min(start, end)));
|
|
20236
|
-
const b2 = Math.max(1, Math.floor(Math.max(start, end)));
|
|
20237
|
-
return a2 === b2 ? `@${path}#${a2}` : `@${path}#${a2}-${b2}`;
|
|
20238
|
-
}
|
|
20239
|
-
function fileReferenceWithCodeClipboardText(path, start, end, lines, lang) {
|
|
20240
|
-
const ref = fileReferenceClipboardText(path, start, end);
|
|
20241
|
-
if (!ref)
|
|
20242
|
-
return "";
|
|
20243
|
-
if (!lines || lines.length === 0)
|
|
20244
|
-
return ref;
|
|
20245
|
-
const fence2 = (lang || "").trim();
|
|
20246
|
-
return `${ref}
|
|
20247
|
-
|
|
20248
|
-
\`\`\`${fence2}
|
|
20249
|
-
${lines.join(`
|
|
20250
|
-
`)}
|
|
20251
|
-
\`\`\``;
|
|
20252
|
-
}
|
|
20253
|
-
|
|
20254
20416
|
// web-src/core/ws-highlight.ts
|
|
20255
20417
|
function isWhitespaceOnlyInlineHighlight(text2) {
|
|
20256
20418
|
return !!text2 && !/\S/.test(text2);
|
|
@@ -22669,6 +22831,16 @@ ${lines.join(`
|
|
|
22669
22831
|
selectors: [{ action: "toggle-theme" }],
|
|
22670
22832
|
description: { en: "Toggle theme", ja: "テーマ切り替え" }
|
|
22671
22833
|
},
|
|
22834
|
+
{
|
|
22835
|
+
selectors: [
|
|
22836
|
+
{ action: "copy-ai-context" },
|
|
22837
|
+
{ action: "copy-ai-context-with-code" }
|
|
22838
|
+
],
|
|
22839
|
+
description: {
|
|
22840
|
+
en: "Copy AI context (with code if a selection is active)",
|
|
22841
|
+
ja: "AI 用コンテキストをコピー(選択行があればコード付き)"
|
|
22842
|
+
}
|
|
22843
|
+
},
|
|
22672
22844
|
{
|
|
22673
22845
|
selectors: [
|
|
22674
22846
|
{ action: "annotation-previous" },
|
|
@@ -23060,7 +23232,7 @@ code-viewer doctor --cwd /path/to/repo --port 64160 --json`
|
|
|
23060
23232
|
rows: [
|
|
23061
23233
|
[
|
|
23062
23234
|
"settings.json",
|
|
23063
|
-
"Viewer Settings — diff layout, theme, language, sidebar/history widths, font sizes, syntax highlight, ignore-whitespace, hide-tests, scope overrides (omitted dirs / excluded names), upload toggle, annotation panel open/follow/mute/rate, and the last viewed diff range."
|
|
23235
|
+
"Viewer Settings — diff layout, theme, language, sidebar/history widths, font sizes, syntax highlight, ignore-whitespace, hide-tests, scope overrides (omitted dirs / excluded names), upload toggle, annotation panel open/width/follow/mute/rate, and the last viewed diff range."
|
|
23064
23236
|
],
|
|
23065
23237
|
[
|
|
23066
23238
|
"view-state.json",
|
|
@@ -23198,9 +23370,13 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
23198
23370
|
"Copy as AI prompt",
|
|
23199
23371
|
"Each annotation has a copy button that produces a paste-ready prompt block referencing the annotation URL, so you can hand it back to the originating agent."
|
|
23200
23372
|
],
|
|
23373
|
+
[
|
|
23374
|
+
"Timestamps and width",
|
|
23375
|
+
"Session and entry rows show creation time. The panel can be resized, and its width is saved per project."
|
|
23376
|
+
],
|
|
23201
23377
|
[
|
|
23202
23378
|
"Persistent state",
|
|
23203
|
-
"Open/closed, follow, mute, and rate are stored under .code-viewer/settings.json; annotations themselves live in .code-viewer/annotations.json."
|
|
23379
|
+
"Open/closed, width, follow, mute, and rate are stored under .code-viewer/settings.json; annotations themselves live in .code-viewer/annotations.json."
|
|
23204
23380
|
]
|
|
23205
23381
|
]
|
|
23206
23382
|
}
|
|
@@ -23569,15 +23745,19 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
23569
23745
|
rows: [
|
|
23570
23746
|
[
|
|
23571
23747
|
"Drag on line numbers",
|
|
23572
|
-
"Highlight a range; the floating copy pill prepares @path#
|
|
23748
|
+
"Highlight a range; the floating copy pill prepares @path#1-9"
|
|
23573
23749
|
],
|
|
23574
23750
|
[
|
|
23575
23751
|
"Click the pill",
|
|
23576
|
-
"Copy @path#
|
|
23752
|
+
"Copy @path#1-9 to the clipboard for pasting into an AI agent"
|
|
23577
23753
|
],
|
|
23578
23754
|
[
|
|
23579
23755
|
"Shift+Click the pill",
|
|
23580
|
-
"Copy @path#
|
|
23756
|
+
"Copy @path#1-9 plus a fenced code block of the selected lines — paste straight to an AI without re-fetching the file"
|
|
23757
|
+
],
|
|
23758
|
+
[
|
|
23759
|
+
"x button / Escape",
|
|
23760
|
+
"Clear the selected range and hide the floating copy pill"
|
|
23581
23761
|
]
|
|
23582
23762
|
]
|
|
23583
23763
|
}
|
|
@@ -23704,7 +23884,7 @@ code-viewer doctor --cwd /path/to/repo --port 64160 --json`
|
|
|
23704
23884
|
rows: [
|
|
23705
23885
|
[
|
|
23706
23886
|
"settings.json",
|
|
23707
|
-
"Viewer Settings — diff レイアウト、テーマ、言語、サイドバー/履歴幅、フォントサイズ、シンタックスハイライト、whitespace 無視、テスト非表示、scope 上書き(除外ディレクトリ /
|
|
23887
|
+
"Viewer Settings — diff レイアウト、テーマ、言語、サイドバー/履歴幅、フォントサイズ、シンタックスハイライト、whitespace 無視、テスト非表示、scope 上書き(除外ディレクトリ / 除外名)、アップロード許可、注釈パネルの開閉/幅/follow/ミュート/再生速度、最後に表示した diff 範囲を保存します。"
|
|
23708
23888
|
],
|
|
23709
23889
|
[
|
|
23710
23890
|
"view-state.json",
|
|
@@ -23842,9 +24022,13 @@ code-viewer annotate add-db --db app.db --tab query \\
|
|
|
23842
24022
|
"AI 用プロンプトとしてコピー",
|
|
23843
24023
|
"各注釈のコピーボタンが、注釈 URL を含む貼り付け可能なプロンプトを生成します。元のエージェントへそのまま戻せます。"
|
|
23844
24024
|
],
|
|
24025
|
+
[
|
|
24026
|
+
"日時と幅",
|
|
24027
|
+
"セッションと注釈の行には作成日時が出ます。パネル幅はリサイズでき、プロジェクト単位で保存されます。"
|
|
24028
|
+
],
|
|
23845
24029
|
[
|
|
23846
24030
|
"永続化",
|
|
23847
|
-
"
|
|
24031
|
+
"パネルの開閉・幅・follow・ミュート・速度は .code-viewer/settings.json に、注釈自体は .code-viewer/annotations.json に保存されます。"
|
|
23848
24032
|
]
|
|
23849
24033
|
]
|
|
23850
24034
|
}
|
|
@@ -24210,15 +24394,19 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
24210
24394
|
rows: [
|
|
24211
24395
|
[
|
|
24212
24396
|
"行番号でドラッグ",
|
|
24213
|
-
"範囲をハイライトし、フロートする Copy ピルが @path#
|
|
24397
|
+
"範囲をハイライトし、フロートする Copy ピルが @path#1-9 を用意"
|
|
24214
24398
|
],
|
|
24215
24399
|
[
|
|
24216
24400
|
"ピルをクリック",
|
|
24217
|
-
"@path#
|
|
24401
|
+
"@path#1-9 をコピー(AI エージェントへの貼り付け用)"
|
|
24218
24402
|
],
|
|
24219
24403
|
[
|
|
24220
24404
|
"Shift+ピルをクリック",
|
|
24221
|
-
"@path#
|
|
24405
|
+
"@path#1-9 と選択行の実コード(フェンス付き)をまとめてコピー — AI へ直接貼れて、ファイル再取得不要"
|
|
24406
|
+
],
|
|
24407
|
+
[
|
|
24408
|
+
"x ボタン / Escape",
|
|
24409
|
+
"選択範囲を解除し、フロートする Copy ピルを閉じる"
|
|
24222
24410
|
]
|
|
24223
24411
|
]
|
|
24224
24412
|
}
|
|
@@ -24839,35 +25027,57 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
24839
25027
|
}
|
|
24840
25028
|
return ordered;
|
|
24841
25029
|
}
|
|
24842
|
-
function createLineRefPill() {
|
|
24843
|
-
const pill = document.createElement("
|
|
25030
|
+
function createLineRefPill(deps) {
|
|
25031
|
+
const pill = document.createElement("div");
|
|
24844
25032
|
pill.id = "line-ref-pill";
|
|
24845
|
-
pill.type = "button";
|
|
24846
|
-
pill.title = "選択行の参照をコピー(Claude Code / Codex に貼り付け用)。Shift+Click でコード本体も添付。";
|
|
24847
25033
|
pill.hidden = true;
|
|
25034
|
+
const copyButton = document.createElement("button");
|
|
25035
|
+
copyButton.id = "line-ref-pill-copy";
|
|
25036
|
+
copyButton.type = "button";
|
|
25037
|
+
copyButton.title = "選択行の参照をコピー(Claude Code / Codex に貼り付け用)。Shift+Click でコード本体も添付。";
|
|
25038
|
+
const closeButton = document.createElement("button");
|
|
25039
|
+
closeButton.id = "line-ref-pill-close";
|
|
25040
|
+
closeButton.type = "button";
|
|
25041
|
+
closeButton.title = "選択を解除";
|
|
25042
|
+
closeButton.setAttribute("aria-label", "選択を解除");
|
|
25043
|
+
closeButton.textContent = "×";
|
|
25044
|
+
pill.appendChild(copyButton);
|
|
25045
|
+
pill.appendChild(closeButton);
|
|
24848
25046
|
document.body.appendChild(pill);
|
|
24849
25047
|
let refText = "";
|
|
24850
25048
|
let currentPath = "";
|
|
24851
25049
|
let currentStart = 0;
|
|
24852
25050
|
let currentEnd = 0;
|
|
24853
25051
|
let feedbackTimer = null;
|
|
25052
|
+
function selectionLineCount() {
|
|
25053
|
+
return currentEnd - currentStart + 1;
|
|
25054
|
+
}
|
|
25055
|
+
function countBadgeHtml() {
|
|
25056
|
+
const count = selectionLineCount();
|
|
25057
|
+
if (count <= 1)
|
|
25058
|
+
return "";
|
|
25059
|
+
const warn = count >= AI_CONTEXT_LARGE_SELECTION_LINE_THRESHOLD;
|
|
25060
|
+
return `<span class="lrp-count${warn ? " lrp-count-warn" : ""}">${count} lines</span>`;
|
|
25061
|
+
}
|
|
24854
25062
|
function render(state) {
|
|
24855
25063
|
pill.classList.toggle("copied", state === "copied" || state === "copied-code");
|
|
24856
25064
|
if (state === "copied") {
|
|
24857
|
-
|
|
25065
|
+
copyButton.innerHTML = `${CHECK_ICON}<span class="lrp-label">Copied!</span>`;
|
|
24858
25066
|
return;
|
|
24859
25067
|
}
|
|
24860
25068
|
if (state === "copied-code") {
|
|
24861
|
-
|
|
25069
|
+
const count = selectionLineCount();
|
|
25070
|
+
const suffix = count > 1 ? ` (${count} lines)` : "";
|
|
25071
|
+
copyButton.innerHTML = `${CHECK_ICON}<span class="lrp-label">Copied + code${suffix}</span>`;
|
|
24862
25072
|
return;
|
|
24863
25073
|
}
|
|
24864
25074
|
if (state === "failed") {
|
|
24865
|
-
|
|
25075
|
+
copyButton.innerHTML = `${COPY_ICON}<span class="lrp-label">copy failed</span>`;
|
|
24866
25076
|
return;
|
|
24867
25077
|
}
|
|
24868
|
-
|
|
25078
|
+
copyButton.innerHTML = `${COPY_ICON}<span class="lrp-label">Copy</span>` + `<span class="lrp-ref">${escapeHtml2(refText)}</span>` + countBadgeHtml();
|
|
24869
25079
|
}
|
|
24870
|
-
|
|
25080
|
+
copyButton.addEventListener("click", async (event) => {
|
|
24871
25081
|
if (!refText)
|
|
24872
25082
|
return;
|
|
24873
25083
|
const withCode = event.shiftKey;
|
|
@@ -24894,6 +25104,9 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
24894
25104
|
render("ready");
|
|
24895
25105
|
}, 1200);
|
|
24896
25106
|
});
|
|
25107
|
+
closeButton.addEventListener("click", () => {
|
|
25108
|
+
deps.onClose();
|
|
25109
|
+
});
|
|
24897
25110
|
return {
|
|
24898
25111
|
show(path, start, end) {
|
|
24899
25112
|
const next = fileReferenceClipboardText(path, start, end);
|
|
@@ -26418,8 +26631,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
26418
26631
|
return $("#filelist").classList.contains("tree-virtual");
|
|
26419
26632
|
}
|
|
26420
26633
|
function virtualSidebarActiveIndex() {
|
|
26421
|
-
const
|
|
26422
|
-
return SIDEBAR_VISIBLE_ROWS.findIndex((row) => row.path ===
|
|
26634
|
+
const activePath2 = SIDEBAR_VIRTUAL_ACTIVE_PATH || STATE.activeFile || "";
|
|
26635
|
+
return SIDEBAR_VISIBLE_ROWS.findIndex((row) => row.path === activePath2);
|
|
26423
26636
|
}
|
|
26424
26637
|
function selectVirtualSidebarIndex(index, options) {
|
|
26425
26638
|
if (!SIDEBAR_VISIBLE_ROWS.length)
|
|
@@ -28337,6 +28550,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
28337
28550
|
const VIRTUAL_SOURCE_PAGE_SIZE = 2000;
|
|
28338
28551
|
const VIRTUAL_SOURCE_ROW_HEIGHT = 20;
|
|
28339
28552
|
const VIRTUAL_SOURCE_HIGHLIGHT_MAX_LINE_LENGTH = 2000;
|
|
28553
|
+
const UNKNOWN_TEXT_SNIFF_BYTES = 8192;
|
|
28554
|
+
const SOURCE_LOADING_SLOW_THRESHOLD_MS = 3000;
|
|
28340
28555
|
let sourceShikiLoadPromise = null;
|
|
28341
28556
|
let PREFERRED_SOURCE_TAB = null;
|
|
28342
28557
|
let SOURCE_CURSOR = null;
|
|
@@ -28626,13 +28841,17 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
28626
28841
|
view.className = "gdp-source-viewer loading";
|
|
28627
28842
|
const content = document.createElement("div");
|
|
28628
28843
|
content.className = "gdp-source-loading-content";
|
|
28844
|
+
const spinner = document.createElement("span");
|
|
28845
|
+
spinner.className = "gdp-source-loading-spinner";
|
|
28846
|
+
spinner.setAttribute("aria-hidden", "true");
|
|
28847
|
+
spinner.textContent = "";
|
|
28629
28848
|
const title = document.createElement("strong");
|
|
28630
28849
|
title.className = "gdp-source-loading-title";
|
|
28631
28850
|
title.textContent = "Loading file";
|
|
28632
28851
|
const message = document.createElement("div");
|
|
28633
28852
|
message.className = "gdp-source-loading-message";
|
|
28634
28853
|
message.textContent = `${target.path} at ${target.ref}`;
|
|
28635
|
-
content.append(title, message);
|
|
28854
|
+
content.append(spinner, title, message);
|
|
28636
28855
|
if (onCancel) {
|
|
28637
28856
|
const button = document.createElement("button");
|
|
28638
28857
|
button.type = "button";
|
|
@@ -28646,6 +28865,27 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
28646
28865
|
content.appendChild(button);
|
|
28647
28866
|
}
|
|
28648
28867
|
view.appendChild(content);
|
|
28868
|
+
const startedAt = Date.now();
|
|
28869
|
+
window.setTimeout(() => {
|
|
28870
|
+
if (!view.isConnected)
|
|
28871
|
+
return;
|
|
28872
|
+
const slowNote = document.createElement("div");
|
|
28873
|
+
slowNote.className = "gdp-source-loading-slow-note";
|
|
28874
|
+
content.insertBefore(slowNote, onCancel ? content.lastChild : null);
|
|
28875
|
+
let interval = null;
|
|
28876
|
+
const updateSlowNote = () => {
|
|
28877
|
+
if (!view.isConnected) {
|
|
28878
|
+
if (interval !== null)
|
|
28879
|
+
window.clearInterval(interval);
|
|
28880
|
+
return;
|
|
28881
|
+
}
|
|
28882
|
+
const elapsed = Math.max(1, Math.floor((Date.now() - startedAt) / 1000));
|
|
28883
|
+
title.textContent = `Still loading file (${elapsed}s)`;
|
|
28884
|
+
slowNote.textContent = `Taking longer than usual (${elapsed}s elapsed). You can cancel below.`;
|
|
28885
|
+
};
|
|
28886
|
+
updateSlowNote();
|
|
28887
|
+
interval = window.setInterval(updateSlowNote, 1000);
|
|
28888
|
+
}, SOURCE_LOADING_SLOW_THRESHOLD_MS);
|
|
28649
28889
|
if (body)
|
|
28650
28890
|
body.replaceWith(view);
|
|
28651
28891
|
else
|
|
@@ -28703,16 +28943,42 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
28703
28943
|
else
|
|
28704
28944
|
card.appendChild(view);
|
|
28705
28945
|
}
|
|
28946
|
+
function renderSourceInternalPath(card, target, kind) {
|
|
28947
|
+
const body = card.querySelector(".gdp-file-detail-body, .d2h-files-diff, .d2h-file-diff, .gdp-media, .gdp-source-viewer");
|
|
28948
|
+
const info = createSourceFileInfo(target, "internal metadata", {
|
|
28949
|
+
loadMeta: false
|
|
28950
|
+
});
|
|
28951
|
+
const extraChildren = [info];
|
|
28952
|
+
if (kind === "code-viewer") {
|
|
28953
|
+
const link2 = document.createElement("a");
|
|
28954
|
+
link2.className = "gdp-btn gdp-btn-sm gdp-source-download";
|
|
28955
|
+
link2.href = buildRawFileUrl(target);
|
|
28956
|
+
link2.textContent = "Download raw";
|
|
28957
|
+
link2.target = "_blank";
|
|
28958
|
+
link2.rel = "noreferrer";
|
|
28959
|
+
extraChildren.push(link2);
|
|
28960
|
+
}
|
|
28961
|
+
const view = renderUnsupportedPreview({
|
|
28962
|
+
message: kind === "code-viewer" ? "This path is managed by code-viewer and is not previewed from the file viewer." : "Git internal metadata is not previewed from the file viewer.",
|
|
28963
|
+
extraChildren
|
|
28964
|
+
});
|
|
28965
|
+
if (body)
|
|
28966
|
+
body.replaceWith(view);
|
|
28967
|
+
else
|
|
28968
|
+
card.appendChild(view);
|
|
28969
|
+
}
|
|
28706
28970
|
function renderHtmlPreview(target, html) {
|
|
28707
28971
|
return renderHtmlPreviewFrame(`${target.path} preview`, html);
|
|
28708
28972
|
}
|
|
28709
|
-
function createSourceFileInfo(target, kind) {
|
|
28973
|
+
function createSourceFileInfo(target, kind, options = {}) {
|
|
28710
28974
|
const info = document.createElement("div");
|
|
28711
28975
|
info.className = "gdp-source-file-info";
|
|
28712
28976
|
const type = document.createElement("span");
|
|
28713
28977
|
type.className = "kind";
|
|
28714
28978
|
type.textContent = humanFileKind(target.path, undefined, kind);
|
|
28715
28979
|
info.appendChild(type);
|
|
28980
|
+
if (options.loadMeta === false)
|
|
28981
|
+
return info;
|
|
28716
28982
|
loadRawFileInfo(target).then((meta) => {
|
|
28717
28983
|
type.textContent = humanFileKind(target.path, meta.type, kind);
|
|
28718
28984
|
if (meta.size != null) {
|
|
@@ -28937,6 +29203,18 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
28937
29203
|
function shouldVirtualizeSource(textValue, lines) {
|
|
28938
29204
|
return textValue.length >= VIRTUAL_SOURCE_SIZE_THRESHOLD || lines.length >= VIRTUAL_SOURCE_LINE_THRESHOLD;
|
|
28939
29205
|
}
|
|
29206
|
+
async function sourceLooksTextByContent(target, meta, signal) {
|
|
29207
|
+
if (meta.size === 0)
|
|
29208
|
+
return true;
|
|
29209
|
+
const end = meta.size != null ? Math.max(0, Math.min(meta.size, UNKNOWN_TEXT_SNIFF_BYTES) - 1) : UNKNOWN_TEXT_SNIFF_BYTES - 1;
|
|
29210
|
+
const response = await trackLoad(fetch(buildRawFileUrl(target), {
|
|
29211
|
+
headers: { Range: `bytes=0-${end}` },
|
|
29212
|
+
signal
|
|
29213
|
+
}));
|
|
29214
|
+
if (!response.ok && response.status !== 206)
|
|
29215
|
+
return false;
|
|
29216
|
+
return isLikelyTextBytes(new Uint8Array(await response.arrayBuffer()));
|
|
29217
|
+
}
|
|
28940
29218
|
function isVirtualSourceDisabled() {
|
|
28941
29219
|
return deps.STATE.route.screen === "file" && deps.STATE.route.virtual === "off";
|
|
28942
29220
|
}
|
|
@@ -29633,15 +29911,16 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
29633
29911
|
const card = document.createElement("article");
|
|
29634
29912
|
card.className = "gdp-file-shell loaded gdp-standalone-source gdp-source-mode";
|
|
29635
29913
|
card.dataset.path = target.path;
|
|
29914
|
+
const internalKind = sourceInternalPathKind(target.path);
|
|
29636
29915
|
const wrapper = document.createElement("div");
|
|
29637
29916
|
wrapper.className = "gdp-file-detail-wrapper";
|
|
29638
|
-
const activeTab = STATE.route.screen === "file" && STATE.route.preview ? "preview" : "code";
|
|
29917
|
+
const activeTab = !internalKind && STATE.route.screen === "file" && STATE.route.preview ? "preview" : "code";
|
|
29639
29918
|
const { sticky, header } = createFileShellSticky({
|
|
29640
29919
|
currentRange,
|
|
29641
29920
|
setRoute,
|
|
29642
29921
|
setPreferredSourceTab,
|
|
29643
29922
|
createFileBreadcrumb
|
|
29644
|
-
}, target, activeTab);
|
|
29923
|
+
}, target, activeTab, internalKind ? { includeFileTabs: false, previewable: false } : {});
|
|
29645
29924
|
const pathActions = header.querySelector(".gdp-file-detail-path") || header;
|
|
29646
29925
|
pathActions.appendChild(createOpenPathButton(target.path, "file-parent", "open parent folder in OS"));
|
|
29647
29926
|
if (repoTarget && canTrashWorktreeRef(repoTarget)) {
|
|
@@ -29651,11 +29930,13 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
29651
29930
|
loadRepo();
|
|
29652
29931
|
}));
|
|
29653
29932
|
}
|
|
29654
|
-
|
|
29655
|
-
|
|
29656
|
-
|
|
29657
|
-
|
|
29658
|
-
|
|
29933
|
+
if (!internalKind) {
|
|
29934
|
+
loadRawFileInfo(target).then((meta) => {
|
|
29935
|
+
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
29936
|
+
return;
|
|
29937
|
+
header.appendChild(createFileDetailMeta(target, meta));
|
|
29938
|
+
});
|
|
29939
|
+
}
|
|
29659
29940
|
if (!repoTarget) {
|
|
29660
29941
|
const back = document.createElement("button");
|
|
29661
29942
|
back.type = "button";
|
|
@@ -29674,11 +29955,24 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
29674
29955
|
wrapper.appendChild(detailBody);
|
|
29675
29956
|
card.appendChild(wrapper);
|
|
29676
29957
|
mountFileShellCard({ $, repoFileTargetFromRoute, renderRepoBlobSidebar, placeSidebarToggle }, target, card, repoTarget);
|
|
29958
|
+
if (internalKind) {
|
|
29959
|
+
renderSourceInternalPath(card, target, internalKind);
|
|
29960
|
+
return;
|
|
29961
|
+
}
|
|
29677
29962
|
const controller = new AbortController;
|
|
29678
29963
|
ACTIVE_SOURCE_LOAD = { controller, req, target, card };
|
|
29679
29964
|
renderSourceLoading(card, target, () => cancelActiveSourceLoad("user"));
|
|
29680
29965
|
try {
|
|
29681
|
-
|
|
29966
|
+
let displayKind = sourceDisplayKind(target.path);
|
|
29967
|
+
let rawInfo = null;
|
|
29968
|
+
if (displayKind === "unsupported") {
|
|
29969
|
+
rawInfo = await loadRawFileInfo(target);
|
|
29970
|
+
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
29971
|
+
return;
|
|
29972
|
+
if (await sourceLooksTextByContent(target, rawInfo, controller.signal)) {
|
|
29973
|
+
displayKind = "text";
|
|
29974
|
+
}
|
|
29975
|
+
}
|
|
29682
29976
|
if (displayKind === "unsupported") {
|
|
29683
29977
|
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
29684
29978
|
return;
|
|
@@ -29694,7 +29988,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
29694
29988
|
return;
|
|
29695
29989
|
}
|
|
29696
29990
|
if (displayKind === "text") {
|
|
29697
|
-
const meta = await loadRawFileInfo(target);
|
|
29991
|
+
const meta = rawInfo ?? await loadRawFileInfo(target);
|
|
29698
29992
|
if (req !== SOURCE_REQ_SEQ || !sourceTargetsEqual(sourceTargetFromRoute(), target))
|
|
29699
29993
|
return;
|
|
29700
29994
|
if (!isVirtualSourceDisabled() && meta.size != null && meta.size >= VIRTUAL_SOURCE_SIZE_THRESHOLD) {
|
|
@@ -30259,7 +30553,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30259
30553
|
function routeFromLocation() {
|
|
30260
30554
|
const savedLanguage = viewerLanguageFromSearch(window.location.search) || savedViewerLanguage();
|
|
30261
30555
|
const parsedRoute = parseRoute(window.location.pathname, window.location.search, savedRange());
|
|
30262
|
-
const routeBase = parsedRoute.screen === "unknown" ? { screen: "diff", range: parsedRoute.range } : parsedRoute;
|
|
30556
|
+
const routeBase = parsedRoute.screen === "unknown" ? { screen: "diff", range: parsedRoute.range } : normalizeInternalFileRoute(parsedRoute);
|
|
30263
30557
|
return routeBase.screen === "help" && !new URLSearchParams(window.location.search).has("lang") ? { ...routeBase, lang: savedLanguage } : routeBase;
|
|
30264
30558
|
}
|
|
30265
30559
|
function applyPersistedStateToState() {
|
|
@@ -30292,6 +30586,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30292
30586
|
applySidebarHidden(STATE.sidebarHidden, { persist: false });
|
|
30293
30587
|
applyHistoryWidth(STATE.historyWidth, false);
|
|
30294
30588
|
applySidebarWidth(STATE.sbWidth, { persist: false });
|
|
30589
|
+
ANNOTATIONS_UI?.applyAnnotationPanelWidth(APP_SETTINGS.annotationPanelWidth ?? 380, false);
|
|
30295
30590
|
setLayout(STATE.layout, false);
|
|
30296
30591
|
applyTheme();
|
|
30297
30592
|
localizeViewerChrome();
|
|
@@ -30324,8 +30619,30 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30324
30619
|
})();
|
|
30325
30620
|
let highlightConfigured = false;
|
|
30326
30621
|
let REPO_SIDEBAR_REF = null;
|
|
30327
|
-
const LINE_REF_PILL = createLineRefPill(
|
|
30622
|
+
const LINE_REF_PILL = createLineRefPill({
|
|
30623
|
+
onClose: () => {
|
|
30624
|
+
clearLineSelection();
|
|
30625
|
+
}
|
|
30626
|
+
});
|
|
30328
30627
|
const DIFF_LINE_SELECT = createDiffLineSelect({ pill: LINE_REF_PILL });
|
|
30628
|
+
function clearRenderedSourceLineTargets() {
|
|
30629
|
+
document.querySelectorAll(".gdp-source-line-target").forEach((row) => {
|
|
30630
|
+
row.classList.remove("gdp-source-line-target");
|
|
30631
|
+
});
|
|
30632
|
+
}
|
|
30633
|
+
function clearLineSelection() {
|
|
30634
|
+
const route = STATE.route;
|
|
30635
|
+
if (route.screen === "file" && route.line) {
|
|
30636
|
+
const { line, ...rest } = route;
|
|
30637
|
+
setRoute(rest, true);
|
|
30638
|
+
return true;
|
|
30639
|
+
}
|
|
30640
|
+
if (route.screen === "diff") {
|
|
30641
|
+
return DIFF_LINE_SELECT.clear();
|
|
30642
|
+
}
|
|
30643
|
+
LINE_REF_PILL.hide();
|
|
30644
|
+
return false;
|
|
30645
|
+
}
|
|
30329
30646
|
function syncLineRefPill() {
|
|
30330
30647
|
const route = STATE.route;
|
|
30331
30648
|
if (route.screen === "diff")
|
|
@@ -30335,7 +30652,10 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30335
30652
|
const start = typeof route.line === "number" ? route.line : route.line.start;
|
|
30336
30653
|
const end = typeof route.line === "number" ? route.line : route.line.end;
|
|
30337
30654
|
LINE_REF_PILL.show(route.path, start, end);
|
|
30655
|
+
return;
|
|
30338
30656
|
}
|
|
30657
|
+
if (route.screen === "file")
|
|
30658
|
+
clearRenderedSourceLineTargets();
|
|
30339
30659
|
}
|
|
30340
30660
|
const SIDEBAR = createSidebar({
|
|
30341
30661
|
$,
|
|
@@ -30558,7 +30878,12 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30558
30878
|
queryHistory: "query history",
|
|
30559
30879
|
settings: "viewer settings",
|
|
30560
30880
|
theme: "toggle theme",
|
|
30561
|
-
product: "code viewer"
|
|
30881
|
+
product: "code viewer",
|
|
30882
|
+
copyAiContext: "Copy AI context (Shift+Click to include code)",
|
|
30883
|
+
copyAiContextCopied: "Copied AI context",
|
|
30884
|
+
copyAiContextCopiedWithCode: (lines) => `Copied AI context + code (${lines} line${lines === 1 ? "" : "s"})`,
|
|
30885
|
+
copyAiContextFailed: "Copy failed",
|
|
30886
|
+
copyAiContextEmpty: "Nothing to copy here"
|
|
30562
30887
|
},
|
|
30563
30888
|
topbar: {
|
|
30564
30889
|
resetRange: "reset to HEAD .. worktree",
|
|
@@ -30664,7 +30989,12 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30664
30989
|
queryHistory: "クエリ履歴",
|
|
30665
30990
|
settings: "ビューア設定",
|
|
30666
30991
|
theme: "テーマ切り替え",
|
|
30667
|
-
product: "code viewer"
|
|
30992
|
+
product: "code viewer",
|
|
30993
|
+
copyAiContext: "AI 用コンテキストをコピー(Shift+Click でコードも添付)",
|
|
30994
|
+
copyAiContextCopied: "コピーしました",
|
|
30995
|
+
copyAiContextCopiedWithCode: (lines) => `コピーしました(コード付き・${lines}行)`,
|
|
30996
|
+
copyAiContextFailed: "コピーに失敗しました",
|
|
30997
|
+
copyAiContextEmpty: "コピーする内容がありません"
|
|
30668
30998
|
},
|
|
30669
30999
|
topbar: {
|
|
30670
31000
|
resetRange: "HEAD .. worktree に戻す",
|
|
@@ -30798,8 +31128,15 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
30798
31128
|
viewerSettings.setAttribute("aria-label", text2.global.settings);
|
|
30799
31129
|
}
|
|
30800
31130
|
const theme = document.querySelector("#theme");
|
|
30801
|
-
if (theme)
|
|
31131
|
+
if (theme) {
|
|
30802
31132
|
theme.title = text2.global.theme;
|
|
31133
|
+
theme.setAttribute("aria-label", text2.global.theme);
|
|
31134
|
+
}
|
|
31135
|
+
const copyAiContext = document.querySelector("#copy-ai-context");
|
|
31136
|
+
if (copyAiContext) {
|
|
31137
|
+
copyAiContext.title = text2.global.copyAiContext;
|
|
31138
|
+
copyAiContext.setAttribute("aria-label", text2.global.copyAiContext);
|
|
31139
|
+
}
|
|
30803
31140
|
const refReset = document.querySelector("#ref-reset");
|
|
30804
31141
|
if (refReset)
|
|
30805
31142
|
refReset.title = text2.topbar.resetRange;
|
|
@@ -31011,6 +31348,22 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31011
31348
|
});
|
|
31012
31349
|
return highlightLoadPromise;
|
|
31013
31350
|
}
|
|
31351
|
+
function routeCanUseSyntaxHighlighter(route = STATE.route) {
|
|
31352
|
+
if (!STATE.syntaxHighlight)
|
|
31353
|
+
return false;
|
|
31354
|
+
if (route.screen === "diff" || route.screen === "history")
|
|
31355
|
+
return true;
|
|
31356
|
+
return route.screen === "file" && sourceInternalPathKind(route.path) === null;
|
|
31357
|
+
}
|
|
31358
|
+
function ensureSyntaxHighlighterForRoute() {
|
|
31359
|
+
if (!routeCanUseSyntaxHighlighter())
|
|
31360
|
+
return;
|
|
31361
|
+
loadSyntaxHighlighter().then((hljsRef) => {
|
|
31362
|
+
if (!hljsRef)
|
|
31363
|
+
return;
|
|
31364
|
+
rerenderLoadedDiffs();
|
|
31365
|
+
});
|
|
31366
|
+
}
|
|
31014
31367
|
function setLayout(layout, persist = true) {
|
|
31015
31368
|
STATE.layout = layout;
|
|
31016
31369
|
if (persist)
|
|
@@ -31290,6 +31643,21 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31290
31643
|
function isHistoryPanelRoute(route) {
|
|
31291
31644
|
return route.screen === "history" || isFileHistoryRoute(route);
|
|
31292
31645
|
}
|
|
31646
|
+
function normalizeInternalFileRoute(route) {
|
|
31647
|
+
if (route.screen !== "file")
|
|
31648
|
+
return route;
|
|
31649
|
+
if (sourceInternalPathKind(route.path) === null)
|
|
31650
|
+
return route;
|
|
31651
|
+
if (route.view === "blob" && !route.preview && !route.line)
|
|
31652
|
+
return route;
|
|
31653
|
+
return {
|
|
31654
|
+
screen: "file",
|
|
31655
|
+
path: route.path,
|
|
31656
|
+
ref: route.ref,
|
|
31657
|
+
range: route.range,
|
|
31658
|
+
view: "blob"
|
|
31659
|
+
};
|
|
31660
|
+
}
|
|
31293
31661
|
function parkRangeForHistory() {
|
|
31294
31662
|
if (preHistoryRange === null)
|
|
31295
31663
|
preHistoryRange = { from: STATE.from, to: STATE.to };
|
|
@@ -31396,7 +31764,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31396
31764
|
}
|
|
31397
31765
|
function setRoute(route, replace2 = false) {
|
|
31398
31766
|
const previousRoute = STATE.route;
|
|
31399
|
-
let nextRoute = route.screen === "unknown" ? { screen: "diff", range: route.range } : route;
|
|
31767
|
+
let nextRoute = route.screen === "unknown" ? { screen: "diff", range: route.range } : normalizeInternalFileRoute(route);
|
|
31400
31768
|
if (isHistoryPanelRoute(previousRoute) && !isHistoryPanelRoute(nextRoute)) {
|
|
31401
31769
|
if (preHistoryRange)
|
|
31402
31770
|
nextRoute = { ...nextRoute, range: preHistoryRange };
|
|
@@ -31676,6 +32044,24 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31676
32044
|
applyViewedState,
|
|
31677
32045
|
enqueueInitialLoads
|
|
31678
32046
|
} = DIFF_VIEW;
|
|
32047
|
+
function setGlobalHeaderIcons() {
|
|
32048
|
+
const annotationsIcon = document.querySelector("#annotations-toggle .goi-icon");
|
|
32049
|
+
if (annotationsIcon) {
|
|
32050
|
+
annotationsIcon.innerHTML = iconSvg("octicon-comment-discussion", COMMENT_DISCUSSION_16_PATH);
|
|
32051
|
+
}
|
|
32052
|
+
const doctorIcon = document.querySelector("#doctor-btn .goi-icon");
|
|
32053
|
+
if (doctorIcon) {
|
|
32054
|
+
doctorIcon.innerHTML = iconSvg("octicon-pulse", PULSE_16_PATH);
|
|
32055
|
+
}
|
|
32056
|
+
const themeButton = document.querySelector("#theme");
|
|
32057
|
+
if (themeButton) {
|
|
32058
|
+
themeButton.innerHTML = iconSvg("octicon-moon", MOON_16_PATH);
|
|
32059
|
+
}
|
|
32060
|
+
const copyAiContextButton = document.querySelector("#copy-ai-context");
|
|
32061
|
+
if (copyAiContextButton) {
|
|
32062
|
+
copyAiContextButton.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
|
|
32063
|
+
}
|
|
32064
|
+
}
|
|
31679
32065
|
applySidebarFontSize();
|
|
31680
32066
|
applyCodeFontSize();
|
|
31681
32067
|
applySidebarHidden(STATE.sidebarHidden, { persist: false });
|
|
@@ -31683,6 +32069,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31683
32069
|
installHistoryPageDom();
|
|
31684
32070
|
hydrateRefSelectorMounts();
|
|
31685
32071
|
setSidebarTreeActionIcons();
|
|
32072
|
+
setGlobalHeaderIcons();
|
|
31686
32073
|
$$(".sb-view-seg button").forEach((b2) => {
|
|
31687
32074
|
b2.addEventListener("click", () => {
|
|
31688
32075
|
STATE.sbView = b2.dataset.view || "tree";
|
|
@@ -31698,6 +32085,67 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
31698
32085
|
event.preventDefault();
|
|
31699
32086
|
toggleDoctorSheet();
|
|
31700
32087
|
});
|
|
32088
|
+
let copyAiContextFeedbackTimer = null;
|
|
32089
|
+
$("#copy-ai-context")?.addEventListener("click", async (event) => {
|
|
32090
|
+
const button = event.currentTarget;
|
|
32091
|
+
const feedback = document.querySelector("#copy-ai-context-feedback");
|
|
32092
|
+
const selectionTarget = resolveSelectionTarget(STATE.route);
|
|
32093
|
+
let selectionCode;
|
|
32094
|
+
if (event.shiftKey && selectionTarget) {
|
|
32095
|
+
const renderedLines = readRenderedLines(selectionTarget.path, selectionTarget.start, selectionTarget.end);
|
|
32096
|
+
if (renderedLines.length > 0) {
|
|
32097
|
+
selectionCode = {
|
|
32098
|
+
lines: renderedLines,
|
|
32099
|
+
lang: langFromPath(selectionTarget.path)
|
|
32100
|
+
};
|
|
32101
|
+
}
|
|
32102
|
+
}
|
|
32103
|
+
const text2 = aiContextClipboardText({
|
|
32104
|
+
route: STATE.route,
|
|
32105
|
+
diffFrom: STATE.from,
|
|
32106
|
+
diffTo: STATE.to,
|
|
32107
|
+
selectionCode
|
|
32108
|
+
});
|
|
32109
|
+
const finish = (ok, withCode, lineCount, reason) => {
|
|
32110
|
+
const label = reason === "empty" ? uiText().global.copyAiContextEmpty : ok ? withCode ? uiText().global.copyAiContextCopiedWithCode(lineCount) : uiText().global.copyAiContextCopied : uiText().global.copyAiContextFailed;
|
|
32111
|
+
const isLargeCopy = ok && withCode && lineCount >= AI_CONTEXT_LARGE_SELECTION_LINE_THRESHOLD;
|
|
32112
|
+
const stateClass = reason === "empty" ? "" : ok ? isLargeCopy ? "warn" : "copied" : "failed";
|
|
32113
|
+
button.classList.remove("copied", "failed", "warn");
|
|
32114
|
+
if (stateClass)
|
|
32115
|
+
button.classList.add(stateClass);
|
|
32116
|
+
button.title = label;
|
|
32117
|
+
button.setAttribute("aria-label", label);
|
|
32118
|
+
if (feedback) {
|
|
32119
|
+
feedback.textContent = label;
|
|
32120
|
+
feedback.classList.remove("copied", "failed", "warn");
|
|
32121
|
+
if (stateClass)
|
|
32122
|
+
feedback.classList.add(stateClass);
|
|
32123
|
+
feedback.hidden = false;
|
|
32124
|
+
}
|
|
32125
|
+
if (copyAiContextFeedbackTimer)
|
|
32126
|
+
clearTimeout(copyAiContextFeedbackTimer);
|
|
32127
|
+
copyAiContextFeedbackTimer = setTimeout(() => {
|
|
32128
|
+
copyAiContextFeedbackTimer = null;
|
|
32129
|
+
button.classList.remove("copied", "failed", "warn");
|
|
32130
|
+
button.title = uiText().global.copyAiContext;
|
|
32131
|
+
button.setAttribute("aria-label", uiText().global.copyAiContext);
|
|
32132
|
+
if (feedback) {
|
|
32133
|
+
feedback.hidden = true;
|
|
32134
|
+
feedback.classList.remove("copied", "failed", "warn");
|
|
32135
|
+
}
|
|
32136
|
+
}, 1200);
|
|
32137
|
+
};
|
|
32138
|
+
if (!text2) {
|
|
32139
|
+
finish(false, false, 0, "empty");
|
|
32140
|
+
return;
|
|
32141
|
+
}
|
|
32142
|
+
try {
|
|
32143
|
+
await navigator.clipboard.writeText(text2);
|
|
32144
|
+
finish(true, !!selectionCode, selectionCode?.lines.length ?? 0);
|
|
32145
|
+
} catch {
|
|
32146
|
+
finish(false, false, 0);
|
|
32147
|
+
}
|
|
32148
|
+
});
|
|
31701
32149
|
$("#scope-settings-close")?.addEventListener("click", closeScopeSettings);
|
|
31702
32150
|
$("#scope-omit-reset")?.addEventListener("click", resetScopeSettings);
|
|
31703
32151
|
$("#viewer-language")?.addEventListener("change", (event) => {
|
|
@@ -32050,6 +32498,18 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32050
32498
|
$("#theme").click();
|
|
32051
32499
|
return true;
|
|
32052
32500
|
}
|
|
32501
|
+
if (action === "copy-ai-context") {
|
|
32502
|
+
$("#copy-ai-context")?.click();
|
|
32503
|
+
return true;
|
|
32504
|
+
}
|
|
32505
|
+
if (action === "copy-ai-context-with-code") {
|
|
32506
|
+
$("#copy-ai-context")?.dispatchEvent(new MouseEvent("click", {
|
|
32507
|
+
bubbles: true,
|
|
32508
|
+
cancelable: true,
|
|
32509
|
+
shiftKey: true
|
|
32510
|
+
}));
|
|
32511
|
+
return true;
|
|
32512
|
+
}
|
|
32053
32513
|
if (action === "open-help") {
|
|
32054
32514
|
openHelpKeybindings({
|
|
32055
32515
|
getRoute: () => STATE.route,
|
|
@@ -32078,6 +32538,10 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32078
32538
|
if (e2.__gdpVirtualSourcePagingHandled)
|
|
32079
32539
|
return;
|
|
32080
32540
|
const targetEl = e2.target;
|
|
32541
|
+
if (e2.key === "Escape" && !isEditableKeyTarget(targetEl) && clearLineSelection()) {
|
|
32542
|
+
e2.preventDefault();
|
|
32543
|
+
return;
|
|
32544
|
+
}
|
|
32081
32545
|
if ((e2.ctrlKey || e2.metaKey) && !e2.shiftKey && !e2.altKey && e2.key.toLowerCase() === "z" && !isEditableKeyTarget(targetEl)) {
|
|
32082
32546
|
if (await undoLastAction())
|
|
32083
32547
|
e2.preventDefault();
|
|
@@ -32390,7 +32854,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32390
32854
|
const routeLanguage = viewerLanguageFromSearch(window.location.search);
|
|
32391
32855
|
if (routeLanguage && routeLanguage !== STATE.language)
|
|
32392
32856
|
setViewerLanguage(routeLanguage);
|
|
32393
|
-
|
|
32857
|
+
let nextRoute = parsedRoute.screen === "unknown" ? { screen: "diff", range: parsedRoute.range } : parsedRoute;
|
|
32858
|
+
nextRoute = normalizeInternalFileRoute(nextRoute);
|
|
32394
32859
|
if (previousRoute.screen === "database" && nextRoute.screen !== "database")
|
|
32395
32860
|
DATABASE_VIEW.suspend();
|
|
32396
32861
|
if (isHistoryPanelRoute(previousRoute) && !isHistoryPanelRoute(nextRoute))
|
|
@@ -32400,6 +32865,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32400
32865
|
STATE.route = nextRoute.screen === "help" && !new URLSearchParams(window.location.search).has("lang") ? { ...nextRoute, lang: STATE.language } : nextRoute;
|
|
32401
32866
|
STATE.from = STATE.route.range.from;
|
|
32402
32867
|
STATE.to = STATE.route.range.to;
|
|
32868
|
+
ensureSyntaxHighlighterForRoute();
|
|
32403
32869
|
if (STATE.route.screen === "repo" || STATE.route.screen === "file" && (STATE.route.view === "blob" || STATE.route.view === "blame" || STATE.route.view === "history"))
|
|
32404
32870
|
STATE.repoRef = STATE.route.ref || "worktree";
|
|
32405
32871
|
ANNOTATIONS_UI?.restoreSessionFromUrl();
|
|
@@ -32491,11 +32957,7 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32491
32957
|
patchSettings({ syntaxHighlight: on });
|
|
32492
32958
|
setHighlightButton(on && getHljs() ? "loaded" : "idle");
|
|
32493
32959
|
if (on) {
|
|
32494
|
-
|
|
32495
|
-
if (!hljsRef)
|
|
32496
|
-
return;
|
|
32497
|
-
rerenderLoadedDiffs();
|
|
32498
|
-
});
|
|
32960
|
+
ensureSyntaxHighlighterForRoute();
|
|
32499
32961
|
} else {
|
|
32500
32962
|
rerenderLoadedDiffs();
|
|
32501
32963
|
}
|
|
@@ -32581,6 +33043,8 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32581
33043
|
getRoute: () => STATE.route,
|
|
32582
33044
|
getAnnotationPanelOpen: () => APP_SETTINGS.annotationPanelOpen === true,
|
|
32583
33045
|
setAnnotationPanelOpenState: (open) => patchSettings({ annotationPanelOpen: open }),
|
|
33046
|
+
getAnnotationPanelWidth: () => APP_SETTINGS.annotationPanelWidth,
|
|
33047
|
+
setAnnotationPanelWidth: (width) => patchSettings({ annotationPanelWidth: width }),
|
|
32584
33048
|
getAnnotationFollow: () => APP_SETTINGS.annotationFollow !== false,
|
|
32585
33049
|
setAnnotationFollow: (follow) => patchSettings({ annotationFollow: follow }),
|
|
32586
33050
|
leaveDatabaseView: () => {
|
|
@@ -32600,6 +33064,34 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32600
33064
|
patchSettings({ range: currentRange() });
|
|
32601
33065
|
}
|
|
32602
33066
|
});
|
|
33067
|
+
(function setupAnnotationPanelResizer() {
|
|
33068
|
+
const panel = document.getElementById("annotation-panel");
|
|
33069
|
+
const handle = document.getElementById("annotation-panel-resizer");
|
|
33070
|
+
if (!panel || !handle)
|
|
33071
|
+
return;
|
|
33072
|
+
let dragging = false;
|
|
33073
|
+
let startX = 0;
|
|
33074
|
+
let startW = 0;
|
|
33075
|
+
handle.addEventListener("mousedown", (e2) => {
|
|
33076
|
+
dragging = true;
|
|
33077
|
+
startX = e2.clientX;
|
|
33078
|
+
startW = panel.offsetWidth;
|
|
33079
|
+
document.body.classList.add("gdp-annotation-resizing");
|
|
33080
|
+
e2.preventDefault();
|
|
33081
|
+
});
|
|
33082
|
+
window.addEventListener("mousemove", (e2) => {
|
|
33083
|
+
if (!dragging)
|
|
33084
|
+
return;
|
|
33085
|
+
ANNOTATIONS_UI?.applyAnnotationPanelWidth(startW - (e2.clientX - startX), false);
|
|
33086
|
+
});
|
|
33087
|
+
window.addEventListener("mouseup", () => {
|
|
33088
|
+
if (!dragging)
|
|
33089
|
+
return;
|
|
33090
|
+
dragging = false;
|
|
33091
|
+
document.body.classList.remove("gdp-annotation-resizing");
|
|
33092
|
+
ANNOTATIONS_UI?.applyAnnotationPanelWidth(panel.offsetWidth);
|
|
33093
|
+
});
|
|
33094
|
+
})();
|
|
32603
33095
|
replaceUrlWithCurrentRoute();
|
|
32604
33096
|
createAnnotationsPlayer({
|
|
32605
33097
|
$,
|
|
@@ -32835,46 +33327,85 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32835
33327
|
}
|
|
32836
33328
|
}, 350);
|
|
32837
33329
|
}
|
|
32838
|
-
const es = new EventSource("/events");
|
|
32839
33330
|
const catchUpGate = createCatchUpGate(() => Date.now(), 1000);
|
|
32840
33331
|
let openedOnce = false;
|
|
32841
|
-
|
|
32842
|
-
|
|
32843
|
-
|
|
32844
|
-
|
|
32845
|
-
|
|
32846
|
-
|
|
32847
|
-
|
|
32848
|
-
|
|
32849
|
-
|
|
32850
|
-
}
|
|
32851
|
-
|
|
32852
|
-
|
|
32853
|
-
|
|
32854
|
-
|
|
32855
|
-
|
|
32856
|
-
|
|
32857
|
-
|
|
32858
|
-
|
|
32859
|
-
|
|
32860
|
-
|
|
32861
|
-
|
|
32862
|
-
|
|
32863
|
-
|
|
32864
|
-
|
|
32865
|
-
|
|
32866
|
-
|
|
32867
|
-
|
|
32868
|
-
|
|
32869
|
-
|
|
32870
|
-
|
|
32871
|
-
|
|
32872
|
-
|
|
32873
|
-
|
|
33332
|
+
let eventSource = null;
|
|
33333
|
+
let eventSourceConnectTimer = null;
|
|
33334
|
+
function shouldConnectEventSource() {
|
|
33335
|
+
return document.visibilityState === "visible";
|
|
33336
|
+
}
|
|
33337
|
+
function disconnectEventSource() {
|
|
33338
|
+
if (eventSourceConnectTimer !== null) {
|
|
33339
|
+
window.clearTimeout(eventSourceConnectTimer);
|
|
33340
|
+
eventSourceConnectTimer = null;
|
|
33341
|
+
}
|
|
33342
|
+
eventSource?.close();
|
|
33343
|
+
eventSource = null;
|
|
33344
|
+
}
|
|
33345
|
+
function connectEventSource() {
|
|
33346
|
+
if (!shouldConnectEventSource())
|
|
33347
|
+
return;
|
|
33348
|
+
if (eventSource)
|
|
33349
|
+
return;
|
|
33350
|
+
const es = new EventSource("/events");
|
|
33351
|
+
eventSource = es;
|
|
33352
|
+
es.addEventListener("update", (event) => {
|
|
33353
|
+
const raw = event.data;
|
|
33354
|
+
let paths = null;
|
|
33355
|
+
if (raw && raw !== "tick") {
|
|
33356
|
+
try {
|
|
33357
|
+
const parsed = JSON.parse(raw);
|
|
33358
|
+
if (Array.isArray(parsed.paths))
|
|
33359
|
+
paths = parsed.paths;
|
|
33360
|
+
} catch {}
|
|
33361
|
+
}
|
|
33362
|
+
scheduleSseLoad(paths);
|
|
33363
|
+
});
|
|
33364
|
+
es.addEventListener("watch-limit", (event) => {
|
|
33365
|
+
const raw = event.data;
|
|
33366
|
+
const limit = Number(raw);
|
|
33367
|
+
if (Number.isFinite(limit) && limit > 0)
|
|
33368
|
+
showWatchLimitBanner(limit);
|
|
33369
|
+
});
|
|
33370
|
+
es.addEventListener("reload", () => location.reload());
|
|
33371
|
+
es.addEventListener("annotation", (event) => {
|
|
33372
|
+
ANNOTATIONS_UI?.handleSse(event.data);
|
|
33373
|
+
});
|
|
33374
|
+
es.addEventListener("db-query", (event) => {
|
|
33375
|
+
DATABASE_VIEW.handleSse("db-query", event.data);
|
|
33376
|
+
});
|
|
33377
|
+
es.addEventListener("db-snapshot", (event) => {
|
|
33378
|
+
DATABASE_VIEW.handleSse("db-snapshot", event.data);
|
|
33379
|
+
});
|
|
33380
|
+
es.addEventListener("error", () => setStatus("error"));
|
|
33381
|
+
es.addEventListener("open", () => {
|
|
33382
|
+
setStatus("live");
|
|
33383
|
+
if (!openedOnce) {
|
|
33384
|
+
openedOnce = true;
|
|
33385
|
+
return;
|
|
33386
|
+
}
|
|
33387
|
+
catchUpDiff();
|
|
33388
|
+
});
|
|
33389
|
+
}
|
|
33390
|
+
function scheduleEventSourceConnect() {
|
|
33391
|
+
if (!shouldConnectEventSource())
|
|
33392
|
+
return;
|
|
33393
|
+
if (eventSource || eventSourceConnectTimer !== null)
|
|
33394
|
+
return;
|
|
33395
|
+
const schedule = () => {
|
|
33396
|
+
eventSourceConnectTimer = window.setTimeout(() => {
|
|
33397
|
+
eventSourceConnectTimer = null;
|
|
33398
|
+
connectEventSource();
|
|
33399
|
+
}, 1000);
|
|
33400
|
+
};
|
|
33401
|
+
if (document.readyState === "complete") {
|
|
33402
|
+
schedule();
|
|
32874
33403
|
return;
|
|
32875
33404
|
}
|
|
32876
|
-
|
|
32877
|
-
}
|
|
33405
|
+
window.addEventListener("load", schedule, { once: true });
|
|
33406
|
+
}
|
|
33407
|
+
scheduleEventSourceConnect();
|
|
33408
|
+
window.addEventListener("pagehide", disconnectEventSource);
|
|
32878
33409
|
function catchUpDiff() {
|
|
32879
33410
|
const historyWorktreeSelected = HISTORY_VIEW.isWorktreeSelected();
|
|
32880
33411
|
if (!shouldAutoLoadCurrentRoute())
|
|
@@ -32890,9 +33421,18 @@ code-viewer query snapshot delete --id snap-abc123`
|
|
|
32890
33421
|
load({ force: true });
|
|
32891
33422
|
}
|
|
32892
33423
|
document.addEventListener("visibilitychange", () => {
|
|
32893
|
-
if (
|
|
32894
|
-
|
|
33424
|
+
if (document.hidden) {
|
|
33425
|
+
disconnectEventSource();
|
|
33426
|
+
return;
|
|
33427
|
+
}
|
|
33428
|
+
scheduleEventSourceConnect();
|
|
33429
|
+
catchUpDiff();
|
|
33430
|
+
ANNOTATIONS_UI?.refreshAnnotations();
|
|
33431
|
+
});
|
|
33432
|
+
window.addEventListener("focus", () => {
|
|
33433
|
+
scheduleEventSourceConnect();
|
|
33434
|
+
catchUpDiff();
|
|
33435
|
+
ANNOTATIONS_UI?.refreshAnnotations();
|
|
32895
33436
|
});
|
|
32896
|
-
window.addEventListener("focus", catchUpDiff);
|
|
32897
33437
|
})();
|
|
32898
33438
|
})();
|