@bendyline/docblocks-react 1.1.2 → 2.1.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.
Files changed (225) hide show
  1. package/README.md +37 -5
  2. package/dist/ExportDialog-7LDIXJZ3.js +10 -0
  3. package/dist/ExportDialog-7LDIXJZ3.js.map +1 -0
  4. package/dist/ExportToolbarControls-GHAOJMH6.js +508 -0
  5. package/dist/ExportToolbarControls-GHAOJMH6.js.map +1 -0
  6. package/dist/GitToolbarControl-GNMRVKWQ.js +136 -0
  7. package/dist/GitToolbarControl-GNMRVKWQ.js.map +1 -0
  8. package/dist/GitUI-VHOBQY43.js +1133 -0
  9. package/dist/GitUI-VHOBQY43.js.map +1 -0
  10. package/dist/LazyEditorShell-EF2BWRXU.js +6 -0
  11. package/dist/LazyEditorShell-EF2BWRXU.js.map +1 -0
  12. package/dist/ShareDialog-63ENBEDZ.js +213 -0
  13. package/dist/ShareDialog-63ENBEDZ.js.map +1 -0
  14. package/dist/chunk-4XXSWN3T.js +13 -0
  15. package/dist/chunk-4XXSWN3T.js.map +1 -0
  16. package/dist/chunk-57ZJJOC5.js +89 -0
  17. package/dist/chunk-57ZJJOC5.js.map +1 -0
  18. package/dist/chunk-5A4KEWKT.js +97 -0
  19. package/dist/chunk-5A4KEWKT.js.map +1 -0
  20. package/dist/chunk-DD4VFJQI.js +51 -0
  21. package/dist/chunk-DD4VFJQI.js.map +1 -0
  22. package/dist/chunk-FEWQUQML.js +256 -0
  23. package/dist/chunk-FEWQUQML.js.map +1 -0
  24. package/dist/chunk-FMGTHSTX.js +110 -0
  25. package/dist/chunk-FMGTHSTX.js.map +1 -0
  26. package/dist/chunk-UNYZQXWR.js +324 -0
  27. package/dist/chunk-UNYZQXWR.js.map +1 -0
  28. package/dist/chunk-VHDP4IPL.js +70 -0
  29. package/dist/chunk-VHDP4IPL.js.map +1 -0
  30. package/dist/chunk-ZI56BNB7.js +270 -0
  31. package/dist/chunk-ZI56BNB7.js.map +1 -0
  32. package/dist/editor.d.ts +11 -0
  33. package/dist/editor.js +9 -0
  34. package/dist/editor.js.map +1 -0
  35. package/dist/export/index.d.ts +93 -0
  36. package/dist/export/index.js +27 -0
  37. package/dist/export/index.js.map +1 -0
  38. package/dist/index.d.ts +346 -18
  39. package/dist/index.js +6169 -18
  40. package/dist/index.js.map +1 -1
  41. package/dist/run-export-ICTZITXC.js +10 -0
  42. package/dist/run-export-ICTZITXC.js.map +1 -0
  43. package/dist/settings/index.d.ts +36 -0
  44. package/dist/settings/index.js +14 -0
  45. package/dist/settings/index.js.map +1 -0
  46. package/package.json +33 -13
  47. package/src/styles/docblocks.css +2738 -132
  48. package/dist/AppMenu/AppMenu.d.ts +0 -26
  49. package/dist/AppMenu/AppMenu.d.ts.map +0 -1
  50. package/dist/AppMenu/AppMenu.js +0 -28
  51. package/dist/AppMenu/AppMenu.js.map +0 -1
  52. package/dist/AppMenu/index.d.ts +0 -3
  53. package/dist/AppMenu/index.d.ts.map +0 -1
  54. package/dist/AppMenu/index.js +0 -2
  55. package/dist/AppMenu/index.js.map +0 -1
  56. package/dist/DocBlocksShell/DocBlocksShell.d.ts +0 -36
  57. package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +0 -1
  58. package/dist/DocBlocksShell/DocBlocksShell.js +0 -1351
  59. package/dist/DocBlocksShell/DocBlocksShell.js.map +0 -1
  60. package/dist/DocBlocksShell/index.d.ts +0 -3
  61. package/dist/DocBlocksShell/index.d.ts.map +0 -1
  62. package/dist/DocBlocksShell/index.js +0 -2
  63. package/dist/DocBlocksShell/index.js.map +0 -1
  64. package/dist/Export/ExportDialog.d.ts +0 -16
  65. package/dist/Export/ExportDialog.d.ts.map +0 -1
  66. package/dist/Export/ExportDialog.js +0 -158
  67. package/dist/Export/ExportDialog.js.map +0 -1
  68. package/dist/Export/ExportToolbarControls.d.ts +0 -17
  69. package/dist/Export/ExportToolbarControls.d.ts.map +0 -1
  70. package/dist/Export/ExportToolbarControls.js +0 -200
  71. package/dist/Export/ExportToolbarControls.js.map +0 -1
  72. package/dist/Export/export-options.d.ts +0 -53
  73. package/dist/Export/export-options.d.ts.map +0 -1
  74. package/dist/Export/export-options.js +0 -49
  75. package/dist/Export/export-options.js.map +0 -1
  76. package/dist/Export/index.d.ts +0 -6
  77. package/dist/Export/index.d.ts.map +0 -1
  78. package/dist/Export/index.js +0 -3
  79. package/dist/Export/index.js.map +0 -1
  80. package/dist/Export/run-export.d.ts +0 -8
  81. package/dist/Export/run-export.d.ts.map +0 -1
  82. package/dist/Export/run-export.js +0 -296
  83. package/dist/Export/run-export.js.map +0 -1
  84. package/dist/Export/transform-summaries.d.ts +0 -7
  85. package/dist/Export/transform-summaries.d.ts.map +0 -1
  86. package/dist/Export/transform-summaries.js +0 -6
  87. package/dist/Export/transform-summaries.js.map +0 -1
  88. package/dist/FileExplorer/FileExplorer.d.ts +0 -21
  89. package/dist/FileExplorer/FileExplorer.d.ts.map +0 -1
  90. package/dist/FileExplorer/FileExplorer.js +0 -140
  91. package/dist/FileExplorer/FileExplorer.js.map +0 -1
  92. package/dist/FileExplorer/FileTreeNode.d.ts +0 -18
  93. package/dist/FileExplorer/FileTreeNode.d.ts.map +0 -1
  94. package/dist/FileExplorer/FileTreeNode.js +0 -112
  95. package/dist/FileExplorer/FileTreeNode.js.map +0 -1
  96. package/dist/FileExplorer/index.d.ts +0 -6
  97. package/dist/FileExplorer/index.d.ts.map +0 -1
  98. package/dist/FileExplorer/index.js +0 -4
  99. package/dist/FileExplorer/index.js.map +0 -1
  100. package/dist/FileExplorer/useFileTree.d.ts +0 -35
  101. package/dist/FileExplorer/useFileTree.d.ts.map +0 -1
  102. package/dist/FileExplorer/useFileTree.js +0 -124
  103. package/dist/FileExplorer/useFileTree.js.map +0 -1
  104. package/dist/WorkspacePicker/WorkspacePicker.d.ts +0 -17
  105. package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +0 -1
  106. package/dist/WorkspacePicker/WorkspacePicker.js +0 -63
  107. package/dist/WorkspacePicker/WorkspacePicker.js.map +0 -1
  108. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts +0 -11
  109. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts.map +0 -1
  110. package/dist/WorkspacePicker/WorkspaceSettingsButton.js +0 -27
  111. package/dist/WorkspacePicker/WorkspaceSettingsButton.js.map +0 -1
  112. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts +0 -20
  113. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts.map +0 -1
  114. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js +0 -36
  115. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js.map +0 -1
  116. package/dist/WorkspacePicker/index.d.ts +0 -3
  117. package/dist/WorkspacePicker/index.d.ts.map +0 -1
  118. package/dist/WorkspacePicker/index.js +0 -2
  119. package/dist/WorkspacePicker/index.js.map +0 -1
  120. package/dist/hooks/index.d.ts +0 -2
  121. package/dist/hooks/index.d.ts.map +0 -1
  122. package/dist/hooks/index.js +0 -2
  123. package/dist/hooks/index.js.map +0 -1
  124. package/dist/hooks/useAutoSave.d.ts +0 -15
  125. package/dist/hooks/useAutoSave.d.ts.map +0 -1
  126. package/dist/hooks/useAutoSave.js +0 -83
  127. package/dist/hooks/useAutoSave.js.map +0 -1
  128. package/dist/icons.d.ts +0 -7
  129. package/dist/icons.d.ts.map +0 -1
  130. package/dist/icons.js +0 -27
  131. package/dist/icons.js.map +0 -1
  132. package/dist/index.d.ts.map +0 -1
  133. package/dist/monaco-slim.d.ts +0 -19
  134. package/dist/monaco-slim.d.ts.map +0 -1
  135. package/dist/monaco-slim.js +0 -19
  136. package/dist/monaco-slim.js.map +0 -1
  137. package/dist/preferences/versioning.d.ts +0 -27
  138. package/dist/preferences/versioning.d.ts.map +0 -1
  139. package/dist/preferences/versioning.js +0 -62
  140. package/dist/preferences/versioning.js.map +0 -1
  141. package/src/AppMenu/AppMenu.tsx +0 -264
  142. package/src/AppMenu/index.ts +0 -2
  143. package/src/DocBlocksShell/DocBlocksShell.tsx +0 -1778
  144. package/src/DocBlocksShell/index.ts +0 -2
  145. package/src/Export/ExportDialog.tsx +0 -383
  146. package/src/Export/ExportToolbarControls.tsx +0 -313
  147. package/src/Export/export-options.ts +0 -99
  148. package/src/Export/index.ts +0 -5
  149. package/src/Export/run-export.ts +0 -349
  150. package/src/Export/transform-summaries.ts +0 -14
  151. package/src/FileExplorer/FileExplorer.tsx +0 -282
  152. package/src/FileExplorer/FileTreeNode.tsx +0 -214
  153. package/src/FileExplorer/index.ts +0 -5
  154. package/src/FileExplorer/useFileTree.ts +0 -178
  155. package/src/WorkspacePicker/WorkspacePicker.tsx +0 -137
  156. package/src/WorkspacePicker/WorkspaceSettingsButton.tsx +0 -88
  157. package/src/WorkspacePicker/WorkspaceSettingsDialog.tsx +0 -121
  158. package/src/WorkspacePicker/index.ts +0 -2
  159. package/src/fonts/fonts.css +0 -362
  160. package/src/fonts/licenses/LICENSE-cormorant-garamond.txt +0 -93
  161. package/src/fonts/licenses/LICENSE-crimson-text.txt +0 -93
  162. package/src/fonts/licenses/LICENSE-dm-sans.txt +0 -93
  163. package/src/fonts/licenses/LICENSE-dm-serif-display.txt +0 -93
  164. package/src/fonts/licenses/LICENSE-hanken-grotesk.txt +0 -94
  165. package/src/fonts/licenses/LICENSE-ibm-plex-sans.txt +0 -93
  166. package/src/fonts/licenses/LICENSE-inter.txt +0 -93
  167. package/src/fonts/licenses/LICENSE-jetbrains-mono.txt +0 -93
  168. package/src/fonts/licenses/LICENSE-lora.txt +0 -93
  169. package/src/fonts/licenses/LICENSE-merriweather.txt +0 -93
  170. package/src/fonts/licenses/LICENSE-oswald.txt +0 -93
  171. package/src/fonts/licenses/LICENSE-playfair-display.txt +0 -93
  172. package/src/fonts/licenses/LICENSE-pt-serif.txt +0 -93
  173. package/src/fonts/licenses/LICENSE-roboto.txt +0 -93
  174. package/src/fonts/licenses/LICENSE-source-serif-4.txt +0 -93
  175. package/src/fonts/woff2/cormorant-garamond-400.woff2 +0 -0
  176. package/src/fonts/woff2/cormorant-garamond-700.woff2 +0 -0
  177. package/src/fonts/woff2/crimson-text-400.woff2 +0 -0
  178. package/src/fonts/woff2/crimson-text-400i.woff2 +0 -0
  179. package/src/fonts/woff2/crimson-text-700.woff2 +0 -0
  180. package/src/fonts/woff2/dm-sans-400.woff2 +0 -0
  181. package/src/fonts/woff2/dm-sans-400i.woff2 +0 -0
  182. package/src/fonts/woff2/dm-sans-500.woff2 +0 -0
  183. package/src/fonts/woff2/dm-sans-700.woff2 +0 -0
  184. package/src/fonts/woff2/dm-serif-display-400.woff2 +0 -0
  185. package/src/fonts/woff2/hanken-grotesk-400.woff2 +0 -0
  186. package/src/fonts/woff2/hanken-grotesk-400i.woff2 +0 -0
  187. package/src/fonts/woff2/hanken-grotesk-500.woff2 +0 -0
  188. package/src/fonts/woff2/hanken-grotesk-600.woff2 +0 -0
  189. package/src/fonts/woff2/hanken-grotesk-700.woff2 +0 -0
  190. package/src/fonts/woff2/ibm-plex-sans-400.woff2 +0 -0
  191. package/src/fonts/woff2/ibm-plex-sans-400i.woff2 +0 -0
  192. package/src/fonts/woff2/ibm-plex-sans-500.woff2 +0 -0
  193. package/src/fonts/woff2/ibm-plex-sans-600.woff2 +0 -0
  194. package/src/fonts/woff2/ibm-plex-sans-700.woff2 +0 -0
  195. package/src/fonts/woff2/inter-400.woff2 +0 -0
  196. package/src/fonts/woff2/inter-400i.woff2 +0 -0
  197. package/src/fonts/woff2/inter-500.woff2 +0 -0
  198. package/src/fonts/woff2/inter-600.woff2 +0 -0
  199. package/src/fonts/woff2/inter-700.woff2 +0 -0
  200. package/src/fonts/woff2/jetbrains-mono-400.woff2 +0 -0
  201. package/src/fonts/woff2/jetbrains-mono-400i.woff2 +0 -0
  202. package/src/fonts/woff2/jetbrains-mono-700.woff2 +0 -0
  203. package/src/fonts/woff2/lora-400.woff2 +0 -0
  204. package/src/fonts/woff2/lora-400i.woff2 +0 -0
  205. package/src/fonts/woff2/lora-700.woff2 +0 -0
  206. package/src/fonts/woff2/merriweather-400.woff2 +0 -0
  207. package/src/fonts/woff2/merriweather-700.woff2 +0 -0
  208. package/src/fonts/woff2/oswald-400.woff2 +0 -0
  209. package/src/fonts/woff2/oswald-700.woff2 +0 -0
  210. package/src/fonts/woff2/playfair-display-400.woff2 +0 -0
  211. package/src/fonts/woff2/playfair-display-700.woff2 +0 -0
  212. package/src/fonts/woff2/pt-serif-400.woff2 +0 -0
  213. package/src/fonts/woff2/pt-serif-700.woff2 +0 -0
  214. package/src/fonts/woff2/roboto-400.woff2 +0 -0
  215. package/src/fonts/woff2/roboto-400i.woff2 +0 -0
  216. package/src/fonts/woff2/roboto-700.woff2 +0 -0
  217. package/src/fonts/woff2/source-serif-4-400.woff2 +0 -0
  218. package/src/fonts/woff2/source-serif-4-400i.woff2 +0 -0
  219. package/src/fonts/woff2/source-serif-4-700.woff2 +0 -0
  220. package/src/hooks/index.ts +0 -1
  221. package/src/hooks/useAutoSave.ts +0 -116
  222. package/src/icons.tsx +0 -70
  223. package/src/index.ts +0 -31
  224. package/src/monaco-slim.ts +0 -20
  225. package/src/preferences/versioning.ts +0 -69
@@ -0,0 +1,1133 @@
1
+ import {
2
+ useMenuKeyboard
3
+ } from "./chunk-57ZJJOC5.js";
4
+ import {
5
+ BADGE_GLYPHS,
6
+ BADGE_LABELS,
7
+ badgeKindFor,
8
+ formatAheadBehind,
9
+ summarizeDirty,
10
+ useGitContext
11
+ } from "./chunk-5A4KEWKT.js";
12
+ import {
13
+ Dialog
14
+ } from "./chunk-FMGTHSTX.js";
15
+
16
+ // src/Git/GitStatusBar.tsx
17
+ import { useCallback, useEffect, useRef, useState } from "react";
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ function GitStatusBar() {
20
+ const git = useGitContext();
21
+ const [menuOpen, setMenuOpen] = useState(false);
22
+ const rootRef = useRef(null);
23
+ const { menuRef, triggerRef, handleMenuKeyDown, handleTriggerKeyDown, closeMenu } = useMenuKeyboard(menuOpen, setMenuOpen);
24
+ useEffect(() => {
25
+ if (!menuOpen) return;
26
+ const onPointerDown = (e) => {
27
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
28
+ setMenuOpen(false);
29
+ }
30
+ };
31
+ document.addEventListener("pointerdown", onPointerDown);
32
+ return () => document.removeEventListener("pointerdown", onPointerDown);
33
+ }, [menuOpen]);
34
+ const runItem = useCallback(
35
+ (action) => {
36
+ closeMenu(false);
37
+ action();
38
+ },
39
+ [closeMenu]
40
+ );
41
+ if (!git || !git.repo || !git.status) return null;
42
+ const { status } = git;
43
+ const branchLabel = status.detached ? "detached HEAD" : status.branch ?? "no branch";
44
+ const aheadBehind = formatAheadBehind(status);
45
+ const dirty = summarizeDirty(status);
46
+ const merging = status.operation === "merge";
47
+ const chipLabelParts = [`Git: branch ${branchLabel}`];
48
+ if (status.ahead > 0) chipLabelParts.push(`${status.ahead} ahead`);
49
+ if (status.behind > 0) chipLabelParts.push(`${status.behind} behind`);
50
+ if (dirty) chipLabelParts.push(dirty);
51
+ if (merging) chipLabelParts.push("merge in progress");
52
+ const canCreatePr = git.capabilities?.ghAvailable === true && git.remoteWeb?.host === "github.com";
53
+ return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: "db-git-statusbar", children: [
54
+ /* @__PURE__ */ jsxs(
55
+ "button",
56
+ {
57
+ ref: triggerRef,
58
+ type: "button",
59
+ className: "db-git-statusbar-chip",
60
+ onClick: () => setMenuOpen((open) => !open),
61
+ onKeyDown: handleTriggerKeyDown,
62
+ "aria-haspopup": "menu",
63
+ "aria-expanded": menuOpen,
64
+ "aria-label": chipLabelParts.join(", "),
65
+ title: chipLabelParts.join(", "),
66
+ children: [
67
+ /* @__PURE__ */ jsx("span", { className: "db-git-branch-glyph", "aria-hidden": "true", children: "\u2387" }),
68
+ /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-branch", children: branchLabel }),
69
+ aheadBehind && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-counts", children: aheadBehind }),
70
+ dirty && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-dirty", children: dirty }),
71
+ merging && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-merge", children: "merging" }),
72
+ git.busy && /* @__PURE__ */ jsx("span", { className: "db-git-statusbar-busy", "aria-hidden": "true", children: "\u2026" })
73
+ ]
74
+ }
75
+ ),
76
+ menuOpen && /* @__PURE__ */ jsxs(
77
+ "div",
78
+ {
79
+ ref: menuRef,
80
+ className: "db-git-menu",
81
+ role: "menu",
82
+ "aria-label": "Git actions",
83
+ onKeyDown: handleMenuKeyDown,
84
+ children: [
85
+ /* @__PURE__ */ jsx(
86
+ "button",
87
+ {
88
+ type: "button",
89
+ role: "menuitem",
90
+ tabIndex: -1,
91
+ className: "db-git-menu-item",
92
+ disabled: status.changes.length === 0 && !merging,
93
+ onClick: () => runItem(() => git.openDialog({ kind: "commit" })),
94
+ children: merging ? "Commit merge\u2026" : "Commit\u2026"
95
+ }
96
+ ),
97
+ /* @__PURE__ */ jsx(
98
+ "button",
99
+ {
100
+ type: "button",
101
+ role: "menuitem",
102
+ tabIndex: -1,
103
+ className: "db-git-menu-item",
104
+ disabled: git.busy !== null,
105
+ onClick: () => runItem(() => void git.push()),
106
+ children: status.upstream === null && !status.unborn ? "Publish branch" : "Push"
107
+ }
108
+ ),
109
+ /* @__PURE__ */ jsx(
110
+ "button",
111
+ {
112
+ type: "button",
113
+ role: "menuitem",
114
+ tabIndex: -1,
115
+ className: "db-git-menu-item",
116
+ disabled: git.busy !== null,
117
+ onClick: () => runItem(() => void git.pull()),
118
+ children: "Pull"
119
+ }
120
+ ),
121
+ /* @__PURE__ */ jsx(
122
+ "button",
123
+ {
124
+ type: "button",
125
+ role: "menuitem",
126
+ tabIndex: -1,
127
+ className: "db-git-menu-item",
128
+ disabled: git.busy !== null,
129
+ onClick: () => runItem(() => void git.fetchRemote()),
130
+ children: "Fetch"
131
+ }
132
+ ),
133
+ /* @__PURE__ */ jsx("div", { className: "db-git-menu-divider", role: "separator" }),
134
+ /* @__PURE__ */ jsx(
135
+ "button",
136
+ {
137
+ type: "button",
138
+ role: "menuitem",
139
+ tabIndex: -1,
140
+ className: "db-git-menu-item",
141
+ onClick: () => runItem(() => git.openDialog({ kind: "branches" })),
142
+ children: "Branches\u2026"
143
+ }
144
+ ),
145
+ /* @__PURE__ */ jsx(
146
+ "button",
147
+ {
148
+ type: "button",
149
+ role: "menuitem",
150
+ tabIndex: -1,
151
+ className: "db-git-menu-item",
152
+ onClick: () => runItem(() => git.openDialog({ kind: "history" })),
153
+ children: "Commit history\u2026"
154
+ }
155
+ ),
156
+ (git.remoteWeb || canCreatePr) && /* @__PURE__ */ jsx("div", { className: "db-git-menu-divider", role: "separator" }),
157
+ git.remoteWeb && /* @__PURE__ */ jsxs(
158
+ "button",
159
+ {
160
+ type: "button",
161
+ role: "menuitem",
162
+ tabIndex: -1,
163
+ className: "db-git-menu-item",
164
+ onClick: () => runItem(() => git.openOnRemote()),
165
+ children: [
166
+ "Open on ",
167
+ git.remoteWeb.host
168
+ ]
169
+ }
170
+ ),
171
+ canCreatePr && /* @__PURE__ */ jsx(
172
+ "button",
173
+ {
174
+ type: "button",
175
+ role: "menuitem",
176
+ tabIndex: -1,
177
+ className: "db-git-menu-item",
178
+ disabled: git.busy !== null,
179
+ onClick: () => runItem(() => void git.createPullRequest()),
180
+ children: "Create pull request"
181
+ }
182
+ )
183
+ ]
184
+ }
185
+ )
186
+ ] });
187
+ }
188
+
189
+ // src/Git/GitCommitDialog.tsx
190
+ import { useMemo, useRef as useRef2, useState as useState2 } from "react";
191
+
192
+ // src/Git/commit-selection.ts
193
+ var INCLUDED_BY_DEFAULT = true;
194
+ function normalise(path) {
195
+ return path.startsWith("/") ? path : `/${path}`;
196
+ }
197
+ var NO_OVERRIDES = /* @__PURE__ */ new Map();
198
+ function resolveSelection(changes, wholeIndex, overrides = NO_OVERRIDES) {
199
+ const included = /* @__PURE__ */ new Map();
200
+ const locked = /* @__PURE__ */ new Set();
201
+ for (const change of changes) {
202
+ const path = normalise(change.path);
203
+ if (wholeIndex) locked.add(path);
204
+ included.set(path, wholeIndex ? true : overrides.get(path) ?? INCLUDED_BY_DEFAULT);
205
+ }
206
+ return { included, locked };
207
+ }
208
+ function isIncluded(selection, path) {
209
+ return selection.included.get(normalise(path)) ?? INCLUDED_BY_DEFAULT;
210
+ }
211
+ function isLocked(selection, path) {
212
+ return selection.locked.has(normalise(path));
213
+ }
214
+ function toggleOverride(overrides, selection, path) {
215
+ const key = normalise(path);
216
+ if (isLocked(selection, key)) return overrides;
217
+ const next = new Map(overrides);
218
+ next.set(key, !isIncluded(selection, key));
219
+ return next;
220
+ }
221
+ function setAllOverrides(selection, value) {
222
+ const next = /* @__PURE__ */ new Map();
223
+ for (const key of selection.included.keys()) {
224
+ if (!selection.locked.has(key)) next.set(key, value);
225
+ }
226
+ return next;
227
+ }
228
+ function allSelected(selection) {
229
+ return [...selection.included.values()].every(Boolean);
230
+ }
231
+ function selectedPaths(selection) {
232
+ return [...selection.included.entries()].filter(([, on]) => on).map(([path]) => path);
233
+ }
234
+ function canCommit(message, selection) {
235
+ return message.trim().length > 0 && selectedPaths(selection).length > 0;
236
+ }
237
+ function isMergeCommit(status) {
238
+ return status?.operation === "merge";
239
+ }
240
+ function commitsWholeIndex(status) {
241
+ return status !== null && status.operation !== null;
242
+ }
243
+
244
+ // src/Git/GitCommitDialog.tsx
245
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
246
+ var OPERATION_LABELS = {
247
+ merge: "merge",
248
+ rebase: "rebase",
249
+ "cherry-pick": "cherry-pick",
250
+ revert: "revert",
251
+ bisect: "bisect"
252
+ };
253
+ function GitCommitDialog({ onClose }) {
254
+ const git = useGitContext();
255
+ const status = git?.status ?? null;
256
+ const merging = isMergeCommit(status);
257
+ const wholeIndex = commitsWholeIndex(status);
258
+ const changes = status?.changes;
259
+ const [message, setMessage] = useState2("");
260
+ const [overrides, setOverrides] = useState2(NO_OVERRIDES);
261
+ const messageRef = useRef2(null);
262
+ const selection = useMemo(
263
+ () => resolveSelection(changes ?? [], wholeIndex, overrides),
264
+ [changes, wholeIndex, overrides]
265
+ );
266
+ if (!git || !status) return null;
267
+ const allOn = allSelected(selection);
268
+ const commitDisabled = !canCommit(message, selection) || git.busy !== null;
269
+ const handleCommit = async () => {
270
+ const ok = await git.commit(message, selectedPaths(selection));
271
+ if (ok) onClose();
272
+ };
273
+ return /* @__PURE__ */ jsxs2(
274
+ Dialog,
275
+ {
276
+ title: merging ? "Commit merge" : "Commit changes",
277
+ onClose,
278
+ size: "wide",
279
+ closeOnBackdrop: false,
280
+ initialFocusRef: messageRef,
281
+ footer: /* @__PURE__ */ jsxs2(Fragment, { children: [
282
+ /* @__PURE__ */ jsx2("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Cancel" }),
283
+ /* @__PURE__ */ jsx2(
284
+ "button",
285
+ {
286
+ type: "button",
287
+ className: "db-git-primary-btn",
288
+ disabled: commitDisabled,
289
+ onClick: () => void handleCommit(),
290
+ children: "Commit"
291
+ }
292
+ )
293
+ ] }),
294
+ children: [
295
+ wholeIndex && /* @__PURE__ */ jsxs2("p", { className: "db-settings-hint", children: [
296
+ merging ? "You\u2019re completing a merge. Committing will conclude it." : `A ${OPERATION_LABELS[status.operation ?? ""] ?? "git operation"} is in progress.`,
297
+ " ",
298
+ "Git records every change below in this commit \u2014 files cannot be left out until the",
299
+ " ",
300
+ merging ? "merge" : "operation",
301
+ " is finished."
302
+ ] }),
303
+ /* @__PURE__ */ jsx2(
304
+ "textarea",
305
+ {
306
+ ref: messageRef,
307
+ className: "db-git-commit-message",
308
+ value: message,
309
+ onChange: (e) => setMessage(e.target.value),
310
+ placeholder: "Commit message",
311
+ "aria-label": "Commit message",
312
+ rows: 3
313
+ }
314
+ ),
315
+ !wholeIndex && /* @__PURE__ */ jsx2("div", { className: "db-git-form-row", children: /* @__PURE__ */ jsx2(
316
+ "button",
317
+ {
318
+ type: "button",
319
+ className: "db-git-secondary-btn",
320
+ onClick: () => setOverrides(setAllOverrides(selection, !allOn)),
321
+ children: allOn ? "Select none" : "Select all"
322
+ }
323
+ ) }),
324
+ /* @__PURE__ */ jsx2("ul", { className: "db-git-file-list", children: status.changes.map((change) => {
325
+ const kind = badgeKindFor(change);
326
+ const locked = isLocked(selection, change.path);
327
+ const checked = isIncluded(selection, change.path);
328
+ return /* @__PURE__ */ jsxs2("li", { className: "db-git-file-row", children: [
329
+ /* @__PURE__ */ jsxs2("label", { children: [
330
+ /* @__PURE__ */ jsx2(
331
+ "input",
332
+ {
333
+ type: "checkbox",
334
+ checked,
335
+ disabled: locked,
336
+ title: locked ? `Included automatically while the ${merging ? "merge" : "operation"} is in progress` : void 0,
337
+ onChange: () => setOverrides((o) => toggleOverride(o, selection, change.path))
338
+ }
339
+ ),
340
+ /* @__PURE__ */ jsx2("span", { children: change.path.replace(/^\/+/, "") })
341
+ ] }),
342
+ /* @__PURE__ */ jsx2("span", { className: "db-git-file-kind", children: BADGE_LABELS[kind] })
343
+ ] }, change.path);
344
+ }) }),
345
+ git.lastResult?.tone === "error" && /* @__PURE__ */ jsx2("p", { className: "db-git-form-error", role: "alert", children: git.lastResult.message })
346
+ ]
347
+ }
348
+ );
349
+ }
350
+
351
+ // src/Git/GitBranchesDialog.tsx
352
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
353
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
354
+ function GitBranchesDialog({
355
+ createFocus,
356
+ onClose
357
+ }) {
358
+ const git = useGitContext();
359
+ const gitApi = git?.gitApi ?? null;
360
+ const repositoryId = git?.repositoryId ?? null;
361
+ const [branches, setBranches] = useState3(null);
362
+ const [loadError, setLoadError] = useState3(null);
363
+ const [newName, setNewName] = useState3("");
364
+ const createInputRef = useRef3(null);
365
+ useEffect2(() => {
366
+ if (!gitApi || !repositoryId) return;
367
+ let cancelled = false;
368
+ void gitApi.listBranches(repositoryId).then(
369
+ (result) => {
370
+ if (cancelled) return;
371
+ if (result.ok) setBranches(result.value);
372
+ else setLoadError(result.error.message || "Could not list branches");
373
+ },
374
+ // A rejected call (the host went away) left the dialog on
375
+ // "Loading branches…" forever. Fail visibly instead.
376
+ (error) => {
377
+ if (cancelled) return;
378
+ setLoadError(error instanceof Error ? error.message : "Could not list branches");
379
+ }
380
+ );
381
+ return () => {
382
+ cancelled = true;
383
+ };
384
+ }, [gitApi, repositoryId]);
385
+ if (!git) return null;
386
+ const locals = branches?.filter((b) => b.kind === "local") ?? [];
387
+ const remotes = branches?.filter((b) => b.kind === "remote") ?? [];
388
+ const canCreate = newName.trim().length > 0 && git.busy === null;
389
+ const handleSwitch = async (name) => {
390
+ const ok = await git.switchBranch(name);
391
+ if (ok) onClose();
392
+ };
393
+ const handleCreate = async () => {
394
+ if (!canCreate) return;
395
+ const ok = await git.createBranch(newName.trim());
396
+ if (ok) onClose();
397
+ };
398
+ return /* @__PURE__ */ jsxs3(
399
+ Dialog,
400
+ {
401
+ title: "Branches",
402
+ onClose,
403
+ initialFocusRef: createFocus ? createInputRef : void 0,
404
+ children: [
405
+ branches === null && loadError === null && /* @__PURE__ */ jsx3("p", { className: "db-git-hint", children: "Loading branches\u2026" }),
406
+ loadError !== null && /* @__PURE__ */ jsx3("p", { className: "db-git-form-error", role: "alert", children: loadError }),
407
+ branches !== null && /* @__PURE__ */ jsx3("div", { className: "db-git-branch-list", children: locals.map(
408
+ (branch) => branch.current ? /* @__PURE__ */ jsx3(
409
+ "span",
410
+ {
411
+ className: "db-git-branch-row db-git-branch-row--current",
412
+ "aria-current": "true",
413
+ children: branch.name
414
+ },
415
+ branch.name
416
+ ) : /* @__PURE__ */ jsx3(
417
+ "button",
418
+ {
419
+ type: "button",
420
+ className: "db-git-branch-row",
421
+ disabled: git.busy !== null,
422
+ onClick: () => void handleSwitch(branch.name),
423
+ children: branch.name
424
+ },
425
+ branch.name
426
+ )
427
+ ) }),
428
+ git.lastResult?.tone === "error" && /* @__PURE__ */ jsx3("p", { className: "db-git-form-error", role: "alert", children: git.lastResult.message }),
429
+ /* @__PURE__ */ jsx3("hr", {}),
430
+ /* @__PURE__ */ jsxs3("div", { className: "db-git-form-row", children: [
431
+ /* @__PURE__ */ jsx3("label", { className: "db-git-form-label", htmlFor: "db-git-new-branch-name", children: "New branch" }),
432
+ /* @__PURE__ */ jsx3(
433
+ "input",
434
+ {
435
+ id: "db-git-new-branch-name",
436
+ ref: createInputRef,
437
+ className: "db-git-form-input",
438
+ type: "text",
439
+ value: newName,
440
+ onChange: (e) => setNewName(e.target.value),
441
+ onKeyDown: (e) => {
442
+ if (e.key === "Enter") void handleCreate();
443
+ },
444
+ placeholder: "feature/my-branch",
445
+ spellCheck: false
446
+ }
447
+ ),
448
+ /* @__PURE__ */ jsx3(
449
+ "button",
450
+ {
451
+ type: "button",
452
+ className: "db-git-primary-btn",
453
+ disabled: !canCreate,
454
+ onClick: () => void handleCreate(),
455
+ children: "Create"
456
+ }
457
+ )
458
+ ] }),
459
+ remotes.length > 0 && /* @__PURE__ */ jsxs3("details", { children: [
460
+ /* @__PURE__ */ jsxs3("summary", { children: [
461
+ "Remote branches (",
462
+ remotes.length,
463
+ ")"
464
+ ] }),
465
+ /* @__PURE__ */ jsx3("div", { className: "db-git-branch-list", children: remotes.map((branch) => /* @__PURE__ */ jsx3("span", { className: "db-git-branch-row", children: branch.name }, branch.name)) })
466
+ ] })
467
+ ]
468
+ }
469
+ );
470
+ }
471
+
472
+ // src/Git/GitHistoryDialog.tsx
473
+ import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef4, useState as useState4 } from "react";
474
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
475
+ var PAGE_SIZE = 50;
476
+ function extraBody(body, subject) {
477
+ const trimmedBody = body.trim();
478
+ const trimmedSubject = subject.trim();
479
+ if (!trimmedBody || trimmedBody === trimmedSubject) return "";
480
+ if (trimmedBody.startsWith(trimmedSubject)) {
481
+ return trimmedBody.slice(trimmedSubject.length).trim();
482
+ }
483
+ return trimmedBody;
484
+ }
485
+ function formatDate(iso) {
486
+ const date = new Date(iso);
487
+ return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
488
+ }
489
+ function GitHistoryDialog({ path, onClose }) {
490
+ const git = useGitContext();
491
+ const gitApi = git?.gitApi ?? null;
492
+ const repositoryId = git?.repositoryId ?? null;
493
+ const [entries, setEntries] = useState4([]);
494
+ const [loading, setLoading] = useState4(false);
495
+ const [error, setError] = useState4(null);
496
+ const [hasMore, setHasMore] = useState4(false);
497
+ const [expandedSha, setExpandedSha] = useState4(null);
498
+ const [details, setDetails] = useState4(/* @__PURE__ */ new Map());
499
+ const generationRef = useRef4(0);
500
+ const loadPage = useCallback2(
501
+ async (skip) => {
502
+ if (!gitApi || !repositoryId) return;
503
+ const generation = generationRef.current;
504
+ const stale = () => generation !== generationRef.current;
505
+ setLoading(true);
506
+ setError(null);
507
+ try {
508
+ const result = await gitApi.log(repositoryId, { path, maxCount: PAGE_SIZE, skip });
509
+ if (stale()) return;
510
+ if (!result.ok) {
511
+ setError(result.error.message);
512
+ return;
513
+ }
514
+ setEntries((prev) => skip === 0 ? result.value : [...prev, ...result.value]);
515
+ setHasMore(result.value.length === PAGE_SIZE);
516
+ } catch (caught) {
517
+ if (stale()) return;
518
+ setError(caught instanceof Error ? caught.message : "Could not load history");
519
+ } finally {
520
+ if (!stale()) setLoading(false);
521
+ }
522
+ },
523
+ [gitApi, repositoryId, path]
524
+ );
525
+ useEffect3(() => {
526
+ generationRef.current += 1;
527
+ setEntries([]);
528
+ setExpandedSha(null);
529
+ setDetails(/* @__PURE__ */ new Map());
530
+ setHasMore(false);
531
+ setLoading(false);
532
+ void loadPage(0);
533
+ }, [loadPage]);
534
+ const handleRowClick = (sha) => {
535
+ if (expandedSha === sha) {
536
+ setExpandedSha(null);
537
+ return;
538
+ }
539
+ setExpandedSha(sha);
540
+ if (!gitApi || !repositoryId || details.has(sha)) return;
541
+ const generation = generationRef.current;
542
+ const record = (detail) => {
543
+ if (generation !== generationRef.current) return;
544
+ setDetails((prev) => {
545
+ const next = new Map(prev);
546
+ next.set(sha, detail);
547
+ return next;
548
+ });
549
+ };
550
+ void gitApi.commitFiles(repositoryId, sha).then(
551
+ (result) => record(result.ok ? result.value : { error: result.error.message }),
552
+ (error2) => record({
553
+ error: error2 instanceof Error ? error2.message : "Could not load this commit"
554
+ })
555
+ );
556
+ };
557
+ if (!git) return null;
558
+ const baseName = path ? path.replace(/^\/+/, "").split("/").pop() : null;
559
+ const title = baseName ? `History \u2014 ${baseName}` : "Commit history";
560
+ return /* @__PURE__ */ jsxs4(Dialog, { title, size: "wide", onClose, children: [
561
+ error && /* @__PURE__ */ jsx4("p", { className: "db-git-form-error", role: "alert", children: error }),
562
+ !error && entries.length === 0 && loading && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "Loading history\u2026" }),
563
+ !error && entries.length === 0 && !loading && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "No commits yet." }),
564
+ entries.length > 0 && /* @__PURE__ */ jsx4("ul", { className: "db-git-history-list", children: entries.map((entry) => {
565
+ const expanded = expandedSha === entry.sha;
566
+ const detail = details.get(entry.sha);
567
+ const meta = [
568
+ entry.authorName,
569
+ entry.sha.slice(0, 7),
570
+ formatDate(entry.authorDate),
571
+ entry.refs.join(", ")
572
+ ].filter(Boolean).join(" \xB7 ");
573
+ const body = detail && !("error" in detail) ? extraBody(detail.body, entry.subject) : "";
574
+ return /* @__PURE__ */ jsxs4("li", { className: "db-git-history-item", children: [
575
+ /* @__PURE__ */ jsxs4(
576
+ "button",
577
+ {
578
+ type: "button",
579
+ className: "db-git-history-toggle",
580
+ "aria-expanded": expanded,
581
+ onClick: () => handleRowClick(entry.sha),
582
+ children: [
583
+ /* @__PURE__ */ jsx4("span", { className: "db-git-history-subject", children: entry.subject }),
584
+ /* @__PURE__ */ jsx4("span", { className: "db-git-history-meta", children: meta })
585
+ ]
586
+ }
587
+ ),
588
+ expanded && !detail && /* @__PURE__ */ jsx4("p", { className: "db-git-hint", children: "Loading\u2026" }),
589
+ expanded && detail && "error" in detail && /* @__PURE__ */ jsx4("p", { className: "db-git-form-error", role: "alert", children: detail.error }),
590
+ expanded && detail && !("error" in detail) && /* @__PURE__ */ jsxs4(Fragment2, { children: [
591
+ body && /* @__PURE__ */ jsx4("pre", { className: "db-git-history-body", children: body }),
592
+ /* @__PURE__ */ jsx4("ul", { className: "db-git-history-files", children: detail.files.map((file) => {
593
+ const kind = badgeKindFor(file);
594
+ return /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4(
595
+ "button",
596
+ {
597
+ type: "button",
598
+ className: "db-git-history-file",
599
+ onClick: () => git.openDialog({
600
+ kind: "diff",
601
+ path: file.path,
602
+ revision: { sha: entry.sha }
603
+ }),
604
+ children: [
605
+ /* @__PURE__ */ jsx4(
606
+ "span",
607
+ {
608
+ className: "db-git-file-kind",
609
+ "aria-label": BADGE_LABELS[kind],
610
+ title: BADGE_LABELS[kind],
611
+ children: BADGE_GLYPHS[kind]
612
+ }
613
+ ),
614
+ file.path.replace(/^\/+/, "")
615
+ ]
616
+ }
617
+ ) }, file.path);
618
+ }) })
619
+ ] })
620
+ ] }, entry.sha);
621
+ }) }),
622
+ hasMore && /* @__PURE__ */ jsx4(
623
+ "button",
624
+ {
625
+ type: "button",
626
+ className: "db-git-secondary-btn",
627
+ disabled: loading,
628
+ onClick: () => void loadPage(entries.length),
629
+ children: "Show older commits"
630
+ }
631
+ )
632
+ ] });
633
+ }
634
+
635
+ // src/Git/GitDiffDialog.tsx
636
+ import { useEffect as useEffect5, useState as useState5 } from "react";
637
+ import { getFileSystemProviderV2, parseWorkspacePath } from "@bendyline/docblocks/filesystem";
638
+
639
+ // src/Git/GitDiffView.tsx
640
+ import { useEffect as useEffect4, useRef as useRef5 } from "react";
641
+ import {
642
+ detectLanguageFromFileName,
643
+ useMonacoLoader
644
+ } from "@bendyline/squisq-editor-react";
645
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
646
+ function languageFor(fileName) {
647
+ const detected = detectLanguageFromFileName(fileName);
648
+ if (detected) return detected;
649
+ return fileName.toLowerCase().endsWith(".md") ? "markdown" : "plaintext";
650
+ }
651
+ function GitDiffView({ original, modified, fileName, theme, labels }) {
652
+ const { monaco, ready } = useMonacoLoader();
653
+ const hostRef = useRef5(null);
654
+ const editorRef = useRef5(null);
655
+ const modelsRef = useRef5(null);
656
+ const language = languageFor(fileName);
657
+ useEffect4(() => {
658
+ const host = hostRef.current;
659
+ if (!monaco || !host) return;
660
+ const originalModel = monaco.editor.createModel("", "plaintext");
661
+ const modifiedModel = monaco.editor.createModel("", "plaintext");
662
+ const editor = monaco.editor.createDiffEditor(host, {
663
+ readOnly: true,
664
+ renderSideBySide: true,
665
+ automaticLayout: true,
666
+ minimap: { enabled: false },
667
+ wordWrap: "on",
668
+ scrollBeyondLastLine: false,
669
+ renderOverviewRuler: false
670
+ });
671
+ editor.setModel({ original: originalModel, modified: modifiedModel });
672
+ editorRef.current = editor;
673
+ modelsRef.current = { original: originalModel, modified: modifiedModel };
674
+ return () => {
675
+ editorRef.current = null;
676
+ modelsRef.current = null;
677
+ editor.dispose();
678
+ originalModel.dispose();
679
+ modifiedModel.dispose();
680
+ };
681
+ }, [monaco]);
682
+ useEffect4(() => {
683
+ if (!monaco) return;
684
+ const models = modelsRef.current;
685
+ if (!models) return;
686
+ if (models.original.getValue() !== original) models.original.setValue(original);
687
+ if (models.modified.getValue() !== modified) models.modified.setValue(modified);
688
+ monaco.editor.setModelLanguage(models.original, language);
689
+ monaco.editor.setModelLanguage(models.modified, language);
690
+ }, [monaco, original, modified, language]);
691
+ useEffect4(() => {
692
+ if (!monaco) return;
693
+ monaco.editor.setTheme(theme === "dark" ? "vs-dark" : "vs");
694
+ }, [monaco, theme]);
695
+ if (!ready) {
696
+ return /* @__PURE__ */ jsx5("div", { className: "db-git-diff-loading", children: "Loading diff\u2026" });
697
+ }
698
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
699
+ labels && /* @__PURE__ */ jsxs5("div", { className: "db-git-diff-labels", children: [
700
+ /* @__PURE__ */ jsx5("span", { children: labels.original }),
701
+ /* @__PURE__ */ jsx5("span", { children: labels.modified })
702
+ ] }),
703
+ /* @__PURE__ */ jsx5("div", { ref: hostRef, className: "db-git-diff-host" })
704
+ ] });
705
+ }
706
+
707
+ // src/Git/GitDiffDialog.tsx
708
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
709
+ function GitDiffDialog({ path, revision, onClose }) {
710
+ const git = useGitContext();
711
+ const gitApi = git?.gitApi ?? null;
712
+ const provider = git?.provider ?? null;
713
+ const repositoryId = git?.repositoryId ?? null;
714
+ const sha = revision?.sha ?? null;
715
+ const [state, setState] = useState5({ phase: "loading" });
716
+ useEffect5(() => {
717
+ if (!gitApi || !repositoryId) {
718
+ setState({ phase: "error", message: "Git is not available for this workspace." });
719
+ return;
720
+ }
721
+ let cancelled = false;
722
+ setState({ phase: "loading" });
723
+ const load = async () => {
724
+ if (sha) {
725
+ const short = sha.slice(0, 7);
726
+ const [parent, at] = await Promise.all([
727
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "parent-of", sha }),
728
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "commit", sha })
729
+ ]);
730
+ if (!parent.ok) return { phase: "error", message: parent.error.message };
731
+ if (!at.ok) return { phase: "error", message: at.error.message };
732
+ if (parent.value.content === null && parent.value.binary || at.value.content === null && at.value.binary) {
733
+ return { phase: "binary" };
734
+ }
735
+ return {
736
+ phase: "ready",
737
+ original: parent.value.content ?? "",
738
+ modified: at.value.content ?? "",
739
+ labels: {
740
+ original: parent.value.content === null ? `${short}^ (absent)` : `${short}^`,
741
+ modified: at.value.content === null ? `${short} (absent)` : short
742
+ }
743
+ };
744
+ }
745
+ if (!provider) {
746
+ return { phase: "error", message: "Workspace files are not available." };
747
+ }
748
+ const providerV2 = getFileSystemProviderV2(provider);
749
+ const [head, working] = await Promise.all([
750
+ gitApi.readFileAtRevision(repositoryId, path, { kind: "head" }),
751
+ providerV2 ? providerV2.readFile(parseWorkspacePath(path)).then((file) => file ? new TextDecoder().decode(file.data) : null) : provider.readFile(path)
752
+ ]);
753
+ if (!head.ok) return { phase: "error", message: head.error.message };
754
+ if (head.value.content === null && head.value.binary) return { phase: "binary" };
755
+ return {
756
+ phase: "ready",
757
+ original: head.value.content ?? "",
758
+ modified: working ?? "",
759
+ labels: {
760
+ original: head.value.content === null ? "HEAD (absent)" : "HEAD",
761
+ modified: working === null ? "Working tree (absent)" : "Working tree"
762
+ }
763
+ };
764
+ };
765
+ load().catch(
766
+ (err) => ({
767
+ phase: "error",
768
+ message: err instanceof Error ? err.message : "Failed to load the diff"
769
+ })
770
+ ).then((next) => {
771
+ if (!cancelled) setState(next);
772
+ });
773
+ return () => {
774
+ cancelled = true;
775
+ };
776
+ }, [gitApi, provider, repositoryId, path, sha]);
777
+ if (!git) return null;
778
+ const fullPath = path.replace(/^\/+/, "");
779
+ const baseName = fullPath.split("/").pop() || fullPath;
780
+ return /* @__PURE__ */ jsxs6(Dialog, { title: baseName, size: "full", onClose, children: [
781
+ /* @__PURE__ */ jsx6("p", { className: "db-settings-hint", children: fullPath }),
782
+ state.phase === "loading" && /* @__PURE__ */ jsx6("p", { className: "db-git-hint", children: "Loading changes\u2026" }),
783
+ state.phase === "error" && /* @__PURE__ */ jsx6("p", { className: "db-git-form-error", role: "alert", children: state.message }),
784
+ state.phase === "binary" && /* @__PURE__ */ jsx6("p", { className: "db-git-hint", children: "Binary file \u2014 no text diff available." }),
785
+ state.phase === "ready" && /* @__PURE__ */ jsx6(
786
+ GitDiffView,
787
+ {
788
+ original: state.original,
789
+ modified: state.modified,
790
+ fileName: baseName,
791
+ theme: git.theme,
792
+ labels: state.labels
793
+ }
794
+ )
795
+ ] });
796
+ }
797
+
798
+ // src/Git/GitCloneDialog.tsx
799
+ import { useEffect as useEffect6, useRef as useRef6, useState as useState6 } from "react";
800
+
801
+ // src/Git/git-clone-utils.ts
802
+ function deriveCloneFolderName(url) {
803
+ const trimmed = url.trim().replace(/\/+$/, "");
804
+ const lastSegment = trimmed.split(/[/:\\]/).pop() ?? "";
805
+ const withoutGit = lastSegment.replace(/\.git$/i, "");
806
+ const sanitized = withoutGit.replace(/[^A-Za-z0-9._-]/g, "-");
807
+ return sanitized.length > 0 ? sanitized : "repository";
808
+ }
809
+ function isLikelyGitUrl(url) {
810
+ const trimmed = url.trim();
811
+ if (trimmed.length === 0 || /\s/.test(trimmed)) return false;
812
+ if (trimmed.startsWith("-") || trimmed.toLowerCase().startsWith("file:")) return false;
813
+ if (/^(https?|ssh|git):\/\/\S+\/\S+/i.test(trimmed)) return true;
814
+ if (/^[\w.-]+@[\w.-]+:\S+/.test(trimmed)) return true;
815
+ return false;
816
+ }
817
+
818
+ // src/Git/GitAuthGuidanceDialog.tsx
819
+ import { maybeGetDocBlocksHost } from "@bendyline/docblocks/host";
820
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
821
+ var LEARN_MORE_URL = "https://docs.github.com/en/get-started/getting-started-with-git/caching-your-github-credentials-in-git";
822
+ var OPERATION_LABELS2 = {
823
+ push: "push",
824
+ pull: "pull",
825
+ fetch: "fetch",
826
+ clone: "clone",
827
+ pr: "create the pull request"
828
+ };
829
+ function GitCredentialGuidance({ detail }) {
830
+ return /* @__PURE__ */ jsxs7(Fragment4, { children: [
831
+ /* @__PURE__ */ jsx7("p", { className: "db-settings-hint", children: "DocBlocks never stores Git credentials. Sign in with one of these, then try again:" }),
832
+ /* @__PURE__ */ jsxs7("ul", { className: "db-git-hint", children: [
833
+ /* @__PURE__ */ jsxs7("li", { children: [
834
+ "A git credential helper (",
835
+ /* @__PURE__ */ jsx7("code", { children: "git config credential.helper" }),
836
+ ")"
837
+ ] }),
838
+ /* @__PURE__ */ jsxs7("li", { children: [
839
+ "The GitHub CLI (",
840
+ /* @__PURE__ */ jsx7("code", { children: "gh auth login" }),
841
+ ")"
842
+ ] }),
843
+ /* @__PURE__ */ jsx7("li", { children: "An SSH key registered with your remote" })
844
+ ] }),
845
+ detail && /* @__PURE__ */ jsxs7("details", { children: [
846
+ /* @__PURE__ */ jsx7("summary", { children: "Details" }),
847
+ /* @__PURE__ */ jsx7("p", { className: "db-git-hint", children: detail })
848
+ ] })
849
+ ] });
850
+ }
851
+ function GitAuthGuidanceDialog({
852
+ operation,
853
+ detail,
854
+ onClose
855
+ }) {
856
+ return /* @__PURE__ */ jsxs7(
857
+ Dialog,
858
+ {
859
+ title: "Git needs credentials",
860
+ onClose,
861
+ footer: /* @__PURE__ */ jsxs7(Fragment4, { children: [
862
+ /* @__PURE__ */ jsx7(
863
+ "button",
864
+ {
865
+ type: "button",
866
+ className: "db-git-secondary-btn",
867
+ onClick: () => void maybeGetDocBlocksHost()?.shell.openExternal(LEARN_MORE_URL),
868
+ children: "Learn more"
869
+ }
870
+ ),
871
+ /* @__PURE__ */ jsx7("button", { type: "button", className: "db-git-primary-btn", onClick: onClose, children: "Close" })
872
+ ] }),
873
+ children: [
874
+ /* @__PURE__ */ jsxs7("p", { className: "db-settings-hint", children: [
875
+ "Git could not authenticate with the remote while trying to ",
876
+ OPERATION_LABELS2[operation],
877
+ "."
878
+ ] }),
879
+ /* @__PURE__ */ jsx7(GitCredentialGuidance, { detail })
880
+ ]
881
+ }
882
+ );
883
+ }
884
+
885
+ // src/Git/GitCloneDialog.tsx
886
+ import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
887
+ function GitCloneDialog({
888
+ onClose,
889
+ onCloned
890
+ }) {
891
+ const git = useGitContext();
892
+ const gitApi = git?.gitApi ?? null;
893
+ const [url, setUrl] = useState6("");
894
+ const [cloning, setCloning] = useState6(false);
895
+ const [progress, setProgress] = useState6(null);
896
+ const [error, setError] = useState6(null);
897
+ const [authDetail, setAuthDetail] = useState6(null);
898
+ const handleRef = useRef6(null);
899
+ const urlInputRef = useRef6(null);
900
+ useEffect6(
901
+ () => () => {
902
+ handleRef.current?.cancel();
903
+ },
904
+ []
905
+ );
906
+ if (!gitApi || typeof gitApi.clone !== "function") return null;
907
+ const canClone = isLikelyGitUrl(url) && !cloning;
908
+ const handleClone = async () => {
909
+ if (!canClone) return;
910
+ setCloning(true);
911
+ setError(null);
912
+ setProgress(null);
913
+ const handle = gitApi.clone(url.trim(), (p) => setProgress(p));
914
+ handleRef.current = handle;
915
+ const result = await handle.result;
916
+ handleRef.current = null;
917
+ setCloning(false);
918
+ setProgress(null);
919
+ if (!result.ok) {
920
+ switch (result.error.code) {
921
+ case "invalid-url":
922
+ setError("That doesn\u2019t look like a valid repository URL.");
923
+ break;
924
+ case "destination-exists":
925
+ setError("A folder with that name already exists there. Pick a different location.");
926
+ break;
927
+ case "auth-failed":
928
+ setAuthDetail({ detail: result.error.message });
929
+ break;
930
+ case "cancelled":
931
+ break;
932
+ // user cancelled — just return to the form
933
+ default:
934
+ setError(result.error.message);
935
+ }
936
+ return;
937
+ }
938
+ if (result.value === null) return;
939
+ onCloned(result.value);
940
+ };
941
+ const progressPercent = progress?.percent ?? null;
942
+ const progressText = progress !== null ? `${progress.phase}\u2026${progressPercent !== null ? ` ${Math.round(progressPercent)}%` : ""}` : "Starting clone\u2026";
943
+ if (authDetail !== null) {
944
+ return /* @__PURE__ */ jsxs8(
945
+ Dialog,
946
+ {
947
+ title: "Clone repository",
948
+ onClose,
949
+ footer: /* @__PURE__ */ jsxs8(Fragment5, { children: [
950
+ /* @__PURE__ */ jsx8(
951
+ "button",
952
+ {
953
+ type: "button",
954
+ className: "db-git-secondary-btn",
955
+ onClick: () => setAuthDetail(null),
956
+ children: "Back"
957
+ }
958
+ ),
959
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "db-git-primary-btn", onClick: onClose, children: "Close" })
960
+ ] }),
961
+ children: [
962
+ /* @__PURE__ */ jsx8("p", { className: "db-settings-hint", children: "Git could not authenticate with that remote." }),
963
+ /* @__PURE__ */ jsx8(GitCredentialGuidance, { detail: authDetail.detail })
964
+ ]
965
+ }
966
+ );
967
+ }
968
+ return /* @__PURE__ */ jsxs8(
969
+ Dialog,
970
+ {
971
+ title: "Clone repository",
972
+ onClose,
973
+ closeOnBackdrop: !cloning,
974
+ initialFocusRef: urlInputRef,
975
+ footer: /* @__PURE__ */ jsxs8(Fragment5, { children: [
976
+ /* @__PURE__ */ jsx8(
977
+ "button",
978
+ {
979
+ type: "button",
980
+ className: "db-git-secondary-btn",
981
+ onClick: onClose,
982
+ disabled: cloning,
983
+ children: "Cancel"
984
+ }
985
+ ),
986
+ /* @__PURE__ */ jsx8(
987
+ "button",
988
+ {
989
+ type: "button",
990
+ className: "db-git-primary-btn",
991
+ disabled: !canClone,
992
+ onClick: () => void handleClone(),
993
+ children: "Clone"
994
+ }
995
+ )
996
+ ] }),
997
+ children: [
998
+ /* @__PURE__ */ jsxs8("div", { className: "db-git-form-row", children: [
999
+ /* @__PURE__ */ jsx8("label", { className: "db-git-form-label", htmlFor: "db-git-clone-url", children: "Repository URL" }),
1000
+ /* @__PURE__ */ jsx8(
1001
+ "input",
1002
+ {
1003
+ id: "db-git-clone-url",
1004
+ ref: urlInputRef,
1005
+ className: "db-git-form-input",
1006
+ type: "text",
1007
+ value: url,
1008
+ onChange: (e) => setUrl(e.target.value),
1009
+ onKeyDown: (e) => {
1010
+ if (e.key === "Enter") void handleClone();
1011
+ },
1012
+ placeholder: "https://github.com/owner/repo.git",
1013
+ disabled: cloning,
1014
+ spellCheck: false
1015
+ }
1016
+ )
1017
+ ] }),
1018
+ isLikelyGitUrl(url) && /* @__PURE__ */ jsxs8("p", { className: "db-git-hint", children: [
1019
+ "Will clone into: ",
1020
+ /* @__PURE__ */ jsx8("b", { children: deriveCloneFolderName(url) }),
1021
+ " \u2014 you\u2019ll pick where next"
1022
+ ] }),
1023
+ /* @__PURE__ */ jsx8("p", { className: "db-git-hint", children: "HTTPS and SSH URLs both work. You\u2019ll choose the destination folder in the next step." }),
1024
+ error !== null && /* @__PURE__ */ jsx8("p", { className: "db-git-form-error", role: "alert", children: error }),
1025
+ cloning && /* @__PURE__ */ jsxs8("div", { className: "db-git-progress", children: [
1026
+ progressPercent !== null && /* @__PURE__ */ jsx8(
1027
+ "div",
1028
+ {
1029
+ className: "db-git-progress-bar",
1030
+ role: "progressbar",
1031
+ "aria-valuemin": 0,
1032
+ "aria-valuemax": 100,
1033
+ "aria-valuenow": Math.round(progressPercent),
1034
+ style: { width: `${progressPercent}%` }
1035
+ }
1036
+ ),
1037
+ /* @__PURE__ */ jsx8("p", { className: "db-git-progress-text", children: progressText }),
1038
+ /* @__PURE__ */ jsx8(
1039
+ "button",
1040
+ {
1041
+ type: "button",
1042
+ className: "db-git-secondary-btn",
1043
+ onClick: () => handleRef.current?.cancel(),
1044
+ children: "Cancel"
1045
+ }
1046
+ )
1047
+ ] })
1048
+ ]
1049
+ }
1050
+ );
1051
+ }
1052
+
1053
+ // src/Git/GitConflictsDialog.tsx
1054
+ import { Fragment as Fragment6, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
1055
+ function GitConflictsDialog({
1056
+ paths,
1057
+ onOpenFile,
1058
+ onClose
1059
+ }) {
1060
+ const git = useGitContext();
1061
+ return /* @__PURE__ */ jsxs9(
1062
+ Dialog,
1063
+ {
1064
+ title: "Merge conflicts",
1065
+ onClose,
1066
+ footer: /* @__PURE__ */ jsxs9(Fragment6, { children: [
1067
+ /* @__PURE__ */ jsx9("button", { type: "button", className: "db-git-secondary-btn", onClick: onClose, children: "Close" }),
1068
+ /* @__PURE__ */ jsx9(
1069
+ "button",
1070
+ {
1071
+ type: "button",
1072
+ className: "db-git-primary-btn",
1073
+ onClick: () => git?.openDialog({ kind: "commit" }),
1074
+ children: "Open commit dialog"
1075
+ }
1076
+ )
1077
+ ] }),
1078
+ children: [
1079
+ /* @__PURE__ */ jsx9("p", { className: "db-settings-hint", children: "These files contain conflict markers. Edit each one to resolve the conflicts, then commit to complete the merge." }),
1080
+ /* @__PURE__ */ jsx9("ul", { className: "db-git-file-list", children: paths.map((path) => /* @__PURE__ */ jsx9("li", { className: "db-git-file-row", children: /* @__PURE__ */ jsx9(
1081
+ "button",
1082
+ {
1083
+ type: "button",
1084
+ onClick: () => {
1085
+ onOpenFile(path);
1086
+ onClose();
1087
+ },
1088
+ children: path.replace(/^\/+/, "")
1089
+ }
1090
+ ) }, path)) })
1091
+ ]
1092
+ }
1093
+ );
1094
+ }
1095
+
1096
+ // src/Git/GitUI.tsx
1097
+ import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1098
+ function GitUI({ onOpenFile, onWorkspaceCloned }) {
1099
+ const git = useGitContext();
1100
+ if (!git || !git.available) return null;
1101
+ const { dialog, closeDialog } = git;
1102
+ return /* @__PURE__ */ jsxs10(Fragment7, { children: [
1103
+ /* @__PURE__ */ jsx10(GitStatusBar, {}),
1104
+ git.repo && /* @__PURE__ */ jsx10("span", { className: "db-git-inline-status", role: "status", "aria-live": "polite", children: git.lastResult?.message ?? "" }),
1105
+ dialog.kind === "commit" && /* @__PURE__ */ jsx10(GitCommitDialog, { onClose: closeDialog }),
1106
+ dialog.kind === "branches" && /* @__PURE__ */ jsx10(GitBranchesDialog, { createFocus: dialog.createFocus, onClose: closeDialog }),
1107
+ dialog.kind === "history" && /* @__PURE__ */ jsx10(GitHistoryDialog, { path: dialog.path, onClose: closeDialog }),
1108
+ dialog.kind === "diff" && /* @__PURE__ */ jsx10(GitDiffDialog, { path: dialog.path, revision: dialog.revision, onClose: closeDialog }),
1109
+ dialog.kind === "clone" && /* @__PURE__ */ jsx10(
1110
+ GitCloneDialog,
1111
+ {
1112
+ onClose: closeDialog,
1113
+ onCloned: (info) => {
1114
+ closeDialog();
1115
+ onWorkspaceCloned?.(info);
1116
+ }
1117
+ }
1118
+ ),
1119
+ dialog.kind === "auth-guidance" && /* @__PURE__ */ jsx10(
1120
+ GitAuthGuidanceDialog,
1121
+ {
1122
+ operation: dialog.operation,
1123
+ detail: dialog.detail,
1124
+ onClose: closeDialog
1125
+ }
1126
+ ),
1127
+ dialog.kind === "conflicts" && /* @__PURE__ */ jsx10(GitConflictsDialog, { paths: dialog.paths, onOpenFile, onClose: closeDialog })
1128
+ ] });
1129
+ }
1130
+ export {
1131
+ GitUI
1132
+ };
1133
+ //# sourceMappingURL=GitUI-VHOBQY43.js.map