@pfmcodes/caret 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +441 -386
- package/components/caret.js +95 -0
- package/components/font.js +16 -0
- package/components/lineCounter.js +91 -0
- package/components/textEditor.js +411 -0
- package/index.js +4 -19
- package/package.json +1 -1
- package/utilities.js +36 -0
- package/editor.js +0 -470
- package/index.css +0 -110
- package/theme.js +0 -14
- package/types/editor.ts +0 -481
- package/types/index.d.ts +0 -46
- package/types/index.ts +0 -22
- package/types/langauges.ts +0 -116
- package/types/theme.ts +0 -14
- /package/{langauges.js → components/languages.js} +0 -0
package/types/editor.ts
DELETED
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import hljs from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/core.js"; // Use default export
|
|
3
|
-
import languages from "./langauges.ts";
|
|
4
|
-
|
|
5
|
-
languages.init();
|
|
6
|
-
|
|
7
|
-
async function createEditor(editor: HTMLElement, data: any) {
|
|
8
|
-
const editor1 = document.createElement("textarea");
|
|
9
|
-
const highlighted = document.createElement("pre");
|
|
10
|
-
const caret = document.createElement("div");
|
|
11
|
-
const measureCanvas = document.createElement("canvas");
|
|
12
|
-
const measureCtx: any = measureCanvas.getContext("2d");
|
|
13
|
-
const isDark = data.theme && (data.theme.includes("dark") || data.theme.includes("night"));
|
|
14
|
-
const caretColor = isDark ? "#fff" : "#7116d8";
|
|
15
|
-
const lineColor = isDark ? "#fff" : "#000";
|
|
16
|
-
const lineCounter = document.createElement("div");
|
|
17
|
-
|
|
18
|
-
const i = Math.random().toString(16).slice(2);
|
|
19
|
-
editor1.id = `Caret-textarea-${i}`;
|
|
20
|
-
highlighted.id = `Caret-highlighted-${i}`;
|
|
21
|
-
caret.id = `Caret-caret-${i}`;
|
|
22
|
-
lineCounter.id = `Caret-lineCounter-${i}`;
|
|
23
|
-
editor1.classList.add("Caret-textarea");
|
|
24
|
-
highlighted.classList.add("Caret-highlighted");
|
|
25
|
-
caret.classList.add("Caret-caret");
|
|
26
|
-
lineCounter.classList.add("Caret-lineCounter");
|
|
27
|
-
editor1.classList.add("dark");
|
|
28
|
-
highlighted.classList.add("dark");
|
|
29
|
-
caret.classList.add("dark");
|
|
30
|
-
lineCounter.classList.add("dark");
|
|
31
|
-
editor1.style.backgroundColor = isDark ? "#222" : "#fff";
|
|
32
|
-
let code = data.value || "";
|
|
33
|
-
let language = data.language;
|
|
34
|
-
let theme = data.theme;
|
|
35
|
-
let lock = data.readOnly || false;
|
|
36
|
-
if (lock) {
|
|
37
|
-
editor1.readOnly = true;
|
|
38
|
-
}
|
|
39
|
-
if (!languages.registeredLanguages.includes(language)) {
|
|
40
|
-
const mod = await import(`https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/${language}.js`);
|
|
41
|
-
languages.registerLanguage(language, mod.default);
|
|
42
|
-
languages.registeredLanguages.push(language);
|
|
43
|
-
}
|
|
44
|
-
if (theme) {
|
|
45
|
-
let themeLink = document.getElementById("Caret-theme")
|
|
46
|
-
if (!themeLink) {
|
|
47
|
-
const link = document.createElement("link");
|
|
48
|
-
link.rel = "stylesheet";
|
|
49
|
-
link.id = "Caret-theme";
|
|
50
|
-
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
51
|
-
document.head.appendChild(link);
|
|
52
|
-
} else {
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
themeLink.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/${theme}.css`;
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
let themeLink = document.getElementById("Caret-theme");
|
|
58
|
-
if (!themeLink) {
|
|
59
|
-
const link = document.createElement("link");
|
|
60
|
-
link.rel = "stylesheet";
|
|
61
|
-
link.id = "Caret-theme";
|
|
62
|
-
link.href = `https://esm.sh/@pfmcodes/highlight.js@1.0.0/styles/hybrid.css`;
|
|
63
|
-
document.head.appendChild(link);
|
|
64
|
-
} else {
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
themeLink.href = `./highlight.js/styles/hybrid.css`;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
editor1.spellcheck = false;
|
|
70
|
-
(editor1 as any).autocapitalize = "off";
|
|
71
|
-
(editor1 as any).autocomplete = "off";
|
|
72
|
-
(editor1 as any).autocorrect = false;
|
|
73
|
-
editor.style = "position: relative; width: 600px; height: 300px; overflow: hidden; /* 👈 CRITICAL */ font-size: 14px;"
|
|
74
|
-
if (code && editor && editor1 && language && highlighted) {
|
|
75
|
-
editor1.style.paddingTop = "-9px";
|
|
76
|
-
editor1.value = data.value;
|
|
77
|
-
highlighted.innerHTML = await _render(data.value, language, editor1);
|
|
78
|
-
}
|
|
79
|
-
const keyDown = async (e: any) => {
|
|
80
|
-
if (e.key !== "Tab") return;
|
|
81
|
-
|
|
82
|
-
e.preventDefault();
|
|
83
|
-
|
|
84
|
-
const value = editor1.value;
|
|
85
|
-
const start = editor1.selectionStart;
|
|
86
|
-
const end = editor1.selectionEnd;
|
|
87
|
-
|
|
88
|
-
const indent = " ";
|
|
89
|
-
|
|
90
|
-
// Find line start & end
|
|
91
|
-
const lineStart = value.lastIndexOf("\n", start - 1) + 1;
|
|
92
|
-
const lineEnd = value.indexOf("\n", end);
|
|
93
|
-
const finalLineEnd = lineEnd === -1 ? value.length : lineEnd;
|
|
94
|
-
|
|
95
|
-
const block = value.slice(lineStart, finalLineEnd);
|
|
96
|
-
const lines = block.split("\n");
|
|
97
|
-
|
|
98
|
-
let newLines;
|
|
99
|
-
let delta = 0;
|
|
100
|
-
|
|
101
|
-
if (e.shiftKey) {
|
|
102
|
-
// UNINDENT
|
|
103
|
-
newLines = lines.map(line => {
|
|
104
|
-
if (line.startsWith(indent)) {
|
|
105
|
-
delta -= indent.length;
|
|
106
|
-
return line.slice(indent.length);
|
|
107
|
-
}
|
|
108
|
-
if (line.startsWith("\t")) {
|
|
109
|
-
delta -= 1;
|
|
110
|
-
return line.slice(1);
|
|
111
|
-
}
|
|
112
|
-
return line;
|
|
113
|
-
});
|
|
114
|
-
} else {
|
|
115
|
-
// INDENT
|
|
116
|
-
newLines = lines.map(line => indent + line);
|
|
117
|
-
delta = indent.length;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const newBlock = newLines.join("\n");
|
|
121
|
-
|
|
122
|
-
editor1.value =
|
|
123
|
-
value.slice(0, lineStart) +
|
|
124
|
-
newBlock +
|
|
125
|
-
value.slice(finalLineEnd);
|
|
126
|
-
|
|
127
|
-
// Fix selection
|
|
128
|
-
editor1.selectionStart = start + delta;
|
|
129
|
-
editor1.selectionEnd =
|
|
130
|
-
end + delta * newLines.length;
|
|
131
|
-
|
|
132
|
-
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
133
|
-
updateLineNumbers();
|
|
134
|
-
updateCaret();
|
|
135
|
-
}
|
|
136
|
-
editor1.addEventListener("keydown", keyDown);
|
|
137
|
-
editor.appendChild(lineCounter);
|
|
138
|
-
editor.appendChild(highlighted);
|
|
139
|
-
editor.appendChild(editor1);
|
|
140
|
-
editor.appendChild(caret);
|
|
141
|
-
|
|
142
|
-
function updateFontMetrics() {
|
|
143
|
-
const style = getComputedStyle(editor1);
|
|
144
|
-
measureCtx.font = `${style.fontSize} ${style.fontFamily}`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function updateLineNumbers() {
|
|
148
|
-
const lines = editor1.value.split("\n");
|
|
149
|
-
const wrapMap = getWrapMap(editor1.value, 71);
|
|
150
|
-
|
|
151
|
-
let html = "";
|
|
152
|
-
lines.forEach((line, i) => {
|
|
153
|
-
const visualLines = wrapMap[i] || 1;
|
|
154
|
-
// first visual line gets the number
|
|
155
|
-
html += `<div class="Caret-lineCounter-number" style="color: ${lineColor}; height: calc(1.5em * ${visualLines})">${i + 1}</div>`;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
lineCounter.innerHTML = html;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
highlighted.style.paddingTop = "12px"
|
|
162
|
-
|
|
163
|
-
function getFontMetrics() {
|
|
164
|
-
const metrics = measureCtx.measureText("Mg");
|
|
165
|
-
return {
|
|
166
|
-
ascent: metrics.actualBoundingBoxAscent,
|
|
167
|
-
descent: metrics.actualBoundingBoxDescent,
|
|
168
|
-
height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
const focus = () => {
|
|
172
|
-
caret.style.opacity = "1";
|
|
173
|
-
caret.style.background = caretColor;
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
editor1.addEventListener("focus", focus);
|
|
177
|
-
|
|
178
|
-
const blur = () => {
|
|
179
|
-
caret.style.opacity = "0";
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
editor1.addEventListener("blur", blur);
|
|
183
|
-
|
|
184
|
-
function getVisualRow(text: string, wrapAt: number) {
|
|
185
|
-
// simulate exactly what wrapCode does, but track caret position
|
|
186
|
-
const words = text.split(" ");
|
|
187
|
-
let currentLine = "";
|
|
188
|
-
let visualRow = 0;
|
|
189
|
-
|
|
190
|
-
for (let w = 0; w < words.length; w++) {
|
|
191
|
-
const word = words[w];
|
|
192
|
-
const isLast = w === words.length - 1;
|
|
193
|
-
const test = currentLine ? currentLine + " " + word : word;
|
|
194
|
-
|
|
195
|
-
if (test.length > wrapAt && currentLine !== "") {
|
|
196
|
-
visualRow++;
|
|
197
|
-
currentLine = word;
|
|
198
|
-
} else {
|
|
199
|
-
currentLine = test;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return { row: visualRow, lineText: currentLine };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function updateCaret() {
|
|
207
|
-
const start = editor1.selectionStart;
|
|
208
|
-
const text = editor1.value.slice(0, start);
|
|
209
|
-
|
|
210
|
-
const lines = text.split("\n");
|
|
211
|
-
const lineIndex = lines.length - 1;
|
|
212
|
-
const currentLineText = lines[lineIndex].replace(/\t/g, " ");
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const style = getComputedStyle(editor1);
|
|
216
|
-
const paddingLeft = parseFloat(style.paddingLeft);
|
|
217
|
-
const paddingTop = parseFloat(style.paddingTop);
|
|
218
|
-
const lineHeight = parseFloat(style.lineHeight) || 20;
|
|
219
|
-
|
|
220
|
-
updateFontMetrics();
|
|
221
|
-
const ascent = measureCtx.measureText("Mg").actualBoundingBoxAscent;
|
|
222
|
-
|
|
223
|
-
const WRAP_AT = 71;
|
|
224
|
-
|
|
225
|
-
// count visual rows from all previous lines
|
|
226
|
-
let totalVisualRows = 0;
|
|
227
|
-
for (let i = 0; i < lineIndex; i++) {
|
|
228
|
-
const l = lines[i].replace(/\t/g, " ");
|
|
229
|
-
const { row } = getVisualRow(l, WRAP_AT);
|
|
230
|
-
totalVisualRows += row + 1;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const { row, lineText } = getVisualRow(currentLineText, WRAP_AT);
|
|
234
|
-
const onWrappedLine = row > 0;
|
|
235
|
-
|
|
236
|
-
totalVisualRows += row;
|
|
237
|
-
|
|
238
|
-
if (onWrappedLine) {
|
|
239
|
-
// on wrapped line - X is just the text on this visual row
|
|
240
|
-
|
|
241
|
-
caret.style.left = paddingLeft + measureCtx.measureText(lineText).width + "px";
|
|
242
|
-
} else {
|
|
243
|
-
// on original line - X is full line text width
|
|
244
|
-
|
|
245
|
-
caret.style.left = paddingLeft + measureCtx.measureText(lineText.trimEnd()).width + "px";
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
caret.style.top = -9 + paddingTop + totalVisualRows * lineHeight + (lineHeight - ascent) + "px";
|
|
249
|
-
caret.style.height = `${lineHeight - 5}px`;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const input = async () => {
|
|
253
|
-
caret.style.opacity = "1";
|
|
254
|
-
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
255
|
-
updateLineNumbers();
|
|
256
|
-
updateCaret();
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
const onDidChangeModelContent = (fn: any) => {
|
|
260
|
-
editor1.addEventListener("input", fn)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
editor1.addEventListener("input", input);
|
|
264
|
-
const scroll = async () => {
|
|
265
|
-
const x = -editor1.scrollLeft;
|
|
266
|
-
const y = -editor1.scrollTop;
|
|
267
|
-
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
268
|
-
highlighted.style.transform = `translateY(${y}px)`;
|
|
269
|
-
caret.style.transform = `translateY(${y}px)`;
|
|
270
|
-
lineCounter.style.transform = `translateY(${y}px)`;
|
|
271
|
-
};
|
|
272
|
-
editor1.addEventListener("scroll", scroll);
|
|
273
|
-
|
|
274
|
-
updateFontMetrics();
|
|
275
|
-
getFontMetrics();
|
|
276
|
-
|
|
277
|
-
editor1.addEventListener("click", updateCaret);
|
|
278
|
-
editor1.addEventListener("keyup", updateCaret);
|
|
279
|
-
|
|
280
|
-
// Initial caret position
|
|
281
|
-
updateLineNumbers();
|
|
282
|
-
updateCaret();
|
|
283
|
-
|
|
284
|
-
// Focus the editor
|
|
285
|
-
editor1.focus();
|
|
286
|
-
function destroy() {
|
|
287
|
-
editor1.removeEventListener('click', updateCaret);
|
|
288
|
-
editor1.removeEventListener('keyup', updateCaret);
|
|
289
|
-
editor1.removeEventListener('scroll', scroll);
|
|
290
|
-
editor1.removeEventListener('keydown', keyDown);
|
|
291
|
-
editor.innerHTML = "";
|
|
292
|
-
}
|
|
293
|
-
async function refresh() {
|
|
294
|
-
highlighted.innerHTML = await _render(editor1.value, language, editor1);
|
|
295
|
-
updateLineNumbers();
|
|
296
|
-
updateCaret();
|
|
297
|
-
}
|
|
298
|
-
function getValue() {
|
|
299
|
-
return editor1.value;
|
|
300
|
-
}
|
|
301
|
-
function setValue(i: string) {
|
|
302
|
-
editor1.value = i;
|
|
303
|
-
refresh();
|
|
304
|
-
}
|
|
305
|
-
async function setLanguage(l: string) {
|
|
306
|
-
if (!languages.registeredLanguages.includes(l)) {
|
|
307
|
-
if (l === "html" || l === "svg") {
|
|
308
|
-
language = "xml";
|
|
309
|
-
l = "xml";
|
|
310
|
-
}
|
|
311
|
-
const mod = await import(`https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/${l}.js`);
|
|
312
|
-
languages.registerLanguage(l, mod)
|
|
313
|
-
}
|
|
314
|
-
language = l;
|
|
315
|
-
refresh();
|
|
316
|
-
}
|
|
317
|
-
return {
|
|
318
|
-
getValue,
|
|
319
|
-
setValue,
|
|
320
|
-
focus,
|
|
321
|
-
setLanguage,
|
|
322
|
-
destroy,
|
|
323
|
-
onDidChangeModelContent,
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function wrapCode(code: string, wrapAt = 71) {
|
|
328
|
-
return code.split("\n").map(line => {
|
|
329
|
-
if (line.length <= wrapAt) return line;
|
|
330
|
-
|
|
331
|
-
const indent = line.match(/^(\s*)/)?.at(1) ?? "";
|
|
332
|
-
const words = line.trimStart().split(" ");
|
|
333
|
-
const wrappedLines = [];
|
|
334
|
-
let currentLine = indent; // first line keeps indent
|
|
335
|
-
let isFirstLine = true;
|
|
336
|
-
|
|
337
|
-
for (const word of words) {
|
|
338
|
-
if (word.length > wrapAt) {
|
|
339
|
-
if (currentLine.trim()) {
|
|
340
|
-
wrappedLines.push(currentLine);
|
|
341
|
-
currentLine = "";
|
|
342
|
-
isFirstLine = false;
|
|
343
|
-
}
|
|
344
|
-
for (let i = 0; i < word.length; i += wrapAt) {
|
|
345
|
-
wrappedLines.push(word.slice(i, i + wrapAt));
|
|
346
|
-
}
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
const test = currentLine ? currentLine + " " + word : word;
|
|
351
|
-
if (test.length > wrapAt) {
|
|
352
|
-
wrappedLines.push(currentLine);
|
|
353
|
-
currentLine = word; // no indent on continuation lines
|
|
354
|
-
isFirstLine = false;
|
|
355
|
-
} else {
|
|
356
|
-
currentLine = test;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (currentLine) wrappedLines.push(currentLine);
|
|
361
|
-
return wrappedLines.join("\n");
|
|
362
|
-
}).join("\n");
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function getWrapMap(code: string, wrapAt = 71) {
|
|
366
|
-
const wrapMap: any = []; // wrapMap[originalLineIndex] = number of visual lines it produces
|
|
367
|
-
|
|
368
|
-
code.split("\n").forEach((line, i) => {
|
|
369
|
-
if (line.length <= wrapAt) {
|
|
370
|
-
wrapMap[i] = 1; // no wrap, 1 visual line
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const indent = line.match(/^(\s*)/)?.at(1) ?? "";
|
|
375
|
-
const words = line.trimStart().split(" ");
|
|
376
|
-
let currentLine = indent;
|
|
377
|
-
let visualLines = 1;
|
|
378
|
-
|
|
379
|
-
for (const word of words) {
|
|
380
|
-
if (word.length > wrapAt) {
|
|
381
|
-
if (currentLine.trim()) {
|
|
382
|
-
visualLines++;
|
|
383
|
-
currentLine = "";
|
|
384
|
-
}
|
|
385
|
-
visualLines += Math.floor(word.length / wrapAt);
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const test = currentLine ? currentLine + " " + word : word;
|
|
390
|
-
if (test.length > wrapAt) {
|
|
391
|
-
visualLines++;
|
|
392
|
-
currentLine = word;
|
|
393
|
-
} else {
|
|
394
|
-
currentLine = test;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
wrapMap[i] = visualLines;
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
return wrapMap;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function escapeHtml(str: string) {
|
|
405
|
-
return str
|
|
406
|
-
.replace(/&/g, "&")
|
|
407
|
-
.replace(/</g, "<")
|
|
408
|
-
.replace(/>/g, ">");
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
async function _render(code: string, language: any, editor: HTMLElement) {
|
|
412
|
-
// If no editor context provided, just highlight everything (initial load)
|
|
413
|
-
if (!editor) {
|
|
414
|
-
return hljs.highlight(code, { language }).value;
|
|
415
|
-
}
|
|
416
|
-
const scrollTop = editor.scrollTop;
|
|
417
|
-
const scrollBottom = scrollTop + editor.clientHeight;
|
|
418
|
-
const style = getComputedStyle(editor);
|
|
419
|
-
const lineHeight = parseFloat(style.lineHeight);
|
|
420
|
-
|
|
421
|
-
// Calculate visible line range
|
|
422
|
-
const startLine = Math.floor(scrollTop / lineHeight);
|
|
423
|
-
const endLine = Math.ceil(scrollBottom / lineHeight);
|
|
424
|
-
|
|
425
|
-
const lines = code.split("\n");
|
|
426
|
-
|
|
427
|
-
// Add buffer (render extra lines above/below for smooth scrolling)
|
|
428
|
-
const bufferLines = 10;
|
|
429
|
-
const visibleStart = Math.max(0, startLine - bufferLines) || 0;
|
|
430
|
-
const visibleEnd = Math.min(lines.length, endLine + bufferLines) || 0;
|
|
431
|
-
|
|
432
|
-
// Split into three sections
|
|
433
|
-
const beforeLines = lines.slice(0, visibleStart);
|
|
434
|
-
const visibleLines: any = lines.slice(visibleStart, visibleEnd);
|
|
435
|
-
const afterLines = lines.slice(visibleEnd);
|
|
436
|
-
|
|
437
|
-
// Only highlight visible portion
|
|
438
|
-
let wrappedCode;
|
|
439
|
-
if (visibleLines.length === 0) {
|
|
440
|
-
wrappedCode = wrapCode(code, 68);
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
wrappedCode = wrapCode(visibleLines.join("\n"), 71)
|
|
444
|
-
}
|
|
445
|
-
const highlightedVisible = hljs.highlight(wrappedCode, { language }).value;
|
|
446
|
-
// Plain text for non-visible areas (no highlighting = faster)
|
|
447
|
-
if (highlightedVisible.trim() === "") {
|
|
448
|
-
return hljs.highlight(escapeHtml(code), { language }).value;
|
|
449
|
-
}
|
|
450
|
-
const beforeHTML = "\n".repeat(beforeLines.length);
|
|
451
|
-
const afterHTML = "\n".repeat(afterLines.length);
|
|
452
|
-
return beforeHTML + highlightedVisible + afterHTML;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
const editor = {
|
|
456
|
-
createEditor
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
export default editor;
|
|
460
|
-
|
|
461
|
-
/*
|
|
462
|
-
createEditor(editor, data): creates the main editor using HTML elements like textarea, pre, div etc.
|
|
463
|
-
Returns an object with the following methods:
|
|
464
|
-
getValue() -> returns the current value from the editor
|
|
465
|
-
setValue(val) -> sets a value to the editor
|
|
466
|
-
focus() -> focuses the editor
|
|
467
|
-
setLanguage(lang) -> changes the syntax highlighting language
|
|
468
|
-
destroy() -> destroys the editor and removes all event listeners
|
|
469
|
-
onDidChangeModelContent(fn) -> fires a callback whenever the editor content changes
|
|
470
|
-
|
|
471
|
-
Internal functions:
|
|
472
|
-
_render(code, language, editor) -> virtual renderer, only highlights visible lines for performance
|
|
473
|
-
wrapCode(code, wrapAt) -> wraps long lines at word boundaries
|
|
474
|
-
getWrapMap(code, wrapAt) -> returns an array mapping each line to its visual line count
|
|
475
|
-
escapeHtml(str) -> escapes HTML special characters
|
|
476
|
-
updateCaret() -> updates the caret position using canvas font metrics
|
|
477
|
-
updateLineNumbers() -> re-renders line numbers, accounting for wrapped lines
|
|
478
|
-
updateFontMetrics() -> updates the canvas font to match the textarea's computed style
|
|
479
|
-
getFontMetrics() -> returns ascent, descent and height of the current font
|
|
480
|
-
getVisualRow(text, wrapAt) -> returns which visual row and remaining text the caret is on
|
|
481
|
-
*/
|
package/types/index.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
declare module "@pfmcodes/caret" {
|
|
2
|
-
interface CaretEditorAPI {
|
|
3
|
-
createEditor(
|
|
4
|
-
el: HTMLElement,
|
|
5
|
-
data: any
|
|
6
|
-
): Promise<{
|
|
7
|
-
getValue(): string;
|
|
8
|
-
setValue(v: string): void;
|
|
9
|
-
focus(): void;
|
|
10
|
-
setLanguage(l: string): Promise<void>;
|
|
11
|
-
destroy(): void;
|
|
12
|
-
}>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface CaretThemeApi {
|
|
16
|
-
setTheme(name: string): void;
|
|
17
|
-
removeTheme(name: string): void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
interface CaretLanguageApi {
|
|
21
|
-
registeredLanguages: string[];
|
|
22
|
-
init(): void;
|
|
23
|
-
registerLanguage(name: string, definition: any): void;
|
|
24
|
-
hljs: any;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const Caret: {
|
|
28
|
-
editor: CaretEditorAPI;
|
|
29
|
-
theme: CaretThemeApi;
|
|
30
|
-
language: CaretLanguageApi;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export default Caret;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
Caret.editor:
|
|
38
|
-
createEditor() -> backbone of caret, handles ui and abstractions
|
|
39
|
-
Caret.theme:
|
|
40
|
-
setTheme() -> changes the current highlight.js theme
|
|
41
|
-
Caret.langauge:
|
|
42
|
-
init() -> initializes default avaible languages
|
|
43
|
-
registerLanguage() -> registers a new languages
|
|
44
|
-
registeredLangauges[List]: has all the langauges registered
|
|
45
|
-
hljs: the highlight.js module
|
|
46
|
-
*/
|
package/types/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import editor from "./editor.ts";
|
|
2
|
-
import theme from "./theme.ts";
|
|
3
|
-
import language from "./langauges.ts";
|
|
4
|
-
|
|
5
|
-
const Caret = {
|
|
6
|
-
editor,
|
|
7
|
-
theme,
|
|
8
|
-
language
|
|
9
|
-
}
|
|
10
|
-
export default Caret;
|
|
11
|
-
|
|
12
|
-
/*
|
|
13
|
-
Caret.editor:
|
|
14
|
-
createEditor() -> backbone of caret, handles ui and abstractions
|
|
15
|
-
Caret.theme:
|
|
16
|
-
setTheme() -> changes the current highlight.js theme
|
|
17
|
-
Caret.langauge:
|
|
18
|
-
init() -> initializes default avaible languages
|
|
19
|
-
registerLanguage() -> registers a new languages
|
|
20
|
-
registeredLangauges[List]: has all the langauges registered
|
|
21
|
-
hljs: the highlight.js module
|
|
22
|
-
*/
|
package/types/langauges.ts
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// @ts-ignore
|
|
2
|
-
import javascript from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/javascript.js";
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
import xml from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/xml.js";
|
|
5
|
-
// @ts-ignore
|
|
6
|
-
import css from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/css.js";
|
|
7
|
-
// @ts-ignore
|
|
8
|
-
import python from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/python.js";
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
import java from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/java.js";
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
import csharp from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/csharp.js";
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
import cpp from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/cpp.js";
|
|
15
|
-
// @ts-ignore
|
|
16
|
-
import ruby from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/ruby.js";
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
import php from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/php.js";
|
|
19
|
-
// @ts-ignore
|
|
20
|
-
import go from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/go.js";
|
|
21
|
-
// @ts-ignore
|
|
22
|
-
import c from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/c.js";
|
|
23
|
-
// @ts-ignore
|
|
24
|
-
import rust from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/rust.js";
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
import kotlin from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/kotlin.js";
|
|
27
|
-
// @ts-ignore
|
|
28
|
-
import swift from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/swift.js";
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
import typescript from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/typescript.js";
|
|
31
|
-
// @ts-ignore
|
|
32
|
-
import json from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/json.js";
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
import bash from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/bash.js";
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
import plaintext from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/languages/plaintext.js";
|
|
37
|
-
// @ts-ignore
|
|
38
|
-
import hljs from "https://esm.sh/@pfmcodes/highlight.js@1.0.0/es/core.js";
|
|
39
|
-
|
|
40
|
-
let registeredLanguages: Array<any> = [];
|
|
41
|
-
|
|
42
|
-
function init() {
|
|
43
|
-
// Register all languages
|
|
44
|
-
hljs.registerLanguage("javascript", javascript);
|
|
45
|
-
hljs.registerLanguage("xml", xml);
|
|
46
|
-
hljs.registerLanguage("css", css);
|
|
47
|
-
hljs.registerLanguage("html", xml);
|
|
48
|
-
hljs.registerLanguage("python", python);
|
|
49
|
-
hljs.registerLanguage("java", java);
|
|
50
|
-
hljs.registerLanguage("csharp", csharp);
|
|
51
|
-
hljs.registerLanguage("cpp", cpp);
|
|
52
|
-
hljs.registerLanguage("ruby", ruby);
|
|
53
|
-
hljs.registerLanguage("php", php);
|
|
54
|
-
hljs.registerLanguage("go", go);
|
|
55
|
-
hljs.registerLanguage("c", c);
|
|
56
|
-
hljs.registerLanguage("rust", rust);
|
|
57
|
-
hljs.registerLanguage("kotlin", kotlin);
|
|
58
|
-
hljs.registerLanguage("swift", swift);
|
|
59
|
-
hljs.registerLanguage("typescript", typescript);
|
|
60
|
-
hljs.registerLanguage("json", json);
|
|
61
|
-
hljs.registerLanguage("bash", bash);
|
|
62
|
-
hljs.registerLanguage("shell", bash);
|
|
63
|
-
hljs.registerLanguage("sh", bash);
|
|
64
|
-
hljs.registerLanguage("plaintext", plaintext);
|
|
65
|
-
registeredLanguages = [
|
|
66
|
-
"javascript",
|
|
67
|
-
"js",
|
|
68
|
-
"xml",
|
|
69
|
-
"html",
|
|
70
|
-
"svg",
|
|
71
|
-
"python",
|
|
72
|
-
"java",
|
|
73
|
-
"csharp",
|
|
74
|
-
"cpp",
|
|
75
|
-
"ruby",
|
|
76
|
-
"php",
|
|
77
|
-
"go",
|
|
78
|
-
"c",
|
|
79
|
-
"rust",
|
|
80
|
-
"kotlin",
|
|
81
|
-
"swift",
|
|
82
|
-
"typescript",
|
|
83
|
-
"json",
|
|
84
|
-
"bash",
|
|
85
|
-
"shell",
|
|
86
|
-
"sh",
|
|
87
|
-
"plaintext"
|
|
88
|
-
]
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function registerAliases(a: any, b: any) {
|
|
92
|
-
hljs.registerAliases(a, b)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function registerLanguage(name: string, definition: any) {
|
|
96
|
-
hljs.registerLanguage(name, definition);
|
|
97
|
-
if (!registeredLanguages.includes(name)) {
|
|
98
|
-
registeredLanguages.push(name);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const languages = {
|
|
103
|
-
init,
|
|
104
|
-
registeredLanguages,
|
|
105
|
-
registerLanguage,
|
|
106
|
-
hljs
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export default languages;
|
|
110
|
-
|
|
111
|
-
/*
|
|
112
|
-
registeredLannguage: added for the editor.js can check if the langauge provided already is regsitered or not
|
|
113
|
-
init: just registers some languages and updates the registeredLangauges variable
|
|
114
|
-
registerLanguage: just registers a language
|
|
115
|
-
registerAliases: basically registers a nickname or second name for an language
|
|
116
|
-
*/
|
package/types/theme.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
function setTheme(name: string) {
|
|
2
|
-
const link = document.getElementById("Caret-theme") as HTMLLinkElement;
|
|
3
|
-
link.href = `./highlight.js/styles/${name}.css`;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const theme = {
|
|
7
|
-
setTheme
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default theme;
|
|
11
|
-
|
|
12
|
-
/*
|
|
13
|
-
setTheme() -> changes the current highlight.js theme
|
|
14
|
-
*/
|
|
File without changes
|