overtype 1.2.2 → 1.2.3
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 +9 -4
- package/dist/overtype.cjs +243 -1
- package/dist/overtype.cjs.map +2 -2
- package/dist/overtype.esm.js +243 -1
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +243 -1
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +56 -49
- package/package.json +1 -1
- package/src/overtype.js +145 -1
- package/src/parser.js +162 -0
package/dist/overtype.js
CHANGED
|
@@ -397,9 +397,147 @@ var OverType = (() => {
|
|
|
397
397
|
});
|
|
398
398
|
return processed;
|
|
399
399
|
}
|
|
400
|
+
/**
|
|
401
|
+
* Get list context at cursor position
|
|
402
|
+
* @param {string} text - Full text content
|
|
403
|
+
* @param {number} cursorPosition - Current cursor position
|
|
404
|
+
* @returns {Object} List context information
|
|
405
|
+
*/
|
|
406
|
+
static getListContext(text, cursorPosition) {
|
|
407
|
+
const lines = text.split("\n");
|
|
408
|
+
let currentPos = 0;
|
|
409
|
+
let lineIndex = 0;
|
|
410
|
+
let lineStart = 0;
|
|
411
|
+
for (let i = 0; i < lines.length; i++) {
|
|
412
|
+
const lineLength = lines[i].length;
|
|
413
|
+
if (currentPos + lineLength >= cursorPosition) {
|
|
414
|
+
lineIndex = i;
|
|
415
|
+
lineStart = currentPos;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
currentPos += lineLength + 1;
|
|
419
|
+
}
|
|
420
|
+
const currentLine = lines[lineIndex];
|
|
421
|
+
const lineEnd = lineStart + currentLine.length;
|
|
422
|
+
const checkboxMatch = currentLine.match(this.LIST_PATTERNS.checkbox);
|
|
423
|
+
if (checkboxMatch) {
|
|
424
|
+
return {
|
|
425
|
+
inList: true,
|
|
426
|
+
listType: "checkbox",
|
|
427
|
+
indent: checkboxMatch[1],
|
|
428
|
+
marker: "-",
|
|
429
|
+
checked: checkboxMatch[2] === "x",
|
|
430
|
+
content: checkboxMatch[3],
|
|
431
|
+
lineStart,
|
|
432
|
+
lineEnd,
|
|
433
|
+
markerEndPos: lineStart + checkboxMatch[1].length + checkboxMatch[2].length + 5
|
|
434
|
+
// indent + "- [ ] "
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
const bulletMatch = currentLine.match(this.LIST_PATTERNS.bullet);
|
|
438
|
+
if (bulletMatch) {
|
|
439
|
+
return {
|
|
440
|
+
inList: true,
|
|
441
|
+
listType: "bullet",
|
|
442
|
+
indent: bulletMatch[1],
|
|
443
|
+
marker: bulletMatch[2],
|
|
444
|
+
content: bulletMatch[3],
|
|
445
|
+
lineStart,
|
|
446
|
+
lineEnd,
|
|
447
|
+
markerEndPos: lineStart + bulletMatch[1].length + bulletMatch[2].length + 1
|
|
448
|
+
// indent + marker + space
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const numberedMatch = currentLine.match(this.LIST_PATTERNS.numbered);
|
|
452
|
+
if (numberedMatch) {
|
|
453
|
+
return {
|
|
454
|
+
inList: true,
|
|
455
|
+
listType: "numbered",
|
|
456
|
+
indent: numberedMatch[1],
|
|
457
|
+
marker: parseInt(numberedMatch[2]),
|
|
458
|
+
content: numberedMatch[3],
|
|
459
|
+
lineStart,
|
|
460
|
+
lineEnd,
|
|
461
|
+
markerEndPos: lineStart + numberedMatch[1].length + numberedMatch[2].length + 2
|
|
462
|
+
// indent + number + ". "
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
inList: false,
|
|
467
|
+
listType: null,
|
|
468
|
+
indent: "",
|
|
469
|
+
marker: null,
|
|
470
|
+
content: currentLine,
|
|
471
|
+
lineStart,
|
|
472
|
+
lineEnd,
|
|
473
|
+
markerEndPos: lineStart
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Create a new list item based on context
|
|
478
|
+
* @param {Object} context - List context from getListContext
|
|
479
|
+
* @returns {string} New list item text
|
|
480
|
+
*/
|
|
481
|
+
static createNewListItem(context) {
|
|
482
|
+
switch (context.listType) {
|
|
483
|
+
case "bullet":
|
|
484
|
+
return `${context.indent}${context.marker} `;
|
|
485
|
+
case "numbered":
|
|
486
|
+
return `${context.indent}${context.marker + 1}. `;
|
|
487
|
+
case "checkbox":
|
|
488
|
+
return `${context.indent}- [ ] `;
|
|
489
|
+
default:
|
|
490
|
+
return "";
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Renumber all numbered lists in text
|
|
495
|
+
* @param {string} text - Text containing numbered lists
|
|
496
|
+
* @returns {string} Text with renumbered lists
|
|
497
|
+
*/
|
|
498
|
+
static renumberLists(text) {
|
|
499
|
+
const lines = text.split("\n");
|
|
500
|
+
const numbersByIndent = /* @__PURE__ */ new Map();
|
|
501
|
+
let inList = false;
|
|
502
|
+
const result = lines.map((line) => {
|
|
503
|
+
const match = line.match(this.LIST_PATTERNS.numbered);
|
|
504
|
+
if (match) {
|
|
505
|
+
const indent = match[1];
|
|
506
|
+
const indentLevel = indent.length;
|
|
507
|
+
const content = match[3];
|
|
508
|
+
if (!inList) {
|
|
509
|
+
numbersByIndent.clear();
|
|
510
|
+
}
|
|
511
|
+
const currentNumber = (numbersByIndent.get(indentLevel) || 0) + 1;
|
|
512
|
+
numbersByIndent.set(indentLevel, currentNumber);
|
|
513
|
+
for (const [level] of numbersByIndent) {
|
|
514
|
+
if (level > indentLevel) {
|
|
515
|
+
numbersByIndent.delete(level);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
inList = true;
|
|
519
|
+
return `${indent}${currentNumber}. ${content}`;
|
|
520
|
+
} else {
|
|
521
|
+
if (line.trim() === "" || !line.match(/^\s/)) {
|
|
522
|
+
inList = false;
|
|
523
|
+
numbersByIndent.clear();
|
|
524
|
+
}
|
|
525
|
+
return line;
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
return result.join("\n");
|
|
529
|
+
}
|
|
400
530
|
};
|
|
401
531
|
// Track link index for anchor naming
|
|
402
532
|
__publicField(MarkdownParser, "linkIndex", 0);
|
|
533
|
+
/**
|
|
534
|
+
* List pattern definitions
|
|
535
|
+
*/
|
|
536
|
+
__publicField(MarkdownParser, "LIST_PATTERNS", {
|
|
537
|
+
bullet: /^(\s*)([-*+])\s+(.*)$/,
|
|
538
|
+
numbered: /^(\s*)(\d+)\.\s+(.*)$/,
|
|
539
|
+
checkbox: /^(\s*)-\s+\[([ x])\]\s+(.*)$/
|
|
540
|
+
});
|
|
403
541
|
|
|
404
542
|
// node_modules/markdown-actions/dist/markdown-actions.esm.js
|
|
405
543
|
var __defProp2 = Object.defineProperty;
|
|
@@ -2872,7 +3010,9 @@ ${blockSuffix}` : suffix;
|
|
|
2872
3010
|
showActiveLineRaw: false,
|
|
2873
3011
|
showStats: false,
|
|
2874
3012
|
toolbar: false,
|
|
2875
|
-
statsFormatter: null
|
|
3013
|
+
statsFormatter: null,
|
|
3014
|
+
smartLists: true
|
|
3015
|
+
// Enable smart list continuation
|
|
2876
3016
|
};
|
|
2877
3017
|
const { theme, colors, ...cleanOptions } = options;
|
|
2878
3018
|
return {
|
|
@@ -3165,11 +3305,113 @@ ${blockSuffix}` : suffix;
|
|
|
3165
3305
|
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3166
3306
|
return;
|
|
3167
3307
|
}
|
|
3308
|
+
if (event.key === "Enter" && !event.shiftKey && !event.metaKey && !event.ctrlKey && this.options.smartLists) {
|
|
3309
|
+
if (this.handleSmartListContinuation()) {
|
|
3310
|
+
event.preventDefault();
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3168
3314
|
const handled = this.shortcuts.handleKeydown(event);
|
|
3169
3315
|
if (!handled && this.options.onKeydown) {
|
|
3170
3316
|
this.options.onKeydown(event, this);
|
|
3171
3317
|
}
|
|
3172
3318
|
}
|
|
3319
|
+
/**
|
|
3320
|
+
* Handle smart list continuation
|
|
3321
|
+
* @returns {boolean} Whether the event was handled
|
|
3322
|
+
*/
|
|
3323
|
+
handleSmartListContinuation() {
|
|
3324
|
+
const textarea = this.textarea;
|
|
3325
|
+
const cursorPos = textarea.selectionStart;
|
|
3326
|
+
const context = MarkdownParser.getListContext(textarea.value, cursorPos);
|
|
3327
|
+
if (!context || !context.inList)
|
|
3328
|
+
return false;
|
|
3329
|
+
if (context.content.trim() === "" && cursorPos >= context.markerEndPos) {
|
|
3330
|
+
this.deleteListMarker(context);
|
|
3331
|
+
return true;
|
|
3332
|
+
}
|
|
3333
|
+
if (cursorPos > context.markerEndPos && cursorPos < context.lineEnd) {
|
|
3334
|
+
this.splitListItem(context, cursorPos);
|
|
3335
|
+
} else {
|
|
3336
|
+
this.insertNewListItem(context);
|
|
3337
|
+
}
|
|
3338
|
+
if (context.listType === "numbered") {
|
|
3339
|
+
this.scheduleNumberedListUpdate();
|
|
3340
|
+
}
|
|
3341
|
+
return true;
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Delete list marker and exit list
|
|
3345
|
+
* @private
|
|
3346
|
+
*/
|
|
3347
|
+
deleteListMarker(context) {
|
|
3348
|
+
this.textarea.setSelectionRange(context.lineStart, context.markerEndPos);
|
|
3349
|
+
document.execCommand("delete");
|
|
3350
|
+
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3351
|
+
}
|
|
3352
|
+
/**
|
|
3353
|
+
* Insert new list item
|
|
3354
|
+
* @private
|
|
3355
|
+
*/
|
|
3356
|
+
insertNewListItem(context) {
|
|
3357
|
+
const newItem = MarkdownParser.createNewListItem(context);
|
|
3358
|
+
document.execCommand("insertText", false, "\n" + newItem);
|
|
3359
|
+
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3360
|
+
}
|
|
3361
|
+
/**
|
|
3362
|
+
* Split list item at cursor position
|
|
3363
|
+
* @private
|
|
3364
|
+
*/
|
|
3365
|
+
splitListItem(context, cursorPos) {
|
|
3366
|
+
const textAfterCursor = context.content.substring(cursorPos - context.markerEndPos);
|
|
3367
|
+
this.textarea.setSelectionRange(cursorPos, context.lineEnd);
|
|
3368
|
+
document.execCommand("delete");
|
|
3369
|
+
const newItem = MarkdownParser.createNewListItem(context);
|
|
3370
|
+
document.execCommand("insertText", false, "\n" + newItem + textAfterCursor);
|
|
3371
|
+
const newCursorPos = this.textarea.selectionStart - textAfterCursor.length;
|
|
3372
|
+
this.textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
3373
|
+
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3374
|
+
}
|
|
3375
|
+
/**
|
|
3376
|
+
* Schedule numbered list renumbering
|
|
3377
|
+
* @private
|
|
3378
|
+
*/
|
|
3379
|
+
scheduleNumberedListUpdate() {
|
|
3380
|
+
if (this.numberUpdateTimeout) {
|
|
3381
|
+
clearTimeout(this.numberUpdateTimeout);
|
|
3382
|
+
}
|
|
3383
|
+
this.numberUpdateTimeout = setTimeout(() => {
|
|
3384
|
+
this.updateNumberedLists();
|
|
3385
|
+
}, 10);
|
|
3386
|
+
}
|
|
3387
|
+
/**
|
|
3388
|
+
* Update/renumber all numbered lists
|
|
3389
|
+
* @private
|
|
3390
|
+
*/
|
|
3391
|
+
updateNumberedLists() {
|
|
3392
|
+
const value = this.textarea.value;
|
|
3393
|
+
const cursorPos = this.textarea.selectionStart;
|
|
3394
|
+
const newValue = MarkdownParser.renumberLists(value);
|
|
3395
|
+
if (newValue !== value) {
|
|
3396
|
+
let offset = 0;
|
|
3397
|
+
const oldLines = value.split("\n");
|
|
3398
|
+
const newLines = newValue.split("\n");
|
|
3399
|
+
let charCount = 0;
|
|
3400
|
+
for (let i = 0; i < oldLines.length && charCount < cursorPos; i++) {
|
|
3401
|
+
if (oldLines[i] !== newLines[i]) {
|
|
3402
|
+
const diff = newLines[i].length - oldLines[i].length;
|
|
3403
|
+
if (charCount + oldLines[i].length < cursorPos) {
|
|
3404
|
+
offset += diff;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
charCount += oldLines[i].length + 1;
|
|
3408
|
+
}
|
|
3409
|
+
this.textarea.value = newValue;
|
|
3410
|
+
const newCursorPos = cursorPos + offset;
|
|
3411
|
+
this.textarea.setSelectionRange(newCursorPos, newCursorPos);
|
|
3412
|
+
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3173
3415
|
/**
|
|
3174
3416
|
* Handle scroll events
|
|
3175
3417
|
* @private
|