@xlxz/markdown-editor 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1806 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +1774 -0
- package/dist/plugins/attachment.d.ts +7 -0
- package/dist/plugins/base-extensions.d.ts +8 -0
- package/dist/plugins/close-brackets.d.ts +8 -0
- package/dist/plugins/expand-text.d.ts +11 -0
- package/dist/plugins/fold.d.ts +8 -0
- package/dist/plugins/hanging-indent.d.ts +7 -0
- package/dist/plugins/indent-guide.d.ts +7 -0
- package/dist/plugins/index.d.ts +22 -0
- package/dist/plugins/keymap.d.ts +8 -0
- package/dist/plugins/line-numbers.d.ts +7 -0
- package/dist/plugins/link-handler.d.ts +8 -0
- package/dist/plugins/list-continuation.d.ts +8 -0
- package/dist/plugins/live-preview.d.ts +8 -0
- package/dist/plugins/markdown-language.d.ts +8 -0
- package/dist/plugins/on-change.d.ts +7 -0
- package/dist/plugins/suggest.d.ts +16 -0
- package/dist/plugins/table-continuation.d.ts +9 -0
- package/dist/plugins/table.d.ts +7 -0
- package/dist/plugins/theme.d.ts +8 -0
- package/dist/plugins/types.d.ts +29 -0
- package/dist/table/copy-widget.d.ts +17 -0
- package/dist/table/detect.d.ts +15 -0
- package/dist/table/format.d.ts +15 -0
- package/dist/table/index.d.ts +6 -0
- package/dist/table/theme.d.ts +8 -0
- package/package.json +57 -0
- package/vendor/app.css +15715 -0
- package/vendor/enhance.js +641 -0
- package/vendor/i18n/en.json +2144 -0
- package/vendor/i18n/zh.json +2144 -0
- package/vendor/lib/codemirror.js +14806 -0
- package/vendor/lib/i18next.min.js +2654 -0
- package/vendor/lib/markdown.js +1717 -0
- package/vendor/lib/mathjax/output/chtml/fonts/tex.js +1 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_AMS-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Bold.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Calligraphic-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Bold.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Fraktur-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Main-Bold.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Main-Italic.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Main-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Math-BoldItalic.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Math-Italic.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Math-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Bold.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Italic.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_SansSerif-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Script-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Size1-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Size2-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Size3-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Size4-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Typewriter-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Vector-Bold.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Vector-Regular.woff +0 -0
- package/vendor/lib/mathjax/output/chtml/fonts/woff-v2/MathJax_Zero.woff +0 -0
- package/vendor/lib/mathjax/tex-chtml-full.js +36 -0
- package/vendor/lib/meta.min.js +1 -0
- package/vendor/lib/modes.min.js +236 -0
- package/vendor/lib/turndown.js +679 -0
- package/vendor/mock.js +28 -0
- package/vendor/obsidian-app.patched.js +161786 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1806 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var exports_src = {};
|
|
31
|
+
__export(exports_src, {
|
|
32
|
+
themePlugin: () => themePlugin,
|
|
33
|
+
tablePlugin: () => tablePlugin,
|
|
34
|
+
tableContinuationPlugin: () => tableContinuationPlugin,
|
|
35
|
+
suggestPlugin: () => suggestPlugin,
|
|
36
|
+
onChangePlugin: () => onChangePlugin,
|
|
37
|
+
markdownLanguagePlugin: () => markdownLanguagePlugin,
|
|
38
|
+
livePreviewPlugin: () => livePreviewPlugin,
|
|
39
|
+
listContinuationPlugin: () => listContinuationPlugin,
|
|
40
|
+
linkHandlerPlugin: () => linkHandlerPlugin,
|
|
41
|
+
lineNumbersPlugin: () => lineNumbersPlugin,
|
|
42
|
+
keymapPlugin: () => keymapPlugin,
|
|
43
|
+
indentGuidePlugin: () => indentGuidePlugin,
|
|
44
|
+
hangingIndentPlugin: () => hangingIndentPlugin,
|
|
45
|
+
foldPlugin: () => foldPlugin,
|
|
46
|
+
expandTextPlugin: () => expandTextPlugin,
|
|
47
|
+
createEditor: () => createEditor,
|
|
48
|
+
closeBracketsPlugin: () => closeBracketsPlugin,
|
|
49
|
+
baseExtensionsPlugin: () => baseExtensionsPlugin,
|
|
50
|
+
autoLoad: () => autoLoad,
|
|
51
|
+
attachmentPlugin: () => attachmentPlugin
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(exports_src);
|
|
54
|
+
|
|
55
|
+
// src/defaults.ts
|
|
56
|
+
var defaultBackend = {
|
|
57
|
+
resolveLinkPath() {
|
|
58
|
+
return null;
|
|
59
|
+
},
|
|
60
|
+
getResourceUrl(path) {
|
|
61
|
+
return path;
|
|
62
|
+
},
|
|
63
|
+
async listLinkTargets() {
|
|
64
|
+
return [];
|
|
65
|
+
},
|
|
66
|
+
async readFile() {
|
|
67
|
+
return "";
|
|
68
|
+
},
|
|
69
|
+
openFile() {},
|
|
70
|
+
async saveAttachment() {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var defaultOptions = {
|
|
75
|
+
tabSize: 4,
|
|
76
|
+
useTab: true,
|
|
77
|
+
readableLineWidth: true,
|
|
78
|
+
showLineNumber: true,
|
|
79
|
+
showIndentGuide: true,
|
|
80
|
+
foldHeading: true,
|
|
81
|
+
foldIndent: true,
|
|
82
|
+
autoPairBrackets: true,
|
|
83
|
+
autoPairMarkdown: true,
|
|
84
|
+
spellcheck: false,
|
|
85
|
+
theme: "dark",
|
|
86
|
+
cssVariables: {}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/mocks.ts
|
|
90
|
+
function createMockOwner(filePath) {
|
|
91
|
+
return {
|
|
92
|
+
file: {
|
|
93
|
+
path: filePath || "untitled.md",
|
|
94
|
+
name: (filePath || "untitled.md").split("/").pop(),
|
|
95
|
+
basename: (filePath || "untitled.md").split("/").pop().replace(/\.md$/, ""),
|
|
96
|
+
extension: "md"
|
|
97
|
+
},
|
|
98
|
+
saveImmediately(fn) {
|
|
99
|
+
if (fn)
|
|
100
|
+
fn();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function createMockApp(backend, opts) {
|
|
105
|
+
return {
|
|
106
|
+
vault: {
|
|
107
|
+
getConfig(key) {
|
|
108
|
+
const configs = {
|
|
109
|
+
tabSize: opts.tabSize,
|
|
110
|
+
useTab: opts.useTab,
|
|
111
|
+
readableLineLength: opts.readableLineWidth,
|
|
112
|
+
showFrontmatter: false,
|
|
113
|
+
livePreview: true,
|
|
114
|
+
autoPairBrackets: opts.autoPairBrackets,
|
|
115
|
+
autoPairMarkdown: opts.autoPairMarkdown,
|
|
116
|
+
rightToLeft: false,
|
|
117
|
+
spellcheck: opts.spellcheck,
|
|
118
|
+
showLineNumber: opts.showLineNumber,
|
|
119
|
+
showIndentGuide: opts.showIndentGuide,
|
|
120
|
+
foldHeading: opts.foldHeading,
|
|
121
|
+
foldIndent: opts.foldIndent
|
|
122
|
+
};
|
|
123
|
+
return configs[key];
|
|
124
|
+
},
|
|
125
|
+
adapter: {
|
|
126
|
+
getResourcePath(p) {
|
|
127
|
+
return backend.getResourceUrl(p);
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
on() {
|
|
131
|
+
return { id: 0 };
|
|
132
|
+
},
|
|
133
|
+
off() {},
|
|
134
|
+
offref() {}
|
|
135
|
+
},
|
|
136
|
+
workspace: {
|
|
137
|
+
openLinkText(link) {
|
|
138
|
+
backend.openFile(link);
|
|
139
|
+
},
|
|
140
|
+
getLeaf() {
|
|
141
|
+
return { openLinkText(link) {
|
|
142
|
+
backend.openFile(link);
|
|
143
|
+
} };
|
|
144
|
+
},
|
|
145
|
+
on() {
|
|
146
|
+
return { id: 0 };
|
|
147
|
+
},
|
|
148
|
+
off() {},
|
|
149
|
+
offref() {}
|
|
150
|
+
},
|
|
151
|
+
metadataCache: {
|
|
152
|
+
getFirstLinkpathDest(link, sourcePath) {
|
|
153
|
+
const resolved = backend.resolveLinkPath(link, sourcePath);
|
|
154
|
+
return resolved ? { path: resolved } : null;
|
|
155
|
+
},
|
|
156
|
+
on() {
|
|
157
|
+
return { id: 0 };
|
|
158
|
+
},
|
|
159
|
+
off() {},
|
|
160
|
+
offref() {}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function createMockEditor(mockApp, mockOwner, view, editorEl) {
|
|
165
|
+
return {
|
|
166
|
+
app: mockApp,
|
|
167
|
+
get path() {
|
|
168
|
+
return mockOwner.file?.path || "";
|
|
169
|
+
},
|
|
170
|
+
get file() {
|
|
171
|
+
return mockOwner.file;
|
|
172
|
+
},
|
|
173
|
+
cm: view,
|
|
174
|
+
editorEl,
|
|
175
|
+
owner: mockOwner,
|
|
176
|
+
addChild(c) {
|
|
177
|
+
return c;
|
|
178
|
+
},
|
|
179
|
+
removeChild(_c) {},
|
|
180
|
+
editTableCell(table, cell) {
|
|
181
|
+
return this.tableCell ||= {
|
|
182
|
+
table,
|
|
183
|
+
cell,
|
|
184
|
+
editor: { cm: view },
|
|
185
|
+
cm: view,
|
|
186
|
+
setReadonly() {},
|
|
187
|
+
onContextMenu() {}
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
destroyTableCell() {
|
|
191
|
+
this.tableCell = null;
|
|
192
|
+
},
|
|
193
|
+
tableCell: null
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/plugins/live-preview.ts
|
|
198
|
+
var livePreviewPlugin = {
|
|
199
|
+
id: "live-preview",
|
|
200
|
+
deps: ["base-extensions"],
|
|
201
|
+
install(ctx) {
|
|
202
|
+
const { livePreview: KB } = window.__stateFields;
|
|
203
|
+
const __kH = window.__kH;
|
|
204
|
+
if (!KB || !__kH) {
|
|
205
|
+
console.warn("[live-preview] Obsidian runtime not available");
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const mockEditor = ctx.getState("__mockEditor");
|
|
209
|
+
const extensions = [];
|
|
210
|
+
extensions.push(KB.init(() => true));
|
|
211
|
+
const livePreviewExts = __kH(mockEditor, ctx.view);
|
|
212
|
+
if (livePreviewExts) {
|
|
213
|
+
extensions.push(livePreviewExts);
|
|
214
|
+
}
|
|
215
|
+
return extensions;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
// src/plugins/markdown-language.ts
|
|
219
|
+
var markdownLanguagePlugin = {
|
|
220
|
+
id: "markdown-language",
|
|
221
|
+
install(_ctx) {
|
|
222
|
+
const lang = window.__language;
|
|
223
|
+
if (!lang) {
|
|
224
|
+
console.warn("[markdown-language] Obsidian language extension not available");
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
return lang;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
// src/plugins/hanging-indent.ts
|
|
231
|
+
var hangingIndentPlugin = {
|
|
232
|
+
id: "hanging-indent",
|
|
233
|
+
install(_ctx) {
|
|
234
|
+
const ext = window.__hangingIndent;
|
|
235
|
+
if (!ext) {
|
|
236
|
+
console.warn("[hanging-indent] Extension not available");
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
return ext;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
// src/plugins/list-continuation.ts
|
|
243
|
+
var LIST_REGEX = /^([>\s]*)(([*+-] |(\d+)([.)] ))(?:\[(.)\] )?)?/;
|
|
244
|
+
var listContinuationPlugin = {
|
|
245
|
+
id: "list-continuation",
|
|
246
|
+
install(ctx) {
|
|
247
|
+
const { keymap, Prec } = window.__cm6;
|
|
248
|
+
const __newlineAndIndent = window.__commands?.newlineAndIndent;
|
|
249
|
+
return Prec.high(keymap.of([
|
|
250
|
+
{
|
|
251
|
+
key: "Enter",
|
|
252
|
+
run(v) {
|
|
253
|
+
const state = v.state;
|
|
254
|
+
const { head } = state.selection.main;
|
|
255
|
+
const line = state.doc.lineAt(head);
|
|
256
|
+
const match = LIST_REGEX.exec(line.text);
|
|
257
|
+
if (!match)
|
|
258
|
+
return false;
|
|
259
|
+
const prefix = match[0];
|
|
260
|
+
const blockquote = match[1] || "";
|
|
261
|
+
const listMarker = match[2] || "";
|
|
262
|
+
if (!blockquote && !listMarker)
|
|
263
|
+
return false;
|
|
264
|
+
if (line.text.slice(prefix.length).trim() === "") {
|
|
265
|
+
v.dispatch({
|
|
266
|
+
changes: { from: line.from, to: line.to, insert: "" },
|
|
267
|
+
userEvent: "input.type"
|
|
268
|
+
});
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
if (listMarker) {
|
|
272
|
+
let newMarker = listMarker;
|
|
273
|
+
const ordNum = match[4];
|
|
274
|
+
if (ordNum) {
|
|
275
|
+
const sep = match[5];
|
|
276
|
+
newMarker = parseInt(ordNum) + 1 + sep;
|
|
277
|
+
}
|
|
278
|
+
const checkbox = match[6] !== undefined ? "[ ] " : "";
|
|
279
|
+
if (checkbox)
|
|
280
|
+
newMarker = newMarker.replace(/\[.\] $/, "");
|
|
281
|
+
const insert = `
|
|
282
|
+
` + blockquote + newMarker + checkbox;
|
|
283
|
+
v.dispatch({
|
|
284
|
+
changes: { from: head, insert },
|
|
285
|
+
selection: { anchor: head + insert.length },
|
|
286
|
+
userEvent: "input.type"
|
|
287
|
+
});
|
|
288
|
+
} else {
|
|
289
|
+
const insert = `
|
|
290
|
+
` + blockquote;
|
|
291
|
+
v.dispatch({
|
|
292
|
+
changes: { from: head, insert },
|
|
293
|
+
selection: { anchor: head + insert.length },
|
|
294
|
+
userEvent: "input.type"
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return true;
|
|
298
|
+
},
|
|
299
|
+
shift(v) {
|
|
300
|
+
if (__newlineAndIndent)
|
|
301
|
+
return __newlineAndIndent(v);
|
|
302
|
+
return false;
|
|
303
|
+
},
|
|
304
|
+
preventDefault: true
|
|
305
|
+
}
|
|
306
|
+
]));
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
// src/plugins/close-brackets.ts
|
|
310
|
+
var closeBracketsPlugin = {
|
|
311
|
+
id: "close-brackets",
|
|
312
|
+
install(ctx) {
|
|
313
|
+
const { EditorState, keymap } = window.__cm6;
|
|
314
|
+
const closeBrackets = window.__closeBrackets;
|
|
315
|
+
if (!closeBrackets) {
|
|
316
|
+
console.warn("[close-brackets] Obsidian closeBrackets extension not available");
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
const { inputHandler: pT, stateField: lT, keymap: fT, markdownSurround: iB } = closeBrackets;
|
|
320
|
+
if (!pT || !lT || !fT)
|
|
321
|
+
return [];
|
|
322
|
+
const opts = ctx.options;
|
|
323
|
+
const brackets = [];
|
|
324
|
+
if (opts.autoPairBrackets !== false)
|
|
325
|
+
brackets.push("(", "[", "{", "'", '"');
|
|
326
|
+
if (opts.autoPairMarkdown !== false)
|
|
327
|
+
brackets.push("*", "_", "`", "```");
|
|
328
|
+
const extensions = [
|
|
329
|
+
pT,
|
|
330
|
+
lT,
|
|
331
|
+
keymap.of(fT),
|
|
332
|
+
EditorState.languageData.of(() => [{ closeBrackets: { brackets } }])
|
|
333
|
+
];
|
|
334
|
+
if (iB)
|
|
335
|
+
extensions.push(iB);
|
|
336
|
+
const frontmatterHandler = window.__frontmatterHandler;
|
|
337
|
+
if (frontmatterHandler)
|
|
338
|
+
extensions.push(frontmatterHandler);
|
|
339
|
+
return extensions;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
// src/plugins/expand-text.ts
|
|
343
|
+
var RULES = [
|
|
344
|
+
{ regex: /(!)?【【$/, replace: (m) => m[1] ? "![[" : "[[" },
|
|
345
|
+
{ regex: /】】$/, replace: () => "]]" },
|
|
346
|
+
{ regex: /···$/, replace: () => "```" }
|
|
347
|
+
];
|
|
348
|
+
var expandTextPlugin = {
|
|
349
|
+
id: "expand-text",
|
|
350
|
+
install(ctx) {
|
|
351
|
+
const { EditorView } = window.__cm6;
|
|
352
|
+
return EditorView.updateListener.of((update) => {
|
|
353
|
+
if (!update.docChanged)
|
|
354
|
+
return;
|
|
355
|
+
const isUserInput = update.transactions.some((tr) => tr.isUserEvent("input"));
|
|
356
|
+
if (!isUserInput)
|
|
357
|
+
return;
|
|
358
|
+
const state = update.state;
|
|
359
|
+
const cursor = state.selection.main.head;
|
|
360
|
+
const line = state.doc.lineAt(cursor);
|
|
361
|
+
const textBefore = line.text.slice(0, cursor - line.from);
|
|
362
|
+
for (const rule of RULES) {
|
|
363
|
+
const match = textBefore.match(rule.regex);
|
|
364
|
+
if (match) {
|
|
365
|
+
const replaceText = rule.replace(match);
|
|
366
|
+
const from = cursor - match[0].length;
|
|
367
|
+
setTimeout(() => {
|
|
368
|
+
ctx.view.dispatch({
|
|
369
|
+
changes: { from, to: cursor, insert: replaceText },
|
|
370
|
+
selection: { anchor: from + replaceText.length },
|
|
371
|
+
userEvent: "input.type"
|
|
372
|
+
});
|
|
373
|
+
}, 0);
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
// src/plugins/fold.ts
|
|
381
|
+
var foldPlugin = {
|
|
382
|
+
id: "fold",
|
|
383
|
+
install(ctx) {
|
|
384
|
+
const opts = ctx.options;
|
|
385
|
+
if (!opts.foldHeading && !opts.foldIndent)
|
|
386
|
+
return [];
|
|
387
|
+
const foldGutter = window.__foldGutter;
|
|
388
|
+
const foldExtensions = window.__foldExtensions;
|
|
389
|
+
const foldHeading = window.__foldHeading;
|
|
390
|
+
const foldIndent = window.__foldIndent;
|
|
391
|
+
const foldEffect = window.__foldEffect;
|
|
392
|
+
if (!foldGutter || !foldExtensions) {
|
|
393
|
+
console.warn("[fold] Fold extensions not available");
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
const extensions = [];
|
|
397
|
+
extensions.push(foldGutter());
|
|
398
|
+
extensions.push(...foldExtensions);
|
|
399
|
+
if (opts.foldHeading && foldHeading)
|
|
400
|
+
extensions.push(foldHeading);
|
|
401
|
+
if (opts.foldIndent && foldIndent)
|
|
402
|
+
extensions.push(foldIndent);
|
|
403
|
+
if (foldEffect)
|
|
404
|
+
extensions.push(foldEffect);
|
|
405
|
+
const container = ctx.view.dom?.parentElement;
|
|
406
|
+
if (container)
|
|
407
|
+
container.classList.add("is-folding");
|
|
408
|
+
return extensions;
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
// src/plugins/line-numbers.ts
|
|
412
|
+
var lineNumbersPlugin = {
|
|
413
|
+
id: "line-numbers",
|
|
414
|
+
install(_ctx) {
|
|
415
|
+
const __lineNumbers = window.__lineNumbers;
|
|
416
|
+
const __activeLineGutter = window.__activeLineGutter;
|
|
417
|
+
const __highlightActiveLineGutter = window.__highlightActiveLineGutter;
|
|
418
|
+
if (!__lineNumbers) {
|
|
419
|
+
console.warn("[line-numbers] lineNumbers extension not available");
|
|
420
|
+
return [];
|
|
421
|
+
}
|
|
422
|
+
const extensions = [__lineNumbers({ fixed: false })];
|
|
423
|
+
if (__activeLineGutter)
|
|
424
|
+
extensions.push(__activeLineGutter);
|
|
425
|
+
if (__highlightActiveLineGutter)
|
|
426
|
+
extensions.push(__highlightActiveLineGutter());
|
|
427
|
+
return extensions;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
// src/plugins/indent-guide.ts
|
|
431
|
+
var indentGuidePlugin = {
|
|
432
|
+
id: "indent-guide",
|
|
433
|
+
install(_ctx) {
|
|
434
|
+
const ext = window.__indentGuide;
|
|
435
|
+
if (!ext) {
|
|
436
|
+
console.warn("[indent-guide] indentGuide extension not available");
|
|
437
|
+
return [];
|
|
438
|
+
}
|
|
439
|
+
return ext;
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
// src/plugins/suggest.ts
|
|
443
|
+
function escapeHtml(str) {
|
|
444
|
+
const div = document.createElement("div");
|
|
445
|
+
div.appendChild(document.createTextNode(str));
|
|
446
|
+
return div.innerHTML;
|
|
447
|
+
}
|
|
448
|
+
var suggestPlugin = {
|
|
449
|
+
id: "suggest",
|
|
450
|
+
install(ctx) {
|
|
451
|
+
const { EditorView, Prec, keymap, StateEffect } = window.__cm6;
|
|
452
|
+
const { view } = ctx;
|
|
453
|
+
const providers = [];
|
|
454
|
+
let suggestEl = null;
|
|
455
|
+
let suggestItems = [];
|
|
456
|
+
let selectedIdx = 0;
|
|
457
|
+
let triggerFrom = -1;
|
|
458
|
+
let activeProvider = null;
|
|
459
|
+
function createSuggestEl() {
|
|
460
|
+
if (suggestEl)
|
|
461
|
+
return suggestEl;
|
|
462
|
+
suggestEl = document.createElement("div");
|
|
463
|
+
suggestEl.className = "xlxz-suggest";
|
|
464
|
+
suggestEl.style.cssText = "position:fixed;z-index:1000;" + "background:var(--background-secondary,#252526);" + "border:1px solid var(--background-modifier-border,#454545);" + "border-radius:4px;max-height:200px;overflow-y:auto;min-width:200px;" + "box-shadow:0 2px 8px rgba(0,0,0,0.3);font-size:13px;display:none;";
|
|
465
|
+
document.body.appendChild(suggestEl);
|
|
466
|
+
suggestEl.addEventListener("mousedown", (e) => e.preventDefault());
|
|
467
|
+
suggestEl.addEventListener("click", (e) => {
|
|
468
|
+
const itemEl = e.target.closest("[data-idx]");
|
|
469
|
+
if (itemEl)
|
|
470
|
+
acceptSuggestion(parseInt(itemEl.getAttribute("data-idx")));
|
|
471
|
+
});
|
|
472
|
+
return suggestEl;
|
|
473
|
+
}
|
|
474
|
+
function showSuggest(coords, items) {
|
|
475
|
+
const el = createSuggestEl();
|
|
476
|
+
suggestItems = items;
|
|
477
|
+
selectedIdx = 0;
|
|
478
|
+
el.innerHTML = items.map((item, i) => `<div data-idx="${i}" style="padding:4px 8px;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;${i === 0 ? "background:var(--background-modifier-hover,#04395e);" : ""}">${escapeHtml(item.label)}</div>`).join("");
|
|
479
|
+
el.style.left = coords.left + "px";
|
|
480
|
+
el.style.top = coords.bottom + 2 + "px";
|
|
481
|
+
el.style.display = "block";
|
|
482
|
+
}
|
|
483
|
+
function hideSuggest() {
|
|
484
|
+
if (suggestEl)
|
|
485
|
+
suggestEl.style.display = "none";
|
|
486
|
+
suggestItems = [];
|
|
487
|
+
triggerFrom = -1;
|
|
488
|
+
activeProvider = null;
|
|
489
|
+
}
|
|
490
|
+
function isVisible() {
|
|
491
|
+
return suggestEl && suggestEl.style.display !== "none";
|
|
492
|
+
}
|
|
493
|
+
function updateSelection(idx) {
|
|
494
|
+
if (!suggestEl)
|
|
495
|
+
return;
|
|
496
|
+
selectedIdx = Math.max(0, Math.min(idx, suggestItems.length - 1));
|
|
497
|
+
const items = suggestEl.querySelectorAll("[data-idx]");
|
|
498
|
+
items.forEach((el, i) => {
|
|
499
|
+
el.style.background = i === selectedIdx ? "var(--background-modifier-hover,#04395e)" : "";
|
|
500
|
+
});
|
|
501
|
+
items[selectedIdx]?.scrollIntoView({ block: "nearest" });
|
|
502
|
+
}
|
|
503
|
+
function acceptSuggestion(idx) {
|
|
504
|
+
if (idx < 0 || idx >= suggestItems.length || !activeProvider)
|
|
505
|
+
return;
|
|
506
|
+
const item = suggestItems[idx];
|
|
507
|
+
const cursor = view.state.selection.main.head;
|
|
508
|
+
const insertText = item.insertText + (activeProvider.suffix || "");
|
|
509
|
+
view.dispatch({
|
|
510
|
+
changes: { from: triggerFrom, to: cursor, insert: insertText },
|
|
511
|
+
selection: { anchor: triggerFrom + insertText.length },
|
|
512
|
+
userEvent: "input.type"
|
|
513
|
+
});
|
|
514
|
+
const provider = activeProvider;
|
|
515
|
+
hideSuggest();
|
|
516
|
+
view.focus();
|
|
517
|
+
if (provider.onAccept)
|
|
518
|
+
provider.onAccept(item);
|
|
519
|
+
}
|
|
520
|
+
function getCoords(update) {
|
|
521
|
+
const cursor = update.state.selection.main.head;
|
|
522
|
+
let coords = update.view.coordsAtPos(cursor);
|
|
523
|
+
if (!coords) {
|
|
524
|
+
const sel = window.getSelection();
|
|
525
|
+
if (sel && sel.rangeCount > 0) {
|
|
526
|
+
const rect = sel.getRangeAt(0).getBoundingClientRect();
|
|
527
|
+
if (rect.height > 0)
|
|
528
|
+
coords = { left: rect.left, bottom: rect.bottom };
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (!coords) {
|
|
532
|
+
const cursorEl = update.view.dom.querySelector(".cm-cursor");
|
|
533
|
+
if (cursorEl) {
|
|
534
|
+
const r = cursorEl.getBoundingClientRect();
|
|
535
|
+
coords = { left: r.left, bottom: r.bottom };
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (!coords) {
|
|
539
|
+
const r = update.view.dom.getBoundingClientRect();
|
|
540
|
+
coords = { left: r.left + 50, bottom: r.top + 30 };
|
|
541
|
+
}
|
|
542
|
+
return coords;
|
|
543
|
+
}
|
|
544
|
+
const listener = EditorView.updateListener.of((update) => {
|
|
545
|
+
if (!update.docChanged && !update.selectionSet)
|
|
546
|
+
return;
|
|
547
|
+
if (providers.length === 0) {
|
|
548
|
+
hideSuggest();
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const state = update.state;
|
|
552
|
+
const cursor = state.selection.main.head;
|
|
553
|
+
const line = state.doc.lineAt(cursor);
|
|
554
|
+
const textBefore = line.text.slice(0, cursor - line.from);
|
|
555
|
+
let matched = false;
|
|
556
|
+
for (const provider of providers) {
|
|
557
|
+
const match = textBefore.match(provider.trigger);
|
|
558
|
+
if (match) {
|
|
559
|
+
matched = true;
|
|
560
|
+
const query = match[1] || "";
|
|
561
|
+
triggerFrom = cursor - query.length;
|
|
562
|
+
activeProvider = provider;
|
|
563
|
+
const result = provider.getSuggestions(query);
|
|
564
|
+
const handleItems = (items) => {
|
|
565
|
+
if (items.length === 0) {
|
|
566
|
+
hideSuggest();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const coords = getCoords(update);
|
|
570
|
+
showSuggest(coords, items);
|
|
571
|
+
};
|
|
572
|
+
if (result instanceof Promise) {
|
|
573
|
+
result.then(handleItems);
|
|
574
|
+
} else {
|
|
575
|
+
handleItems(result);
|
|
576
|
+
}
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (!matched)
|
|
581
|
+
hideSuggest();
|
|
582
|
+
});
|
|
583
|
+
const suggestKeymap = Prec.highest(keymap.of([
|
|
584
|
+
{
|
|
585
|
+
key: "ArrowDown",
|
|
586
|
+
run() {
|
|
587
|
+
if (!isVisible())
|
|
588
|
+
return false;
|
|
589
|
+
updateSelection(selectedIdx + 1);
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
key: "ArrowUp",
|
|
595
|
+
run() {
|
|
596
|
+
if (!isVisible())
|
|
597
|
+
return false;
|
|
598
|
+
updateSelection(selectedIdx - 1);
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
key: "Enter",
|
|
604
|
+
run() {
|
|
605
|
+
if (!isVisible())
|
|
606
|
+
return false;
|
|
607
|
+
acceptSuggestion(selectedIdx);
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
key: "Tab",
|
|
613
|
+
run() {
|
|
614
|
+
if (!isVisible())
|
|
615
|
+
return false;
|
|
616
|
+
acceptSuggestion(selectedIdx);
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
key: "Escape",
|
|
622
|
+
run() {
|
|
623
|
+
if (!isVisible())
|
|
624
|
+
return false;
|
|
625
|
+
hideSuggest();
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
]));
|
|
630
|
+
const suggestState = {
|
|
631
|
+
providers,
|
|
632
|
+
addProvider(provider) {
|
|
633
|
+
providers.push(provider);
|
|
634
|
+
return () => this.removeProvider(provider.id);
|
|
635
|
+
},
|
|
636
|
+
removeProvider(id) {
|
|
637
|
+
const idx = providers.findIndex((p) => p.id === id);
|
|
638
|
+
if (idx !== -1)
|
|
639
|
+
providers.splice(idx, 1);
|
|
640
|
+
},
|
|
641
|
+
destroy() {
|
|
642
|
+
providers.length = 0;
|
|
643
|
+
if (suggestEl) {
|
|
644
|
+
suggestEl.remove();
|
|
645
|
+
suggestEl = null;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
ctx.setState("suggest", suggestState);
|
|
650
|
+
return [listener, suggestKeymap];
|
|
651
|
+
},
|
|
652
|
+
uninstall(ctx) {
|
|
653
|
+
const state = ctx.getState("suggest");
|
|
654
|
+
if (state)
|
|
655
|
+
state.destroy();
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
// src/plugins/link-handler.ts
|
|
659
|
+
var linkHandlerPlugin = {
|
|
660
|
+
id: "link-handler",
|
|
661
|
+
install(ctx) {
|
|
662
|
+
const { EditorView } = window.__cm6;
|
|
663
|
+
const { options: opts, backend: be, view } = ctx;
|
|
664
|
+
const editorEl = view.dom?.parentElement || view.dom;
|
|
665
|
+
const handler = (e) => {
|
|
666
|
+
const target = e.target;
|
|
667
|
+
if (!target?.closest)
|
|
668
|
+
return;
|
|
669
|
+
const internalLink = target.closest(".internal-link, .cm-hmd-internal-link");
|
|
670
|
+
if (internalLink) {
|
|
671
|
+
e.preventDefault();
|
|
672
|
+
e.stopPropagation();
|
|
673
|
+
const linkText = internalLink.getAttribute("data-href") || internalLink.getAttribute("href") || internalLink.textContent?.trim() || "";
|
|
674
|
+
if (linkText) {
|
|
675
|
+
if (opts.onLinkClick) {
|
|
676
|
+
opts.onLinkClick(linkText, opts.filePath || "");
|
|
677
|
+
} else {
|
|
678
|
+
be.openFile(linkText);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const externalLink = target.closest(".external-link");
|
|
684
|
+
if (externalLink) {
|
|
685
|
+
const href = externalLink.getAttribute("href") || externalLink.getAttribute("data-href") || "";
|
|
686
|
+
if (href && /^https?:|^mailto:/.test(href)) {
|
|
687
|
+
e.preventDefault();
|
|
688
|
+
e.stopPropagation();
|
|
689
|
+
if (opts.onExternalLinkClick) {
|
|
690
|
+
opts.onExternalLinkClick(href);
|
|
691
|
+
} else {
|
|
692
|
+
window.open(href, "_blank");
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const underline = target.closest(".cm-underline");
|
|
698
|
+
if (underline) {
|
|
699
|
+
const linkParent = underline.closest(".cm-hmd-internal-link");
|
|
700
|
+
if (linkParent) {
|
|
701
|
+
e.preventDefault();
|
|
702
|
+
e.stopPropagation();
|
|
703
|
+
const pos = view.posAtDOM(underline);
|
|
704
|
+
const doc = view.state.doc.toString();
|
|
705
|
+
const before = doc.lastIndexOf("[[", pos);
|
|
706
|
+
if (before !== -1 && before >= pos - 200) {
|
|
707
|
+
const after = doc.indexOf("]]", before + 2);
|
|
708
|
+
if (after !== -1 && after < pos + 200) {
|
|
709
|
+
const content = doc.slice(before + 2, after);
|
|
710
|
+
const pipeIdx = content.indexOf("|");
|
|
711
|
+
const linkContent = pipeIdx !== -1 ? content.slice(0, pipeIdx) : content;
|
|
712
|
+
if (opts.onLinkClick) {
|
|
713
|
+
opts.onLinkClick(linkContent, opts.filePath || "");
|
|
714
|
+
} else {
|
|
715
|
+
be.openFile(linkContent);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
const extParent = underline.closest(".cm-link");
|
|
722
|
+
if (extParent) {
|
|
723
|
+
e.preventDefault();
|
|
724
|
+
e.stopPropagation();
|
|
725
|
+
const urlEl = extParent.parentElement?.querySelector(".cm-url, .cm-string");
|
|
726
|
+
let url = "";
|
|
727
|
+
if (urlEl) {
|
|
728
|
+
url = urlEl.textContent?.replace(/^\(|\)$/g, "") || "";
|
|
729
|
+
}
|
|
730
|
+
if (!url || !/^https?:/.test(url)) {
|
|
731
|
+
const pos = view.posAtDOM(underline);
|
|
732
|
+
const line = view.state.doc.lineAt(pos);
|
|
733
|
+
const linkMatch = line.text.match(/\[([^\]]*)\]\(([^)]+)\)/g);
|
|
734
|
+
if (linkMatch) {
|
|
735
|
+
for (const m of linkMatch) {
|
|
736
|
+
const urlMatch = m.match(/\(([^)]+)\)/);
|
|
737
|
+
if (urlMatch && /^https?:/.test(urlMatch[1])) {
|
|
738
|
+
url = urlMatch[1];
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (/^https?:/.test(url)) {
|
|
745
|
+
if (opts.onExternalLinkClick) {
|
|
746
|
+
opts.onExternalLinkClick(url);
|
|
747
|
+
} else {
|
|
748
|
+
window.open(url, "_blank");
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
editorEl.addEventListener("click", handler);
|
|
755
|
+
ctx.setState("link-handler", { cleanup: () => editorEl.removeEventListener("click", handler) });
|
|
756
|
+
return [];
|
|
757
|
+
},
|
|
758
|
+
uninstall(ctx) {
|
|
759
|
+
const state = ctx.getState("link-handler");
|
|
760
|
+
if (state?.cleanup)
|
|
761
|
+
state.cleanup();
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
// src/plugins/attachment.ts
|
|
765
|
+
var attachmentPlugin = {
|
|
766
|
+
id: "attachment",
|
|
767
|
+
install(ctx) {
|
|
768
|
+
const { EditorView } = window.__cm6;
|
|
769
|
+
const { backend: be, view } = ctx;
|
|
770
|
+
const editorEl = view.dom?.parentElement || view.dom;
|
|
771
|
+
return EditorView.domEventHandlers({
|
|
772
|
+
dragover(e) {
|
|
773
|
+
e.preventDefault();
|
|
774
|
+
editorEl.classList.add("is-drop-target");
|
|
775
|
+
},
|
|
776
|
+
dragleave(_e) {
|
|
777
|
+
editorEl.classList.remove("is-drop-target");
|
|
778
|
+
},
|
|
779
|
+
async drop(e) {
|
|
780
|
+
editorEl.classList.remove("is-drop-target");
|
|
781
|
+
const files = e.dataTransfer?.files;
|
|
782
|
+
if (!files || files.length === 0)
|
|
783
|
+
return;
|
|
784
|
+
e.preventDefault();
|
|
785
|
+
for (const file of Array.from(files)) {
|
|
786
|
+
const buf = await file.arrayBuffer();
|
|
787
|
+
const savedPath = await be.saveAttachment(file.name, buf);
|
|
788
|
+
if (savedPath) {
|
|
789
|
+
const insert = file.type.startsWith("image/") ? `` : `[[${savedPath}]]`;
|
|
790
|
+
const { from, to } = view.state.selection.main;
|
|
791
|
+
view.dispatch({
|
|
792
|
+
changes: { from, to, insert },
|
|
793
|
+
selection: { anchor: from + insert.length },
|
|
794
|
+
userEvent: "input.drop"
|
|
795
|
+
});
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
},
|
|
799
|
+
paste(e) {
|
|
800
|
+
const items = e.clipboardData?.items;
|
|
801
|
+
if (items) {
|
|
802
|
+
for (const item of Array.from(items)) {
|
|
803
|
+
if (item.type.startsWith("image/")) {
|
|
804
|
+
e.preventDefault();
|
|
805
|
+
const blob = item.getAsFile();
|
|
806
|
+
if (!blob)
|
|
807
|
+
return;
|
|
808
|
+
blob.arrayBuffer().then(async (buf) => {
|
|
809
|
+
const name = "paste-" + Date.now() + "." + (blob.type.split("/")[1] || "png");
|
|
810
|
+
const savedPath = await be.saveAttachment(name, buf);
|
|
811
|
+
if (savedPath) {
|
|
812
|
+
const insert = ``;
|
|
813
|
+
const { from, to } = view.state.selection.main;
|
|
814
|
+
view.dispatch({
|
|
815
|
+
changes: { from, to, insert },
|
|
816
|
+
selection: { anchor: from + insert.length },
|
|
817
|
+
userEvent: "input.paste"
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
const html = e.clipboardData?.getData("text/html");
|
|
826
|
+
if (!html)
|
|
827
|
+
return;
|
|
828
|
+
if (!window.TurndownService)
|
|
829
|
+
return;
|
|
830
|
+
try {
|
|
831
|
+
const td = new window.TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
|
|
832
|
+
const md = td.turndown(html);
|
|
833
|
+
if (!md || !md.trim())
|
|
834
|
+
return;
|
|
835
|
+
e.preventDefault();
|
|
836
|
+
const { from, to } = view.state.selection.main;
|
|
837
|
+
view.dispatch({
|
|
838
|
+
changes: { from, to, insert: md },
|
|
839
|
+
selection: { anchor: from + md.length },
|
|
840
|
+
userEvent: "input.paste"
|
|
841
|
+
});
|
|
842
|
+
} catch (err) {
|
|
843
|
+
console.warn("Paste conversion failed:", err);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
// src/table/detect.ts
|
|
850
|
+
function isTableLine(text) {
|
|
851
|
+
const trimmed = text.trim();
|
|
852
|
+
return trimmed.startsWith("|") && trimmed.endsWith("|") && trimmed.length > 1;
|
|
853
|
+
}
|
|
854
|
+
function isSeparatorLine(text) {
|
|
855
|
+
return /^\|(\s*:?-+:?\s*\|)+$/.test(text.trim());
|
|
856
|
+
}
|
|
857
|
+
function findTableRanges(doc) {
|
|
858
|
+
const ranges = [];
|
|
859
|
+
let blockStart = null;
|
|
860
|
+
let blockFirstLine = 0;
|
|
861
|
+
let blockLastLine = 0;
|
|
862
|
+
let hasSeparator = false;
|
|
863
|
+
const lineCount = doc.lines;
|
|
864
|
+
for (let i = 1;i <= lineCount; i++) {
|
|
865
|
+
const line = doc.line(i);
|
|
866
|
+
if (isTableLine(line.text)) {
|
|
867
|
+
if (blockStart === null) {
|
|
868
|
+
blockStart = line.from;
|
|
869
|
+
blockFirstLine = i;
|
|
870
|
+
}
|
|
871
|
+
blockLastLine = i;
|
|
872
|
+
if (isSeparatorLine(line.text)) {
|
|
873
|
+
hasSeparator = true;
|
|
874
|
+
}
|
|
875
|
+
} else {
|
|
876
|
+
if (blockStart !== null && hasSeparator && blockLastLine - blockFirstLine >= 1) {
|
|
877
|
+
ranges.push({
|
|
878
|
+
from: blockStart,
|
|
879
|
+
to: doc.line(blockLastLine).to,
|
|
880
|
+
firstLine: blockFirstLine,
|
|
881
|
+
lastLine: blockLastLine
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
blockStart = null;
|
|
885
|
+
hasSeparator = false;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (blockStart !== null && hasSeparator && blockLastLine - blockFirstLine >= 1) {
|
|
889
|
+
ranges.push({
|
|
890
|
+
from: blockStart,
|
|
891
|
+
to: doc.line(blockLastLine).to,
|
|
892
|
+
firstLine: blockFirstLine,
|
|
893
|
+
lastLine: blockLastLine
|
|
894
|
+
});
|
|
895
|
+
}
|
|
896
|
+
return ranges;
|
|
897
|
+
}
|
|
898
|
+
function cursorInTable(state, table) {
|
|
899
|
+
for (const range of state.selection.ranges) {
|
|
900
|
+
if (range.from <= table.to && range.to >= table.from)
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// ../../node_modules/.bun/ansi-regex@6.2.2/node_modules/ansi-regex/index.js
|
|
907
|
+
function ansiRegex({ onlyFirst = false } = {}) {
|
|
908
|
+
const ST = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
|
|
909
|
+
const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
|
|
910
|
+
const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
|
|
911
|
+
const pattern = `${osc}|${csi}`;
|
|
912
|
+
return new RegExp(pattern, onlyFirst ? undefined : "g");
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// ../../node_modules/.bun/strip-ansi@7.2.0/node_modules/strip-ansi/index.js
|
|
916
|
+
var regex = ansiRegex();
|
|
917
|
+
function stripAnsi(string) {
|
|
918
|
+
if (typeof string !== "string") {
|
|
919
|
+
throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
|
|
920
|
+
}
|
|
921
|
+
if (!string.includes("\x1B") && !string.includes("")) {
|
|
922
|
+
return string;
|
|
923
|
+
}
|
|
924
|
+
return string.replace(regex, "");
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/lookup-data.js
|
|
928
|
+
var ambiguousMinimalCodePoint = 161;
|
|
929
|
+
var ambiguousMaximumCodePoint = 1114109;
|
|
930
|
+
var ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
931
|
+
var fullwidthMinimalCodePoint = 12288;
|
|
932
|
+
var fullwidthMaximumCodePoint = 65510;
|
|
933
|
+
var fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
934
|
+
var wideMinimalCodePoint = 4352;
|
|
935
|
+
var wideMaximumCodePoint = 262141;
|
|
936
|
+
var wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
937
|
+
|
|
938
|
+
// ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/utilities.js
|
|
939
|
+
var isInRange = (ranges, codePoint) => {
|
|
940
|
+
let low = 0;
|
|
941
|
+
let high = Math.floor(ranges.length / 2) - 1;
|
|
942
|
+
while (low <= high) {
|
|
943
|
+
const mid = Math.floor((low + high) / 2);
|
|
944
|
+
const i = mid * 2;
|
|
945
|
+
if (codePoint < ranges[i]) {
|
|
946
|
+
high = mid - 1;
|
|
947
|
+
} else if (codePoint > ranges[i + 1]) {
|
|
948
|
+
low = mid + 1;
|
|
949
|
+
} else {
|
|
950
|
+
return true;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
return false;
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/lookup.js
|
|
957
|
+
var commonCjkCodePoint = 19968;
|
|
958
|
+
var [wideFastPathStart, wideFastPathEnd] = /* @__PURE__ */ findWideFastPathRange(wideRanges);
|
|
959
|
+
function findWideFastPathRange(ranges) {
|
|
960
|
+
let fastPathStart = ranges[0];
|
|
961
|
+
let fastPathEnd = ranges[1];
|
|
962
|
+
for (let index = 0;index < ranges.length; index += 2) {
|
|
963
|
+
const start = ranges[index];
|
|
964
|
+
const end = ranges[index + 1];
|
|
965
|
+
if (commonCjkCodePoint >= start && commonCjkCodePoint <= end) {
|
|
966
|
+
return [start, end];
|
|
967
|
+
}
|
|
968
|
+
if (end - start > fastPathEnd - fastPathStart) {
|
|
969
|
+
fastPathStart = start;
|
|
970
|
+
fastPathEnd = end;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return [fastPathStart, fastPathEnd];
|
|
974
|
+
}
|
|
975
|
+
var isAmbiguous = (codePoint) => {
|
|
976
|
+
if (codePoint < ambiguousMinimalCodePoint || codePoint > ambiguousMaximumCodePoint) {
|
|
977
|
+
return false;
|
|
978
|
+
}
|
|
979
|
+
return isInRange(ambiguousRanges, codePoint);
|
|
980
|
+
};
|
|
981
|
+
var isFullWidth = (codePoint) => {
|
|
982
|
+
if (codePoint < fullwidthMinimalCodePoint || codePoint > fullwidthMaximumCodePoint) {
|
|
983
|
+
return false;
|
|
984
|
+
}
|
|
985
|
+
return isInRange(fullwidthRanges, codePoint);
|
|
986
|
+
};
|
|
987
|
+
var isWide = (codePoint) => {
|
|
988
|
+
if (codePoint >= wideFastPathStart && codePoint <= wideFastPathEnd) {
|
|
989
|
+
return true;
|
|
990
|
+
}
|
|
991
|
+
if (codePoint < wideMinimalCodePoint || codePoint > wideMaximumCodePoint) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
return isInRange(wideRanges, codePoint);
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
// ../../node_modules/.bun/get-east-asian-width@1.6.0/node_modules/get-east-asian-width/index.js
|
|
998
|
+
function validate(codePoint) {
|
|
999
|
+
if (!Number.isSafeInteger(codePoint)) {
|
|
1000
|
+
throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
function eastAsianWidth(codePoint, { ambiguousAsWide = false } = {}) {
|
|
1004
|
+
validate(codePoint);
|
|
1005
|
+
if (isFullWidth(codePoint) || isWide(codePoint) || ambiguousAsWide && isAmbiguous(codePoint)) {
|
|
1006
|
+
return 2;
|
|
1007
|
+
}
|
|
1008
|
+
return 1;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// ../../node_modules/.bun/string-width@8.2.1/node_modules/string-width/index.js
|
|
1012
|
+
var segmenter = new Intl.Segmenter;
|
|
1013
|
+
var zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Format}|\p{Mark}|\p{Surrogate})+$/v;
|
|
1014
|
+
var leadingNonPrintingRegex = /^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
1015
|
+
var rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
1016
|
+
var unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
1017
|
+
var extendedPictographicRegex = /\p{Extended_Pictographic}/gu;
|
|
1018
|
+
function isDoubleWidthNonRgiEmojiSequence(segment) {
|
|
1019
|
+
if (segment.length > 50) {
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
if (unqualifiedKeycapRegex.test(segment)) {
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
if (segment.includes("")) {
|
|
1026
|
+
const pictographics = segment.match(extendedPictographicRegex);
|
|
1027
|
+
return pictographics !== null && pictographics.length >= 2;
|
|
1028
|
+
}
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
function baseVisible(segment) {
|
|
1032
|
+
return segment.replace(leadingNonPrintingRegex, "");
|
|
1033
|
+
}
|
|
1034
|
+
function isZeroWidthCluster(segment) {
|
|
1035
|
+
return zeroWidthClusterRegex.test(segment);
|
|
1036
|
+
}
|
|
1037
|
+
function isHangulLeadingJamo(codePoint) {
|
|
1038
|
+
return codePoint >= 4352 && codePoint <= 4447 || codePoint >= 43360 && codePoint <= 43388;
|
|
1039
|
+
}
|
|
1040
|
+
function isHangulVowelJamo(codePoint) {
|
|
1041
|
+
return codePoint >= 4448 && codePoint <= 4519 || codePoint >= 55216 && codePoint <= 55238;
|
|
1042
|
+
}
|
|
1043
|
+
function isHangulTrailingJamo(codePoint) {
|
|
1044
|
+
return codePoint >= 4520 && codePoint <= 4607 || codePoint >= 55243 && codePoint <= 55291;
|
|
1045
|
+
}
|
|
1046
|
+
function isHangulJamo(codePoint) {
|
|
1047
|
+
return isHangulLeadingJamo(codePoint) || isHangulVowelJamo(codePoint) || isHangulTrailingJamo(codePoint);
|
|
1048
|
+
}
|
|
1049
|
+
function hangulClusterWidth(visibleSegment, eastAsianWidthOptions) {
|
|
1050
|
+
const codePoints = [];
|
|
1051
|
+
for (const character of visibleSegment) {
|
|
1052
|
+
if (zeroWidthClusterRegex.test(character)) {
|
|
1053
|
+
continue;
|
|
1054
|
+
}
|
|
1055
|
+
codePoints.push(character.codePointAt(0));
|
|
1056
|
+
}
|
|
1057
|
+
if (codePoints.length === 0) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
let width = 0;
|
|
1061
|
+
for (let index = 0;index < codePoints.length; index++) {
|
|
1062
|
+
const codePoint = codePoints[index];
|
|
1063
|
+
if (!isHangulJamo(codePoint)) {
|
|
1064
|
+
if (width === 0) {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
for (let remaining = index;remaining < codePoints.length; remaining++) {
|
|
1068
|
+
width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
|
|
1069
|
+
}
|
|
1070
|
+
return width;
|
|
1071
|
+
}
|
|
1072
|
+
if (isHangulLeadingJamo(codePoint) && isHangulVowelJamo(codePoints[index + 1])) {
|
|
1073
|
+
width += 2;
|
|
1074
|
+
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
1075
|
+
continue;
|
|
1076
|
+
}
|
|
1077
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1078
|
+
}
|
|
1079
|
+
return width;
|
|
1080
|
+
}
|
|
1081
|
+
function trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions) {
|
|
1082
|
+
let extra = 0;
|
|
1083
|
+
let first = true;
|
|
1084
|
+
for (const character of visibleSegment) {
|
|
1085
|
+
if (first) {
|
|
1086
|
+
first = false;
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
if (character >= "" && character <= "") {
|
|
1090
|
+
extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
return extra;
|
|
1094
|
+
}
|
|
1095
|
+
function stringWidth(input, options = {}) {
|
|
1096
|
+
if (typeof input !== "string" || input.length === 0) {
|
|
1097
|
+
return 0;
|
|
1098
|
+
}
|
|
1099
|
+
const {
|
|
1100
|
+
ambiguousIsNarrow = true,
|
|
1101
|
+
countAnsiEscapeCodes = false
|
|
1102
|
+
} = options;
|
|
1103
|
+
let string = input;
|
|
1104
|
+
if (!countAnsiEscapeCodes && (string.includes("\x1B") || string.includes(""))) {
|
|
1105
|
+
string = stripAnsi(string);
|
|
1106
|
+
}
|
|
1107
|
+
if (string.length === 0) {
|
|
1108
|
+
return 0;
|
|
1109
|
+
}
|
|
1110
|
+
if (/^[\u0020-\u007E]*$/.test(string)) {
|
|
1111
|
+
return string.length;
|
|
1112
|
+
}
|
|
1113
|
+
let width = 0;
|
|
1114
|
+
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
1115
|
+
for (const { segment } of segmenter.segment(string)) {
|
|
1116
|
+
if (isZeroWidthCluster(segment)) {
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
if (rgiEmojiRegex.test(segment) || isDoubleWidthNonRgiEmojiSequence(segment)) {
|
|
1120
|
+
width += 2;
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
const visibleSegment = baseVisible(segment);
|
|
1124
|
+
const hangulWidth = hangulClusterWidth(visibleSegment, eastAsianWidthOptions);
|
|
1125
|
+
if (hangulWidth !== undefined) {
|
|
1126
|
+
width += hangulWidth;
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
const codePoint = visibleSegment.codePointAt(0);
|
|
1130
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
1131
|
+
width += trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions);
|
|
1132
|
+
}
|
|
1133
|
+
return width;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// src/table/format.ts
|
|
1137
|
+
function parseCells(text) {
|
|
1138
|
+
return text.trim().split("|").slice(1, -1);
|
|
1139
|
+
}
|
|
1140
|
+
function cellContent(cell) {
|
|
1141
|
+
return cell.trim();
|
|
1142
|
+
}
|
|
1143
|
+
function isSeparatorCell(text) {
|
|
1144
|
+
return /^:?-+:?$/.test(text.trim());
|
|
1145
|
+
}
|
|
1146
|
+
function formatSeparatorCell(text, width) {
|
|
1147
|
+
const trimmed = text.trim();
|
|
1148
|
+
const leftColon = trimmed.startsWith(":");
|
|
1149
|
+
const rightColon = trimmed.endsWith(":");
|
|
1150
|
+
const dashCount = width - (leftColon ? 1 : 0) - (rightColon ? 1 : 0);
|
|
1151
|
+
return (leftColon ? ":" : "") + "-".repeat(Math.max(1, dashCount)) + (rightColon ? ":" : "");
|
|
1152
|
+
}
|
|
1153
|
+
function padEndVisual(str, targetWidth) {
|
|
1154
|
+
const currentWidth = stringWidth(str);
|
|
1155
|
+
const diff = targetWidth - currentWidth;
|
|
1156
|
+
if (diff <= 0)
|
|
1157
|
+
return str;
|
|
1158
|
+
return str + " ".repeat(diff);
|
|
1159
|
+
}
|
|
1160
|
+
function formatTable(doc, table) {
|
|
1161
|
+
const lines = [];
|
|
1162
|
+
for (let i = table.firstLine;i <= table.lastLine; i++) {
|
|
1163
|
+
lines.push(doc.line(i).text);
|
|
1164
|
+
}
|
|
1165
|
+
const rows = lines.map((l) => parseCells(l).map(cellContent));
|
|
1166
|
+
if (rows.length < 2)
|
|
1167
|
+
return null;
|
|
1168
|
+
const colCount = rows[0].length;
|
|
1169
|
+
if (colCount === 0)
|
|
1170
|
+
return null;
|
|
1171
|
+
const colWidths = [];
|
|
1172
|
+
for (let col = 0;col < colCount; col++) {
|
|
1173
|
+
let maxW = 3;
|
|
1174
|
+
for (const row of rows) {
|
|
1175
|
+
const cell = row[col] || "";
|
|
1176
|
+
if (!isSeparatorCell(cell)) {
|
|
1177
|
+
maxW = Math.max(maxW, stringWidth(cell));
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
colWidths.push(maxW);
|
|
1181
|
+
}
|
|
1182
|
+
const formatted = rows.map((row, rowIdx) => {
|
|
1183
|
+
const cells = [];
|
|
1184
|
+
for (let col = 0;col < colCount; col++) {
|
|
1185
|
+
const raw = row[col] || "";
|
|
1186
|
+
const width = colWidths[col];
|
|
1187
|
+
if (isSeparatorLine(lines[rowIdx])) {
|
|
1188
|
+
cells.push(" " + formatSeparatorCell(raw, width) + " ");
|
|
1189
|
+
} else {
|
|
1190
|
+
cells.push(" " + padEndVisual(raw, width) + " ");
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return "|" + cells.join("|") + "|";
|
|
1194
|
+
});
|
|
1195
|
+
const newText = formatted.join(`
|
|
1196
|
+
`);
|
|
1197
|
+
const oldText = doc.sliceString(table.from, table.to);
|
|
1198
|
+
if (newText === oldText)
|
|
1199
|
+
return null;
|
|
1200
|
+
return { from: table.from, to: table.to, insert: newText };
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// src/table/copy-widget.ts
|
|
1204
|
+
function createCopyButtonWidgetClass(WidgetType) {
|
|
1205
|
+
return class CopyButtonWidget extends WidgetType {
|
|
1206
|
+
tableFrom;
|
|
1207
|
+
tableTo;
|
|
1208
|
+
constructor(tableFrom, tableTo) {
|
|
1209
|
+
super();
|
|
1210
|
+
this.tableFrom = tableFrom;
|
|
1211
|
+
this.tableTo = tableTo;
|
|
1212
|
+
}
|
|
1213
|
+
toDOM(view) {
|
|
1214
|
+
const btn = document.createElement("button");
|
|
1215
|
+
btn.className = "cm-table-copy-btn";
|
|
1216
|
+
btn.title = "复制表格(Tab 分隔)";
|
|
1217
|
+
btn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
1218
|
+
btn.addEventListener("click", (e) => {
|
|
1219
|
+
e.preventDefault();
|
|
1220
|
+
e.stopPropagation();
|
|
1221
|
+
const doc = view.state.doc;
|
|
1222
|
+
const text = doc.sliceString(this.tableFrom, this.tableTo);
|
|
1223
|
+
const tsv = text.split(`
|
|
1224
|
+
`).filter((l) => !isSeparatorLine(l)).map((l) => parseCells(l).map(cellContent).join("\t")).join(`
|
|
1225
|
+
`);
|
|
1226
|
+
navigator.clipboard.writeText(tsv);
|
|
1227
|
+
btn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
|
|
1228
|
+
btn.style.color = "var(--text-success)";
|
|
1229
|
+
setTimeout(() => {
|
|
1230
|
+
btn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
1231
|
+
btn.style.color = "";
|
|
1232
|
+
}, 1500);
|
|
1233
|
+
});
|
|
1234
|
+
return btn;
|
|
1235
|
+
}
|
|
1236
|
+
eq(other) {
|
|
1237
|
+
return this.tableFrom === other.tableFrom && this.tableTo === other.tableTo;
|
|
1238
|
+
}
|
|
1239
|
+
ignoreEvent() {
|
|
1240
|
+
return true;
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// src/table/theme.ts
|
|
1246
|
+
function createTableTheme(EditorView) {
|
|
1247
|
+
return EditorView.baseTheme({
|
|
1248
|
+
".cm-table-header, .cm-table-separator, .cm-table-row-even, .cm-table-row-odd": {
|
|
1249
|
+
fontFamily: "var(--font-monospace)",
|
|
1250
|
+
position: "relative"
|
|
1251
|
+
},
|
|
1252
|
+
".cm-table-header": {
|
|
1253
|
+
backgroundColor: "var(--table-header-bg, rgba(80, 120, 200, 0.15))",
|
|
1254
|
+
fontWeight: "600"
|
|
1255
|
+
},
|
|
1256
|
+
".cm-table-separator": {
|
|
1257
|
+
backgroundColor: "var(--table-separator-bg, rgba(80, 120, 200, 0.04))",
|
|
1258
|
+
color: "var(--text-faint)"
|
|
1259
|
+
},
|
|
1260
|
+
".cm-table-active.cm-table-separator": {
|
|
1261
|
+
backgroundColor: "var(--table-separator-bg, rgba(80, 120, 200, 0.04))",
|
|
1262
|
+
color: "var(--text-muted)"
|
|
1263
|
+
},
|
|
1264
|
+
".cm-table-row-even": {
|
|
1265
|
+
backgroundColor: "var(--table-row-even-bg, rgba(80, 140, 220, 0.06))"
|
|
1266
|
+
},
|
|
1267
|
+
".cm-table-row-odd": {
|
|
1268
|
+
backgroundColor: "var(--table-row-odd-bg, rgba(80, 140, 220, 0.12))"
|
|
1269
|
+
},
|
|
1270
|
+
".cm-table-active.cm-table-header": {
|
|
1271
|
+
backgroundColor: "rgba(80, 120, 200, 0.10)"
|
|
1272
|
+
},
|
|
1273
|
+
".cm-table-active.cm-table-row-even": {
|
|
1274
|
+
backgroundColor: "rgba(80, 140, 220, 0.04)"
|
|
1275
|
+
},
|
|
1276
|
+
".cm-table-active.cm-table-row-odd": {
|
|
1277
|
+
backgroundColor: "rgba(80, 140, 220, 0.08)"
|
|
1278
|
+
},
|
|
1279
|
+
".cm-table-copy-btn": {
|
|
1280
|
+
position: "absolute",
|
|
1281
|
+
right: "6px",
|
|
1282
|
+
top: "6px",
|
|
1283
|
+
zIndex: "1",
|
|
1284
|
+
display: "inline-flex",
|
|
1285
|
+
alignItems: "center",
|
|
1286
|
+
justifyContent: "center",
|
|
1287
|
+
padding: "var(--size-4-1) var(--size-4-2)",
|
|
1288
|
+
borderRadius: "var(--code-radius, 4px)",
|
|
1289
|
+
border: "none",
|
|
1290
|
+
backgroundColor: "transparent",
|
|
1291
|
+
color: "var(--text-muted)",
|
|
1292
|
+
cursor: "var(--cursor)",
|
|
1293
|
+
fontSize: "var(--font-ui-smaller)",
|
|
1294
|
+
fontFamily: "var(--font-interface)",
|
|
1295
|
+
opacity: "0",
|
|
1296
|
+
transition: "opacity 0.15s"
|
|
1297
|
+
},
|
|
1298
|
+
".cm-table-header:hover .cm-table-copy-btn": {
|
|
1299
|
+
opacity: "1"
|
|
1300
|
+
},
|
|
1301
|
+
".cm-table-copy-btn:hover": {
|
|
1302
|
+
opacity: "1",
|
|
1303
|
+
backgroundColor: "var(--background-modifier-hover)"
|
|
1304
|
+
},
|
|
1305
|
+
'.cm-table-header span[class*="cm-hmd-table-sep"], .cm-table-separator span[class*="cm-hmd-table-sep"], .cm-table-row-even span[class*="cm-hmd-table-sep"], .cm-table-row-odd span[class*="cm-hmd-table-sep"]': {
|
|
1306
|
+
color: "var(--text-faint)"
|
|
1307
|
+
},
|
|
1308
|
+
'.cm-table-active span[class*="cm-hmd-table-sep"]': {
|
|
1309
|
+
color: "var(--text-muted)"
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// src/table/index.ts
|
|
1315
|
+
function createTableExtension() {
|
|
1316
|
+
const { EditorView, ViewPlugin, Decoration, WidgetType } = window.__cm6;
|
|
1317
|
+
const CopyButtonWidget = createCopyButtonWidgetClass(WidgetType);
|
|
1318
|
+
const tableHeaderDeco = Decoration.line({ class: "cm-table-header" });
|
|
1319
|
+
const tableSepDeco = Decoration.line({ class: "cm-table-separator" });
|
|
1320
|
+
const tableRowEvenDeco = Decoration.line({ class: "cm-table-row-even" });
|
|
1321
|
+
const tableRowOddDeco = Decoration.line({ class: "cm-table-row-odd" });
|
|
1322
|
+
const tableHeaderActiveDeco = Decoration.line({ class: "cm-table-header cm-table-active" });
|
|
1323
|
+
const tableSepActiveDeco = Decoration.line({ class: "cm-table-separator cm-table-active" });
|
|
1324
|
+
const tableRowEvenActiveDeco = Decoration.line({ class: "cm-table-row-even cm-table-active" });
|
|
1325
|
+
const tableRowOddActiveDeco = Decoration.line({ class: "cm-table-row-odd cm-table-active" });
|
|
1326
|
+
const tablePlugin = ViewPlugin.fromClass(class {
|
|
1327
|
+
decorations;
|
|
1328
|
+
formatPending = false;
|
|
1329
|
+
constructor(view) {
|
|
1330
|
+
this.decorations = this.buildDecorations(view);
|
|
1331
|
+
}
|
|
1332
|
+
update(update) {
|
|
1333
|
+
if (update.docChanged || update.selectionSet || update.viewportChanged) {
|
|
1334
|
+
this.decorations = this.buildDecorations(update.view);
|
|
1335
|
+
}
|
|
1336
|
+
if (update.selectionSet && !update.docChanged && !this.formatPending) {
|
|
1337
|
+
this.formatPending = true;
|
|
1338
|
+
const view = update.view;
|
|
1339
|
+
requestAnimationFrame(() => {
|
|
1340
|
+
this.formatPending = false;
|
|
1341
|
+
this.maybeFormatTables(view);
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
maybeFormatTables(view) {
|
|
1346
|
+
const { state } = view;
|
|
1347
|
+
const doc = state.doc;
|
|
1348
|
+
const tables = findTableRanges(doc);
|
|
1349
|
+
const changes = [];
|
|
1350
|
+
for (const table of tables) {
|
|
1351
|
+
if (!cursorInTable(state, table)) {
|
|
1352
|
+
const change = formatTable(doc, table);
|
|
1353
|
+
if (change)
|
|
1354
|
+
changes.push(change);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (changes.length > 0) {
|
|
1358
|
+
view.dispatch({ changes });
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
buildDecorations(view) {
|
|
1362
|
+
const { state } = view;
|
|
1363
|
+
const doc = state.doc;
|
|
1364
|
+
const tables = findTableRanges(doc);
|
|
1365
|
+
const builder = [];
|
|
1366
|
+
for (const table of tables) {
|
|
1367
|
+
const isActive = cursorInTable(state, table);
|
|
1368
|
+
let bodyRowIndex = 0;
|
|
1369
|
+
for (let lineNum = table.firstLine;lineNum <= table.lastLine; lineNum++) {
|
|
1370
|
+
const line = doc.line(lineNum);
|
|
1371
|
+
const text = line.text;
|
|
1372
|
+
if (lineNum === table.firstLine) {
|
|
1373
|
+
builder.push((isActive ? tableHeaderActiveDeco : tableHeaderDeco).range(line.from));
|
|
1374
|
+
} else if (isSeparatorLine(text)) {
|
|
1375
|
+
builder.push((isActive ? tableSepActiveDeco : tableSepDeco).range(line.from));
|
|
1376
|
+
} else {
|
|
1377
|
+
const even = bodyRowIndex % 2 === 0;
|
|
1378
|
+
const deco = isActive ? even ? tableRowEvenActiveDeco : tableRowOddActiveDeco : even ? tableRowEvenDeco : tableRowOddDeco;
|
|
1379
|
+
builder.push(deco.range(line.from));
|
|
1380
|
+
bodyRowIndex++;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
if (!isActive) {
|
|
1384
|
+
const widget = Decoration.widget({
|
|
1385
|
+
widget: new CopyButtonWidget(table.from, table.to),
|
|
1386
|
+
side: 1
|
|
1387
|
+
});
|
|
1388
|
+
builder.push(widget.range(doc.line(table.firstLine).from));
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
builder.sort((a, b) => a.from - b.from);
|
|
1392
|
+
return Decoration.set(builder);
|
|
1393
|
+
}
|
|
1394
|
+
}, {
|
|
1395
|
+
decorations: (v) => v.decorations
|
|
1396
|
+
});
|
|
1397
|
+
const tableTheme = createTableTheme(EditorView);
|
|
1398
|
+
return [tablePlugin, tableTheme];
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// src/plugins/table.ts
|
|
1402
|
+
var tablePlugin = {
|
|
1403
|
+
id: "table",
|
|
1404
|
+
install(_ctx) {
|
|
1405
|
+
return createTableExtension();
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
// src/plugins/table-continuation.ts
|
|
1409
|
+
function isEmptyRow(text) {
|
|
1410
|
+
if (!isTableLine(text))
|
|
1411
|
+
return false;
|
|
1412
|
+
if (isSeparatorLine(text))
|
|
1413
|
+
return false;
|
|
1414
|
+
const cells = text.trim().split("|").slice(1, -1);
|
|
1415
|
+
return cells.every((c) => c.trim() === "");
|
|
1416
|
+
}
|
|
1417
|
+
function getColumnCount(doc, table) {
|
|
1418
|
+
const headerText = doc.line(table.firstLine).text;
|
|
1419
|
+
return headerText.trim().split("|").slice(1, -1).length;
|
|
1420
|
+
}
|
|
1421
|
+
function getCellWidths(text) {
|
|
1422
|
+
const cells = text.trim().split("|").slice(1, -1);
|
|
1423
|
+
return cells.map((c) => Math.max(c.length, 3));
|
|
1424
|
+
}
|
|
1425
|
+
function buildEmptyRow(colCount, widths) {
|
|
1426
|
+
const cells = [];
|
|
1427
|
+
for (let i = 0;i < colCount; i++) {
|
|
1428
|
+
const w = widths[i] || 3;
|
|
1429
|
+
cells.push(" ".repeat(w));
|
|
1430
|
+
}
|
|
1431
|
+
return "|" + cells.join("|") + "|";
|
|
1432
|
+
}
|
|
1433
|
+
var tableContinuationPlugin = {
|
|
1434
|
+
id: "table-continuation",
|
|
1435
|
+
deps: ["table"],
|
|
1436
|
+
install(_ctx) {
|
|
1437
|
+
const { keymap, Prec } = window.__cm6;
|
|
1438
|
+
return Prec.high(keymap.of([
|
|
1439
|
+
{
|
|
1440
|
+
key: "Enter",
|
|
1441
|
+
run(view) {
|
|
1442
|
+
const state = view.state;
|
|
1443
|
+
const { head } = state.selection.main;
|
|
1444
|
+
const line = state.doc.lineAt(head);
|
|
1445
|
+
const text = line.text;
|
|
1446
|
+
if (!isTableLine(text))
|
|
1447
|
+
return false;
|
|
1448
|
+
const tables = findTableRanges(state.doc);
|
|
1449
|
+
const table = tables.find((t) => line.number >= t.firstLine && line.number <= t.lastLine);
|
|
1450
|
+
if (!table)
|
|
1451
|
+
return false;
|
|
1452
|
+
if (isEmptyRow(text)) {
|
|
1453
|
+
view.dispatch({
|
|
1454
|
+
changes: { from: line.from, to: line.to, insert: "" },
|
|
1455
|
+
userEvent: "input.type"
|
|
1456
|
+
});
|
|
1457
|
+
return true;
|
|
1458
|
+
}
|
|
1459
|
+
const colCount = getColumnCount(state.doc, table);
|
|
1460
|
+
const widths = getCellWidths(text);
|
|
1461
|
+
const emptyRow = buildEmptyRow(colCount, widths);
|
|
1462
|
+
const insert = `
|
|
1463
|
+
` + emptyRow;
|
|
1464
|
+
view.dispatch({
|
|
1465
|
+
changes: { from: line.to, insert },
|
|
1466
|
+
selection: { anchor: line.to + insert.length },
|
|
1467
|
+
userEvent: "input.type"
|
|
1468
|
+
});
|
|
1469
|
+
requestAnimationFrame(() => {
|
|
1470
|
+
const newState = view.state;
|
|
1471
|
+
const newTables = findTableRanges(newState.doc);
|
|
1472
|
+
const cursor = newState.selection.main.head;
|
|
1473
|
+
const curLine = newState.doc.lineAt(cursor);
|
|
1474
|
+
const targetTable = newTables.find((t) => curLine.number >= t.firstLine && curLine.number <= t.lastLine);
|
|
1475
|
+
if (targetTable) {
|
|
1476
|
+
const cursorLineNum = curLine.number;
|
|
1477
|
+
const change = formatTable(newState.doc, targetTable);
|
|
1478
|
+
if (change) {
|
|
1479
|
+
view.dispatch({ changes: change });
|
|
1480
|
+
const restoredLine = view.state.doc.line(cursorLineNum);
|
|
1481
|
+
view.dispatch({
|
|
1482
|
+
selection: { anchor: restoredLine.to }
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
});
|
|
1487
|
+
return true;
|
|
1488
|
+
},
|
|
1489
|
+
preventDefault: true
|
|
1490
|
+
}
|
|
1491
|
+
]));
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
// src/plugins/theme.ts
|
|
1495
|
+
var themePlugin = {
|
|
1496
|
+
id: "theme",
|
|
1497
|
+
install(ctx) {
|
|
1498
|
+
const { EditorView } = window.__cm6;
|
|
1499
|
+
const opts = ctx.options;
|
|
1500
|
+
const editorEl = ctx.view.dom?.parentElement || ctx.view.dom;
|
|
1501
|
+
if (!editorEl.classList.contains("markdown-source-view")) {
|
|
1502
|
+
editorEl.classList.add("markdown-source-view", "mod-cm6", "is-live-preview");
|
|
1503
|
+
}
|
|
1504
|
+
if (opts.readableLineWidth) {
|
|
1505
|
+
editorEl.classList.add("is-readable-line-width");
|
|
1506
|
+
}
|
|
1507
|
+
if (opts.theme === "light") {
|
|
1508
|
+
editorEl.classList.add("theme-light");
|
|
1509
|
+
editorEl.classList.remove("theme-dark");
|
|
1510
|
+
} else {
|
|
1511
|
+
editorEl.classList.add("theme-dark");
|
|
1512
|
+
editorEl.classList.remove("theme-light");
|
|
1513
|
+
}
|
|
1514
|
+
if (opts.cssVariables) {
|
|
1515
|
+
for (const [key, value] of Object.entries(opts.cssVariables)) {
|
|
1516
|
+
const prop = key.startsWith("--") ? key : `--${key}`;
|
|
1517
|
+
editorEl.style.setProperty(prop, value);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return EditorView.contentAttributes.of({
|
|
1521
|
+
spellcheck: String(opts.spellcheck ?? false),
|
|
1522
|
+
autocorrect: "on",
|
|
1523
|
+
autocapitalize: "on",
|
|
1524
|
+
contenteditable: "true"
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
};
|
|
1528
|
+
// src/plugins/base-extensions.ts
|
|
1529
|
+
var baseExtensionsPlugin = {
|
|
1530
|
+
id: "base-extensions",
|
|
1531
|
+
install(ctx) {
|
|
1532
|
+
const { EditorState } = window.__cm6;
|
|
1533
|
+
const { editor: jB, owner: WB } = window.__stateFields;
|
|
1534
|
+
const { base: ZB } = window.__compartments;
|
|
1535
|
+
const __indentUnit = window.__indentUnit;
|
|
1536
|
+
const opts = ctx.options;
|
|
1537
|
+
const extensions = [];
|
|
1538
|
+
if (jB) {
|
|
1539
|
+
const mockEditor = ctx.getState("__mockEditor");
|
|
1540
|
+
if (mockEditor)
|
|
1541
|
+
extensions.push(jB.init(() => mockEditor));
|
|
1542
|
+
}
|
|
1543
|
+
if (WB) {
|
|
1544
|
+
const mockOwner = ctx.getState("__mockOwner");
|
|
1545
|
+
if (mockOwner)
|
|
1546
|
+
extensions.push(WB.init(() => mockOwner));
|
|
1547
|
+
}
|
|
1548
|
+
const tabSize = opts.tabSize ?? 4;
|
|
1549
|
+
const indent = opts.useTab !== false ? "\t" : " ".repeat(Math.min(Math.max(tabSize, 2), 4));
|
|
1550
|
+
extensions.push(EditorState.tabSize.of(tabSize));
|
|
1551
|
+
if (__indentUnit)
|
|
1552
|
+
extensions.push(__indentUnit.of(indent));
|
|
1553
|
+
if (window.__baseExtensions && ZB) {
|
|
1554
|
+
extensions.push(ZB.of(window.__baseExtensions));
|
|
1555
|
+
}
|
|
1556
|
+
return extensions;
|
|
1557
|
+
}
|
|
1558
|
+
};
|
|
1559
|
+
// src/plugins/keymap.ts
|
|
1560
|
+
var keymapPlugin = {
|
|
1561
|
+
id: "keymap",
|
|
1562
|
+
install(ctx) {
|
|
1563
|
+
const { keymap } = window.__cm6;
|
|
1564
|
+
const __indentMore = window.__commands?.indentMore;
|
|
1565
|
+
const __indentLess = window.__commands?.indentLess;
|
|
1566
|
+
const opts = ctx.options;
|
|
1567
|
+
return keymap.of([
|
|
1568
|
+
{
|
|
1569
|
+
key: "Tab",
|
|
1570
|
+
run(v) {
|
|
1571
|
+
if (__indentMore)
|
|
1572
|
+
return __indentMore(v);
|
|
1573
|
+
return false;
|
|
1574
|
+
},
|
|
1575
|
+
shift(v) {
|
|
1576
|
+
if (__indentLess)
|
|
1577
|
+
return __indentLess(v);
|
|
1578
|
+
return false;
|
|
1579
|
+
}
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
key: "Mod-s",
|
|
1583
|
+
run(v) {
|
|
1584
|
+
if (opts.onSave)
|
|
1585
|
+
opts.onSave(v.state.doc.toString());
|
|
1586
|
+
return true;
|
|
1587
|
+
},
|
|
1588
|
+
preventDefault: true
|
|
1589
|
+
}
|
|
1590
|
+
]);
|
|
1591
|
+
}
|
|
1592
|
+
};
|
|
1593
|
+
// src/plugins/on-change.ts
|
|
1594
|
+
var onChangePlugin = {
|
|
1595
|
+
id: "on-change",
|
|
1596
|
+
install(ctx) {
|
|
1597
|
+
const { EditorView } = window.__cm6;
|
|
1598
|
+
const opts = ctx.options;
|
|
1599
|
+
return EditorView.updateListener.of((update) => {
|
|
1600
|
+
if (update.docChanged && opts.onChange) {
|
|
1601
|
+
opts.onChange(update.state.doc.toString());
|
|
1602
|
+
}
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
// src/plugin-defaults.ts
|
|
1607
|
+
function getDefaultPlugins(opts) {
|
|
1608
|
+
const plugins = [];
|
|
1609
|
+
plugins.push(baseExtensionsPlugin);
|
|
1610
|
+
plugins.push(themePlugin);
|
|
1611
|
+
plugins.push(markdownLanguagePlugin);
|
|
1612
|
+
plugins.push(hangingIndentPlugin);
|
|
1613
|
+
plugins.push(livePreviewPlugin);
|
|
1614
|
+
plugins.push(listContinuationPlugin);
|
|
1615
|
+
plugins.push(keymapPlugin);
|
|
1616
|
+
plugins.push(expandTextPlugin);
|
|
1617
|
+
if (opts.autoPairBrackets !== false || opts.autoPairMarkdown !== false) {
|
|
1618
|
+
plugins.push(closeBracketsPlugin);
|
|
1619
|
+
}
|
|
1620
|
+
if (opts.showLineNumber !== false) {
|
|
1621
|
+
plugins.push(lineNumbersPlugin);
|
|
1622
|
+
}
|
|
1623
|
+
if (opts.showIndentGuide !== false) {
|
|
1624
|
+
plugins.push(indentGuidePlugin);
|
|
1625
|
+
}
|
|
1626
|
+
if (opts.foldHeading !== false || opts.foldIndent !== false) {
|
|
1627
|
+
plugins.push(foldPlugin);
|
|
1628
|
+
}
|
|
1629
|
+
plugins.push(suggestPlugin);
|
|
1630
|
+
plugins.push(linkHandlerPlugin);
|
|
1631
|
+
plugins.push(attachmentPlugin);
|
|
1632
|
+
plugins.push(tablePlugin);
|
|
1633
|
+
plugins.push(tableContinuationPlugin);
|
|
1634
|
+
plugins.push(onChangePlugin);
|
|
1635
|
+
return plugins;
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
// src/auto-load.ts
|
|
1639
|
+
var SCRIPT_ORDER = [
|
|
1640
|
+
"lib/i18next.min.js",
|
|
1641
|
+
"lib/codemirror.js",
|
|
1642
|
+
"lib/meta.min.js",
|
|
1643
|
+
"lib/modes.min.js",
|
|
1644
|
+
"lib/markdown.js",
|
|
1645
|
+
"lib/turndown.js",
|
|
1646
|
+
"enhance.js",
|
|
1647
|
+
"mock.js",
|
|
1648
|
+
"obsidian-app.patched.js"
|
|
1649
|
+
];
|
|
1650
|
+
var MATH_SCRIPTS = [
|
|
1651
|
+
"lib/mathjax/tex-chtml-full.js"
|
|
1652
|
+
];
|
|
1653
|
+
function autoLoad(options = {}) {
|
|
1654
|
+
const base = options.basePath || "/vendor/";
|
|
1655
|
+
const overrides = options.overrides || {};
|
|
1656
|
+
const scripts = [...SCRIPT_ORDER];
|
|
1657
|
+
if (options.math) {
|
|
1658
|
+
scripts.push(...MATH_SCRIPTS);
|
|
1659
|
+
}
|
|
1660
|
+
return scripts.reduce((promise, script) => {
|
|
1661
|
+
return promise.then(() => {
|
|
1662
|
+
return new Promise((resolve, reject) => {
|
|
1663
|
+
const src = overrides[script] || base + script;
|
|
1664
|
+
const el = document.createElement("script");
|
|
1665
|
+
el.src = src;
|
|
1666
|
+
el.onload = () => resolve();
|
|
1667
|
+
el.onerror = () => reject(new Error("Failed to load: " + src));
|
|
1668
|
+
document.head.appendChild(el);
|
|
1669
|
+
});
|
|
1670
|
+
});
|
|
1671
|
+
}, Promise.resolve());
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
// src/kernel.ts
|
|
1675
|
+
function createEditor(container, options = {}, backend = {}) {
|
|
1676
|
+
const opts = { ...defaultOptions, ...options };
|
|
1677
|
+
const be = { ...defaultBackend, ...backend };
|
|
1678
|
+
if (!window.__cm6 || !window.__cm6.EditorView) {
|
|
1679
|
+
throw new Error("xlxz-markdown-editor: Obsidian runtime not loaded. " + "Ensure vendor scripts are included before calling createEditor().");
|
|
1680
|
+
}
|
|
1681
|
+
const { EditorView, EditorState, StateEffect } = window.__cm6;
|
|
1682
|
+
const view = new EditorView({ parent: container });
|
|
1683
|
+
const mockOwner = createMockOwner(opts.filePath);
|
|
1684
|
+
const mockApp = createMockApp(be, opts);
|
|
1685
|
+
const mockEditor = createMockEditor(mockApp, mockOwner, view, container);
|
|
1686
|
+
const pluginStates = new Map;
|
|
1687
|
+
const activePlugins = new Map;
|
|
1688
|
+
pluginStates.set("__mockEditor", mockEditor);
|
|
1689
|
+
pluginStates.set("__mockOwner", mockOwner);
|
|
1690
|
+
function makeContext() {
|
|
1691
|
+
return {
|
|
1692
|
+
view,
|
|
1693
|
+
options: opts,
|
|
1694
|
+
backend: be,
|
|
1695
|
+
getState(pluginId) {
|
|
1696
|
+
return pluginStates.get(pluginId);
|
|
1697
|
+
},
|
|
1698
|
+
setState(pluginId, state) {
|
|
1699
|
+
pluginStates.set(pluginId, state);
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
function use(plugin) {
|
|
1704
|
+
if (activePlugins.has(plugin.id)) {
|
|
1705
|
+
console.warn(`Plugin "${plugin.id}" is already registered.`);
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (plugin.deps) {
|
|
1709
|
+
for (const dep of plugin.deps) {
|
|
1710
|
+
if (!activePlugins.has(dep)) {
|
|
1711
|
+
console.warn(`Plugin "${plugin.id}" depends on "${dep}" which is not registered.`);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
const ctx = makeContext();
|
|
1716
|
+
const ext = plugin.install(ctx);
|
|
1717
|
+
if (ext) {
|
|
1718
|
+
const exts = Array.isArray(ext) ? ext : [ext];
|
|
1719
|
+
if (exts.length > 0) {
|
|
1720
|
+
view.dispatch({ effects: StateEffect.appendConfig.of(exts) });
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
activePlugins.set(plugin.id, plugin);
|
|
1724
|
+
}
|
|
1725
|
+
function unuse(pluginId) {
|
|
1726
|
+
const plugin = activePlugins.get(pluginId);
|
|
1727
|
+
if (!plugin)
|
|
1728
|
+
return;
|
|
1729
|
+
if (plugin.uninstall) {
|
|
1730
|
+
plugin.uninstall(makeContext());
|
|
1731
|
+
}
|
|
1732
|
+
activePlugins.delete(pluginId);
|
|
1733
|
+
pluginStates.delete(pluginId);
|
|
1734
|
+
}
|
|
1735
|
+
const defaultPlugins = getDefaultPlugins(opts);
|
|
1736
|
+
const initialExtensions = [];
|
|
1737
|
+
for (const plugin of defaultPlugins) {
|
|
1738
|
+
if (activePlugins.has(plugin.id))
|
|
1739
|
+
continue;
|
|
1740
|
+
const ctx = makeContext();
|
|
1741
|
+
const ext = plugin.install(ctx);
|
|
1742
|
+
if (ext) {
|
|
1743
|
+
const exts = Array.isArray(ext) ? ext : [ext];
|
|
1744
|
+
initialExtensions.push(...exts);
|
|
1745
|
+
}
|
|
1746
|
+
activePlugins.set(plugin.id, plugin);
|
|
1747
|
+
}
|
|
1748
|
+
const fullState = EditorState.create({
|
|
1749
|
+
doc: opts.doc || "",
|
|
1750
|
+
extensions: initialExtensions
|
|
1751
|
+
});
|
|
1752
|
+
view.setState(fullState);
|
|
1753
|
+
(function forceRebuild() {
|
|
1754
|
+
const { syntaxTree, Transaction } = window.__cm6;
|
|
1755
|
+
view.dispatch({ annotations: Transaction.addToHistory.of(false) });
|
|
1756
|
+
const tree = syntaxTree(view.state);
|
|
1757
|
+
if (tree.length < view.state.doc.length) {
|
|
1758
|
+
setTimeout(forceRebuild, 50);
|
|
1759
|
+
}
|
|
1760
|
+
})();
|
|
1761
|
+
function registerSuggest(config) {
|
|
1762
|
+
const suggestState = pluginStates.get("suggest");
|
|
1763
|
+
if (!suggestState) {
|
|
1764
|
+
console.warn("registerSuggest: suggest plugin not installed. Call editor.use(suggestPlugin) first.");
|
|
1765
|
+
return () => {};
|
|
1766
|
+
}
|
|
1767
|
+
const provider = {
|
|
1768
|
+
id: `suggest-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
1769
|
+
trigger: config.trigger,
|
|
1770
|
+
getSuggestions: config.getSuggestions,
|
|
1771
|
+
onAccept: config.onAccept,
|
|
1772
|
+
suffix: config.suffix
|
|
1773
|
+
};
|
|
1774
|
+
return suggestState.addProvider(provider);
|
|
1775
|
+
}
|
|
1776
|
+
const instance = {
|
|
1777
|
+
view,
|
|
1778
|
+
getDoc() {
|
|
1779
|
+
return view.state.doc.toString();
|
|
1780
|
+
},
|
|
1781
|
+
setDoc(content) {
|
|
1782
|
+
view.dispatch({
|
|
1783
|
+
changes: { from: 0, to: view.state.doc.length, insert: content }
|
|
1784
|
+
});
|
|
1785
|
+
},
|
|
1786
|
+
getSelection() {
|
|
1787
|
+
const { from, to } = view.state.selection.main;
|
|
1788
|
+
return view.state.doc.sliceString(from, to);
|
|
1789
|
+
},
|
|
1790
|
+
destroy() {
|
|
1791
|
+
const ids = [...activePlugins.keys()].reverse();
|
|
1792
|
+
for (const id of ids)
|
|
1793
|
+
unuse(id);
|
|
1794
|
+
view.destroy();
|
|
1795
|
+
container.innerHTML = "";
|
|
1796
|
+
pluginStates.clear();
|
|
1797
|
+
},
|
|
1798
|
+
focus() {
|
|
1799
|
+
view.focus();
|
|
1800
|
+
},
|
|
1801
|
+
use,
|
|
1802
|
+
unuse,
|
|
1803
|
+
registerSuggest
|
|
1804
|
+
};
|
|
1805
|
+
return instance;
|
|
1806
|
+
}
|