markdown-actions 1.1.1 → 1.2.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.
@@ -36,6 +36,7 @@ var markdownActions = (() => {
36
36
  __export(src_exports, {
37
37
  applyCustomFormat: () => applyCustomFormat,
38
38
  default: () => src_default,
39
+ detectMarkers: () => detectMarkers,
39
40
  expandSelection: () => expandSelection2,
40
41
  getActiveFormats: () => getActiveFormats2,
41
42
  getDebugMode: () => getDebugMode,
@@ -194,8 +195,12 @@ var markdownActions = (() => {
194
195
  textarea.contentEditable = "true";
195
196
  try {
196
197
  canInsertText = document.execCommand("insertText", false, text);
198
+ if (debugMode2)
199
+ console.log("execCommand returned:", canInsertText, "for text with", text.split("\n").length, "lines");
197
200
  } catch (error) {
198
201
  canInsertText = false;
202
+ if (debugMode2)
203
+ console.log("execCommand threw error:", error);
199
204
  }
200
205
  textarea.contentEditable = "false";
201
206
  }
@@ -503,20 +508,20 @@ ${blockSuffix}` : suffix;
503
508
  }
504
509
  function undoUnorderedListStyle(text) {
505
510
  const lines = text.split("\n");
506
- const unorderedListPrefix = "- ";
507
- const shouldUndoUnorderedList = lines.every((line) => line.startsWith(unorderedListPrefix));
511
+ const unorderedListRegex = /^[-*+] /;
512
+ const shouldUndoUnorderedList = lines.every((line) => unorderedListRegex.test(line));
508
513
  let result = lines;
509
514
  if (shouldUndoUnorderedList) {
510
- result = lines.map((line) => line.slice(unorderedListPrefix.length));
515
+ result = lines.map((line) => line.replace(unorderedListRegex, ""));
511
516
  }
512
517
  return {
513
518
  text: result.join("\n"),
514
519
  processed: shouldUndoUnorderedList
515
520
  };
516
521
  }
517
- function makePrefix(index, unorderedList) {
522
+ function makePrefix(index, unorderedList, bulletMarker = "-") {
518
523
  if (unorderedList) {
519
- return "- ";
524
+ return `${bulletMarker} `;
520
525
  } else {
521
526
  return `${index + 1}. `;
522
527
  }
@@ -544,7 +549,7 @@ ${blockSuffix}` : suffix;
544
549
  const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
545
550
  const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText);
546
551
  const prefixedLines = pristineText.split("\n").map((value, index) => {
547
- return `${makePrefix(index, style.unorderedList)}${value}`;
552
+ return `${makePrefix(index, style.unorderedList, style.bulletMarker)}${value}`;
548
553
  });
549
554
  const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
550
555
  return previousValue + makePrefix(currentIndex, style.unorderedList).length;
@@ -587,7 +592,7 @@ ${blockSuffix}` : suffix;
587
592
  adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
588
593
  const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd);
589
594
  const orderedListRegex = /^\d+\.\s+/;
590
- const unorderedListRegex = /^- /;
595
+ const unorderedListRegex = /^[-*+] /;
591
596
  const hasOrderedList = orderedListRegex.test(currentLine);
592
597
  const hasUnorderedList = unorderedListRegex.test(currentLine);
593
598
  const isRemovingCurrent = style.orderedList && hasOrderedList || style.unorderedList && hasUnorderedList;
@@ -662,8 +667,8 @@ ${blockSuffix}` : suffix;
662
667
  }
663
668
  lineStart += line.length + 1;
664
669
  }
665
- if (currentLine.startsWith("- ")) {
666
- if (currentLine.startsWith("- [ ] ") || currentLine.startsWith("- [x] ")) {
670
+ if (/^[-*+] /.test(currentLine)) {
671
+ if (/^[-*+] \[[ xX]\] /.test(currentLine)) {
667
672
  formats.push("task-list");
668
673
  } else {
669
674
  formats.push("bullet-list");
@@ -684,36 +689,30 @@ ${blockSuffix}` : suffix;
684
689
  const lookBehind = Math.max(0, selectionStart - 10);
685
690
  const lookAhead = Math.min(value.length, selectionEnd + 10);
686
691
  const surrounding = value.slice(lookBehind, lookAhead);
687
- if (surrounding.includes("**")) {
688
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
689
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
690
- const lastOpenBold = beforeCursor.lastIndexOf("**");
691
- const nextCloseBold = afterCursor.indexOf("**");
692
- if (lastOpenBold !== -1 && nextCloseBold !== -1) {
693
- formats.push("bold");
694
- }
692
+ const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
693
+ const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
694
+ if (["**", "__"].some((marker) => surrounding.includes(marker) && beforeCursor.lastIndexOf(marker) !== -1 && afterCursor.indexOf(marker) !== -1)) {
695
+ formats.push("bold");
695
696
  }
696
- if (surrounding.includes("_")) {
697
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
698
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
699
- const lastOpenItalic = beforeCursor.lastIndexOf("_");
700
- const nextCloseItalic = afterCursor.indexOf("_");
701
- if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {
702
- formats.push("italic");
703
- }
697
+ const singleMarker = (ch) => {
698
+ const c = ch === "*" ? "\\*" : ch;
699
+ return new RegExp(`(^|[^${c}])${c}[^${c}]*$`).test(beforeCursor) && new RegExp(`^[^${c}]*${c}(?!${c})`).test(afterCursor);
700
+ };
701
+ if (surrounding.includes("_") && singleMarker("_") || surrounding.includes("*") && singleMarker("*")) {
702
+ formats.push("italic");
704
703
  }
705
704
  if (surrounding.includes("`")) {
706
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
707
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
708
- if (beforeCursor.includes("`") && afterCursor.includes("`")) {
705
+ const beforeCursor2 = value.slice(Math.max(0, selectionStart - 100), selectionStart);
706
+ const afterCursor2 = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
707
+ if (beforeCursor2.includes("`") && afterCursor2.includes("`")) {
709
708
  formats.push("code");
710
709
  }
711
710
  }
712
711
  if (surrounding.includes("[") && surrounding.includes("]")) {
713
- const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
714
- const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
715
- const lastOpenBracket = beforeCursor.lastIndexOf("[");
716
- const nextCloseBracket = afterCursor.indexOf("]");
712
+ const beforeCursor2 = value.slice(Math.max(0, selectionStart - 100), selectionStart);
713
+ const afterCursor2 = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
714
+ const lastOpenBracket = beforeCursor2.lastIndexOf("[");
715
+ const nextCloseBracket = afterCursor2.indexOf("]");
717
716
  if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {
718
717
  const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10);
719
718
  if (afterBracket.startsWith("(")) {
@@ -761,23 +760,129 @@ ${blockSuffix}` : suffix;
761
760
  }
762
761
  }
763
762
 
763
+ // src/operations/inline.js
764
+ var isEmphasis = (ch) => ch === "*" || ch === "_";
765
+ var OPENING_PUNCTUATION = /[(\[{"'“‘]/;
766
+ var CLOSING_PUNCTUATION = /[.,;:!?)\]}"'”’]/;
767
+ function carries(kind, n) {
768
+ return kind === "bold" ? n >= 2 : n % 2 === 1;
769
+ }
770
+ function runLength(text, ch, fromEnd) {
771
+ let n = 0;
772
+ while (n < text.length && text[fromEnd ? text.length - 1 - n : n] === ch)
773
+ n++;
774
+ return n;
775
+ }
776
+ function findWrap(value, start, end, kind) {
777
+ const size = kind === "bold" ? 2 : 1;
778
+ let open = start;
779
+ while (open > 0 && isEmphasis(value[open - 1]))
780
+ open--;
781
+ let close = end;
782
+ while (close < value.length && isEmphasis(value[close]))
783
+ close++;
784
+ const before = value.slice(open, start);
785
+ const after = value.slice(end, close);
786
+ for (const ch of ["*", "_"]) {
787
+ if (carries(kind, runLength(before, ch, true)) && carries(kind, runLength(after, ch, false))) {
788
+ return { open: start - size, close: end, size };
789
+ }
790
+ const outerBefore = runLength(before, ch, false);
791
+ if (outerBefore < before.length && carries(kind, outerBefore) && carries(kind, runLength(after, ch, true))) {
792
+ return { open, close: close - size, size };
793
+ }
794
+ }
795
+ return null;
796
+ }
797
+ function targetRange(value, selectionStart, selectionEnd) {
798
+ let start = selectionStart;
799
+ let end = selectionEnd;
800
+ if (start === end) {
801
+ start = wordSelectionStart(value, start);
802
+ end = wordSelectionEnd(value, end, false);
803
+ while (start < end && OPENING_PUNCTUATION.test(value[start]))
804
+ start++;
805
+ while (end > start && CLOSING_PUNCTUATION.test(value[end - 1]))
806
+ end--;
807
+ }
808
+ while (start < end && /\s/.test(value[start]))
809
+ start++;
810
+ while (end > start && /\s/.test(value[end - 1]))
811
+ end--;
812
+ while (start < end && isEmphasis(value[start]))
813
+ start++;
814
+ while (end > start && isEmphasis(value[end - 1]))
815
+ end--;
816
+ return { start, end };
817
+ }
818
+ var clamp = (n, low, high) => Math.min(Math.max(n, low), high);
819
+ function inlineStyle(textarea, kind, marker) {
820
+ const value = textarea.value;
821
+ const caretStart = textarea.selectionStart;
822
+ const caretEnd = textarea.selectionEnd;
823
+ const hadSelection = caretStart !== caretEnd;
824
+ const { start, end } = targetRange(value, caretStart, caretEnd);
825
+ const wrap = start < end ? findWrap(value, start, end, kind) : null;
826
+ if (wrap) {
827
+ textarea.selectionStart = wrap.open;
828
+ textarea.selectionEnd = wrap.close + wrap.size;
829
+ const newStart = start - wrap.size;
830
+ const newEnd = end - wrap.size;
831
+ const caret2 = clamp(caretStart - wrap.size, newStart, newEnd);
832
+ return {
833
+ text: value.slice(wrap.open + wrap.size, wrap.close),
834
+ selectionStart: hadSelection ? newStart : caret2,
835
+ selectionEnd: hadSelection ? newEnd : caret2
836
+ };
837
+ }
838
+ textarea.selectionStart = start;
839
+ textarea.selectionEnd = end;
840
+ const caret = clamp(caretStart, start, end) + marker.length;
841
+ return {
842
+ text: marker + value.slice(start, end) + marker,
843
+ selectionStart: hadSelection ? start + marker.length : caret,
844
+ selectionEnd: hadSelection ? end + marker.length : caret
845
+ };
846
+ }
847
+
848
+ // src/core/markers.js
849
+ var MARKERS = {
850
+ bold: ["**", "__"],
851
+ italic: ["_", "*"],
852
+ bullet: ["-", "*", "+"]
853
+ };
854
+ function resolveMarker(kind, marker) {
855
+ return MARKERS[kind].indexOf(marker) !== -1 ? marker : MARKERS[kind][0];
856
+ }
857
+ var DETECT = {
858
+ bullet: /^[ \t]*([-*+])[ \t]+\S/m,
859
+ bold: /(\*\*|__)(?=[^\s*_])[^\n]*?[^\s*_]\1/,
860
+ italic: /(?:^|[^*_\w])([*_])(?=[^\s*_])[^\n*_]*?[^\s*_]\1(?![*_\w])/
861
+ };
862
+ function detectMarkers(text) {
863
+ const found = {};
864
+ Object.keys(DETECT).forEach((kind) => {
865
+ const match = DETECT[kind].exec(text || "");
866
+ found[kind] = match ? match[1] : null;
867
+ });
868
+ return found;
869
+ }
870
+
764
871
  // src/index.js
765
- function toggleBold(textarea) {
872
+ function toggleBold(textarea, options = {}) {
766
873
  if (!textarea || textarea.disabled || textarea.readOnly)
767
874
  return;
768
875
  debugLog("toggleBold", "Starting");
769
876
  debugSelection(textarea, "Before");
770
- const style = mergeWithDefaults(FORMATS.bold);
771
- const result = blockStyle(textarea, style);
877
+ const result = inlineStyle(textarea, "bold", resolveMarker("bold", options.marker));
772
878
  debugResult(result);
773
879
  insertText(textarea, result);
774
880
  debugSelection(textarea, "After");
775
881
  }
776
- function toggleItalic(textarea) {
882
+ function toggleItalic(textarea, options = {}) {
777
883
  if (!textarea || textarea.disabled || textarea.readOnly)
778
884
  return;
779
- const style = mergeWithDefaults(FORMATS.italic);
780
- const result = blockStyle(textarea, style);
885
+ const result = inlineStyle(textarea, "italic", resolveMarker("italic", options.marker));
781
886
  insertText(textarea, result);
782
887
  }
783
888
  function toggleCode(textarea) {
@@ -809,10 +914,11 @@ ${blockSuffix}` : suffix;
809
914
  const result = blockStyle(textarea, style);
810
915
  insertText(textarea, result);
811
916
  }
812
- function toggleBulletList(textarea) {
917
+ function toggleBulletList(textarea, options = {}) {
813
918
  if (!textarea || textarea.disabled || textarea.readOnly)
814
919
  return;
815
920
  const style = mergeWithDefaults(FORMATS.bulletList);
921
+ style.bulletMarker = resolveMarker("bullet", options.marker);
816
922
  applyListStyle(textarea, style);
817
923
  }
818
924
  function toggleNumberedList(textarea) {
@@ -995,6 +1101,7 @@ ${blockSuffix}` : suffix;
995
1101
  hasFormat: hasFormat2,
996
1102
  expandSelection: expandSelection2,
997
1103
  applyCustomFormat,
1104
+ detectMarkers,
998
1105
  preserveSelection,
999
1106
  setUndoMethod,
1000
1107
  setDebugMode,