@pixerate/editor 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/README.md +175 -2
  2. package/THIRD_PARTY_NOTICES.md +139 -0
  3. package/dist/agent/index.cjs +87 -111
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +70 -211
  6. package/dist/agent/index.d.ts +70 -211
  7. package/dist/agent/index.js +78 -102
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
  10. package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
  11. package/dist/canvas/index.cjs +2075 -86
  12. package/dist/canvas/index.cjs.map +1 -1
  13. package/dist/canvas/index.d.cts +608 -186
  14. package/dist/canvas/index.d.ts +608 -186
  15. package/dist/canvas/index.js +2060 -71
  16. package/dist/canvas/index.js.map +1 -1
  17. package/dist/chunk-26BVFKHU.cjs +453 -0
  18. package/dist/chunk-26BVFKHU.cjs.map +1 -0
  19. package/dist/chunk-2H7ZHPEJ.js +762 -0
  20. package/dist/chunk-2H7ZHPEJ.js.map +1 -0
  21. package/dist/{chunk-DENSCKFC.js → chunk-3CN2WD3X.js} +1730 -189
  22. package/dist/chunk-3CN2WD3X.js.map +1 -0
  23. package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
  24. package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
  25. package/dist/chunk-5S3Z4PPF.js.map +1 -0
  26. package/dist/chunk-664LQYFJ.js +115 -0
  27. package/dist/chunk-664LQYFJ.js.map +1 -0
  28. package/dist/chunk-7DWMJCAT.js +453 -0
  29. package/dist/chunk-7DWMJCAT.js.map +1 -0
  30. package/dist/chunk-ARRTP33I.js +101 -0
  31. package/dist/chunk-ARRTP33I.js.map +1 -0
  32. package/dist/chunk-CPOKFNBG.cjs +101 -0
  33. package/dist/chunk-CPOKFNBG.cjs.map +1 -0
  34. package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
  35. package/dist/chunk-D27YFC46.cjs.map +1 -0
  36. package/dist/chunk-D6FH2YAX.cjs +131 -0
  37. package/dist/chunk-D6FH2YAX.cjs.map +1 -0
  38. package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
  39. package/dist/chunk-FD4LPFAE.cjs.map +1 -0
  40. package/dist/chunk-FODNLX5N.js +749 -0
  41. package/dist/chunk-FODNLX5N.js.map +1 -0
  42. package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
  43. package/dist/chunk-FPENXAEJ.js.map +1 -0
  44. package/dist/chunk-G2I4QJOT.cjs +762 -0
  45. package/dist/chunk-G2I4QJOT.cjs.map +1 -0
  46. package/dist/chunk-HLIMTC6N.js +1 -0
  47. package/dist/chunk-HLIMTC6N.js.map +1 -0
  48. package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
  49. package/dist/chunk-ITBSKI26.js.map +1 -0
  50. package/dist/{chunk-6M3BCTBD.cjs → chunk-MA2F5KHF.cjs} +470 -242
  51. package/dist/chunk-MA2F5KHF.cjs.map +1 -0
  52. package/dist/{chunk-SAZRENEZ.cjs → chunk-MCSJFWAO.cjs} +1733 -192
  53. package/dist/chunk-MCSJFWAO.cjs.map +1 -0
  54. package/dist/chunk-MKA3AHLV.cjs +256 -0
  55. package/dist/chunk-MKA3AHLV.cjs.map +1 -0
  56. package/dist/chunk-OLZJXL4R.cjs +749 -0
  57. package/dist/chunk-OLZJXL4R.cjs.map +1 -0
  58. package/dist/chunk-OXSV64JX.js +689 -0
  59. package/dist/chunk-OXSV64JX.js.map +1 -0
  60. package/dist/chunk-P3RQ5UJE.cjs +689 -0
  61. package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
  62. package/dist/chunk-P6ODPZ4W.js +256 -0
  63. package/dist/chunk-P6ODPZ4W.js.map +1 -0
  64. package/dist/chunk-PGNZKFQS.js +685 -0
  65. package/dist/chunk-PGNZKFQS.js.map +1 -0
  66. package/dist/chunk-PL4JB3BF.cjs +1 -0
  67. package/dist/chunk-PL4JB3BF.cjs.map +1 -0
  68. package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
  69. package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
  70. package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
  71. package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
  72. package/dist/chunk-TNNJXF46.cjs +115 -0
  73. package/dist/chunk-TNNJXF46.cjs.map +1 -0
  74. package/dist/chunk-U5HZSFCS.js +131 -0
  75. package/dist/chunk-U5HZSFCS.js.map +1 -0
  76. package/dist/{chunk-RU52I7QO.js → chunk-U5KWZU4X.js} +388 -160
  77. package/dist/chunk-U5KWZU4X.js.map +1 -0
  78. package/dist/chunk-XNORY7M6.cjs +685 -0
  79. package/dist/chunk-XNORY7M6.cjs.map +1 -0
  80. package/dist/commands/index.cjs +860 -0
  81. package/dist/commands/index.cjs.map +1 -0
  82. package/dist/commands/index.d.cts +244 -0
  83. package/dist/commands/index.d.ts +244 -0
  84. package/dist/commands/index.js +860 -0
  85. package/dist/commands/index.js.map +1 -0
  86. package/dist/comment-store-BEMgVlAA.d.cts +135 -0
  87. package/dist/comment-store-BEMgVlAA.d.ts +135 -0
  88. package/dist/compare/index.cjs +15 -0
  89. package/dist/compare/index.cjs.map +1 -0
  90. package/dist/compare/index.d.cts +58 -0
  91. package/dist/compare/index.d.ts +58 -0
  92. package/dist/compare/index.js +15 -0
  93. package/dist/compare/index.js.map +1 -0
  94. package/dist/{controller-B7GIybc4.d.cts → controller-BhLLAoi8.d.cts} +119 -5
  95. package/dist/{controller-B7GIybc4.d.ts → controller-BhLLAoi8.d.ts} +119 -5
  96. package/dist/documents-BQjzJNe2.d.ts +76 -0
  97. package/dist/documents-KRTPhvst.d.cts +76 -0
  98. package/dist/extensions/index.cjs +53 -5
  99. package/dist/extensions/index.cjs.map +1 -1
  100. package/dist/extensions/index.d.cts +7 -3
  101. package/dist/extensions/index.d.ts +7 -3
  102. package/dist/extensions/index.js +52 -4
  103. package/dist/generation/index.cjs +1373 -0
  104. package/dist/generation/index.cjs.map +1 -0
  105. package/dist/generation/index.d.cts +554 -0
  106. package/dist/generation/index.d.ts +554 -0
  107. package/dist/generation/index.js +1373 -0
  108. package/dist/generation/index.js.map +1 -0
  109. package/dist/grammar/index.cjs +48 -3
  110. package/dist/grammar/index.cjs.map +1 -1
  111. package/dist/grammar/index.d.cts +322 -100
  112. package/dist/grammar/index.d.ts +322 -100
  113. package/dist/grammar/index.js +54 -9
  114. package/dist/history/index.cjs +12 -2
  115. package/dist/history/index.cjs.map +1 -1
  116. package/dist/history/index.d.cts +211 -7
  117. package/dist/history/index.d.ts +211 -7
  118. package/dist/history/index.js +13 -3
  119. package/dist/image-editor/index.cjs +2244 -38
  120. package/dist/image-editor/index.cjs.map +1 -1
  121. package/dist/image-editor/index.d.cts +742 -4
  122. package/dist/image-editor/index.d.ts +742 -4
  123. package/dist/image-editor/index.js +2222 -16
  124. package/dist/image-editor/index.js.map +1 -1
  125. package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
  126. package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
  127. package/dist/index.cjs +193 -98
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +17 -48
  130. package/dist/index.d.ts +17 -48
  131. package/dist/index.js +198 -103
  132. package/dist/index.js.map +1 -1
  133. package/dist/migrate-iTlm3a8h.d.cts +112 -0
  134. package/dist/migrate-iTlm3a8h.d.ts +112 -0
  135. package/dist/persistence/index.cjs +676 -0
  136. package/dist/persistence/index.cjs.map +1 -0
  137. package/dist/persistence/index.d.cts +347 -0
  138. package/dist/persistence/index.d.ts +347 -0
  139. package/dist/persistence/index.js +676 -0
  140. package/dist/persistence/index.js.map +1 -0
  141. package/dist/registry-BDe-vlv3.d.ts +171 -0
  142. package/dist/registry-D32LpIc4.d.cts +354 -0
  143. package/dist/registry-DnzpgY27.d.cts +171 -0
  144. package/dist/registry-evKTP4ls.d.ts +354 -0
  145. package/dist/schema-DYDGdYL9.d.cts +41 -0
  146. package/dist/schema-DYDGdYL9.d.ts +41 -0
  147. package/dist/serializers/index.cjs +4 -3
  148. package/dist/serializers/index.cjs.map +1 -1
  149. package/dist/serializers/index.d.cts +2 -1
  150. package/dist/serializers/index.d.ts +2 -1
  151. package/dist/serializers/index.js +3 -2
  152. package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
  153. package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
  154. package/dist/spreadsheet/index.cjs +53 -3
  155. package/dist/spreadsheet/index.cjs.map +1 -1
  156. package/dist/spreadsheet/index.d.cts +247 -18
  157. package/dist/spreadsheet/index.d.ts +247 -18
  158. package/dist/spreadsheet/index.js +58 -8
  159. package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
  160. package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
  161. package/dist/{track-changes-BSF58RK0.d.cts → track-changes-BK5sVf4_.d.cts} +18 -136
  162. package/dist/{track-changes-BSF58RK0.d.ts → track-changes-CDjCrwKe.d.ts} +18 -136
  163. package/dist/{types-CJ4U-HHI.d.ts → types-DX4Mh4SL.d.cts} +1 -1
  164. package/dist/{types-CJ4U-HHI.d.cts → types-DX4Mh4SL.d.ts} +1 -1
  165. package/dist/types-GT5a5YAX.d.cts +86 -0
  166. package/dist/types-GT5a5YAX.d.ts +86 -0
  167. package/package.json +23 -2
  168. package/dist/chunk-2TWGLC5K.cjs +0 -262
  169. package/dist/chunk-2TWGLC5K.cjs.map +0 -1
  170. package/dist/chunk-4SUNJZWB.cjs.map +0 -1
  171. package/dist/chunk-6M3BCTBD.cjs.map +0 -1
  172. package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
  173. package/dist/chunk-AXV2ZW34.cjs +0 -118
  174. package/dist/chunk-AXV2ZW34.cjs.map +0 -1
  175. package/dist/chunk-B2ZRLN4S.js +0 -118
  176. package/dist/chunk-B2ZRLN4S.js.map +0 -1
  177. package/dist/chunk-DENSCKFC.js.map +0 -1
  178. package/dist/chunk-GVSMRPHB.cjs.map +0 -1
  179. package/dist/chunk-KAADNAPF.js +0 -262
  180. package/dist/chunk-KAADNAPF.js.map +0 -1
  181. package/dist/chunk-MJZBNWG7.js.map +0 -1
  182. package/dist/chunk-OYXSKQFR.js.map +0 -1
  183. package/dist/chunk-QGHGJ56O.js.map +0 -1
  184. package/dist/chunk-RU52I7QO.js.map +0 -1
  185. package/dist/chunk-SAZRENEZ.cjs.map +0 -1
  186. package/dist/types-BZgcDsC5.d.cts +0 -42
  187. package/dist/types-BZgcDsC5.d.ts +0 -42
  188. /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
@@ -1,10 +1,13 @@
1
+ import {
2
+ compareDocuments
3
+ } from "./chunk-FODNLX5N.js";
1
4
  import {
2
5
  INSTRUCTION_REGEX,
3
6
  TEMPLATE_REGEX,
4
7
  VARIABLE_REGEX,
5
8
  matchConditionalTags,
6
9
  parseVariableBody
7
- } from "./chunk-B2ZRLN4S.js";
10
+ } from "./chunk-P6ODPZ4W.js";
8
11
  import {
9
12
  PIXERATE_DOCUMENT_MIME,
10
13
  getClipboardData,
@@ -13,16 +16,20 @@ import {
13
16
  rtfToPlainText,
14
17
  sanitizeImportedHtml,
15
18
  serializeRichClipboardPayload
16
- } from "./chunk-JJDLPEWL.js";
19
+ } from "./chunk-3LV6RRPH.js";
17
20
  import {
18
- CommentStore,
19
- TrackChanges,
20
- createReviewId,
21
21
  escapeHtml,
22
22
  htmlToPlainText,
23
23
  markdownToTipTapHtml,
24
24
  plainTextToSlice
25
- } from "./chunk-MJZBNWG7.js";
25
+ } from "./chunk-PGNZKFQS.js";
26
+ import {
27
+ CommentStore,
28
+ TRACK_CHANGES_SKIP_META,
29
+ TrackChanges,
30
+ createReviewId,
31
+ trackChangesPluginKey
32
+ } from "./chunk-5S3Z4PPF.js";
26
33
 
27
34
  // src/extensions/gradient-text.ts
28
35
  import { Mark } from "@tiptap/core";
@@ -124,11 +131,12 @@ var createGradientDecorations = (doc, options) => {
124
131
  result.error ? {
125
132
  class: "underline decoration-wavy decoration-red-500 text-red-600 dark:text-red-400",
126
133
  "data-conditional-error": result.error,
127
- title: result.error === "unclosed-section" ? `Section "${tag.name}" is never closed with {/${tag.name}}` : `{/${tag.name}} does not close any open section`
134
+ title: result.error === "invalid-condition" ? `Invalid condition: ${result.comparison?.error ?? tag.name}` : result.error === "unclosed-section" ? `Section "${tag.name}" is never closed with {/${tag.name}}` : `{/${tag.name}} does not close any open section`
128
135
  } : {
129
136
  class: "bg-amber-400/30 text-amber-700 dark:text-amber-300 font-medium px-0.5 rounded-xs",
130
137
  "data-conditional": tag.conditional,
131
- "data-variable-condition": tag.name
138
+ // A comparison (`{?amount>100}`) names its subject variable.
139
+ "data-variable-condition": result.comparison?.subject ?? tag.name
132
140
  }
133
141
  )
134
142
  );
@@ -2028,8 +2036,56 @@ function getCommentAuthor(editor) {
2028
2036
  return ext ? resolveAuthor(ext.options.author) : null;
2029
2037
  }
2030
2038
 
2031
- // src/extensions/file-import.ts
2039
+ // src/extensions/document-compare.ts
2032
2040
  import { Extension as Extension7 } from "@tiptap/core";
2041
+ function trackChangesAuthor(state) {
2042
+ return trackChangesPluginKey.getState(state)?.author;
2043
+ }
2044
+ function compareInEditor(editor, original, revised, options = {}) {
2045
+ return compareDocuments(original, revised, {
2046
+ ...options,
2047
+ author: options.author ?? trackChangesAuthor(editor.state),
2048
+ schema: editor.schema
2049
+ });
2050
+ }
2051
+ function applyDocumentComparison(editor, original, revised, options = {}) {
2052
+ const result = compareInEditor(editor, original, revised, options);
2053
+ const { state } = editor;
2054
+ const tr = state.tr.replaceWith(0, state.doc.content.size, result.doc.content);
2055
+ tr.setMeta(TRACK_CHANGES_SKIP_META, true);
2056
+ editor.view.dispatch(tr);
2057
+ return result;
2058
+ }
2059
+ var DocumentCompare = Extension7.create({
2060
+ name: "documentCompare",
2061
+ addOptions() {
2062
+ return { compare: {} };
2063
+ },
2064
+ addStorage() {
2065
+ return { lastResult: null };
2066
+ },
2067
+ addCommands() {
2068
+ return {
2069
+ setContentFromComparison: (original, revised, options = {}) => ({ state, tr, dispatch }) => {
2070
+ const merged = { ...this.options.compare, ...options };
2071
+ const result = compareDocuments(original, revised, {
2072
+ ...merged,
2073
+ author: merged.author ?? trackChangesAuthor(state),
2074
+ schema: state.schema
2075
+ });
2076
+ if (dispatch) {
2077
+ tr.replaceWith(0, tr.doc.content.size, result.doc.content);
2078
+ tr.setMeta(TRACK_CHANGES_SKIP_META, true);
2079
+ this.storage.lastResult = result;
2080
+ }
2081
+ return true;
2082
+ }
2083
+ };
2084
+ }
2085
+ });
2086
+
2087
+ // src/extensions/file-import.ts
2088
+ import { Extension as Extension8 } from "@tiptap/core";
2033
2089
  import { Plugin as Plugin7, PluginKey as PluginKey4 } from "@tiptap/pm/state";
2034
2090
 
2035
2091
  // src/import/registry.ts
@@ -3321,7 +3377,7 @@ function dropPosition(view, event) {
3321
3377
  return void 0;
3322
3378
  }
3323
3379
  }
3324
- var FileImport = Extension7.create({
3380
+ var FileImport = Extension8.create({
3325
3381
  name: "fileImport",
3326
3382
  addOptions() {
3327
3383
  return {
@@ -3372,7 +3428,7 @@ var FileImport = Extension7.create({
3372
3428
  });
3373
3429
 
3374
3430
  // src/extensions/rich-clipboard.ts
3375
- import { Extension as Extension8 } from "@tiptap/core";
3431
+ import { Extension as Extension9 } from "@tiptap/core";
3376
3432
  import { Plugin as Plugin8, PluginKey as PluginKey5 } from "@tiptap/pm/state";
3377
3433
  var richClipboardPluginKey = new PluginKey5("richClipboard");
3378
3434
  function writeRichClipboard(view, event, options = {}) {
@@ -3392,7 +3448,7 @@ function writeRichClipboard(view, event, options = {}) {
3392
3448
  }
3393
3449
  return true;
3394
3450
  }
3395
- var RichClipboard = Extension8.create({
3451
+ var RichClipboard = Extension9.create({
3396
3452
  name: "richClipboard",
3397
3453
  addOptions() {
3398
3454
  return {
@@ -3431,7 +3487,7 @@ var RichClipboard = Extension8.create({
3431
3487
  });
3432
3488
 
3433
3489
  // src/extensions/autocorrect.ts
3434
- import { Extension as Extension9 } from "@tiptap/core";
3490
+ import { Extension as Extension10 } from "@tiptap/core";
3435
3491
  import { closeHistory } from "@tiptap/pm/history";
3436
3492
  import { Plugin as Plugin9, PluginKey as PluginKey6 } from "@tiptap/pm/state";
3437
3493
  var quoteOpener = /[\s ([{<—–‘“-]/;
@@ -3590,7 +3646,7 @@ function isInsidePromptToken(textBefore) {
3590
3646
  const underscores = textBefore.match(/__/g);
3591
3647
  return !!underscores && underscores.length % 2 === 1;
3592
3648
  }
3593
- var Autocorrect = Extension9.create({
3649
+ var Autocorrect = Extension10.create({
3594
3650
  name: "autocorrect",
3595
3651
  addOptions() {
3596
3652
  return {
@@ -3738,7 +3794,7 @@ var Autocorrect = Extension9.create({
3738
3794
  });
3739
3795
 
3740
3796
  // src/extensions/document-structure/outline.ts
3741
- import { Extension as Extension10 } from "@tiptap/core";
3797
+ import { Extension as Extension11 } from "@tiptap/core";
3742
3798
  import {
3743
3799
  Plugin as Plugin10,
3744
3800
  PluginKey as PluginKey7,
@@ -3974,7 +4030,7 @@ function assignHeadingIds(state, types, generateId) {
3974
4030
  });
3975
4031
  return tr;
3976
4032
  }
3977
- var Outline = Extension10.create({
4033
+ var Outline = Extension11.create({
3978
4034
  name: "outline",
3979
4035
  priority: STRUCTURE_PRIORITY,
3980
4036
  addOptions() {
@@ -5169,6 +5225,1250 @@ function getDocumentStructureCommandItems(editor, query = "") {
5169
5225
  );
5170
5226
  }
5171
5227
 
5228
+ // src/extensions/find-replace/extension.ts
5229
+ import { Extension as Extension12 } from "@tiptap/core";
5230
+ import { Plugin as Plugin14, PluginKey as PluginKey11, TextSelection as TextSelection7 } from "@tiptap/pm/state";
5231
+ import { Decoration as Decoration4, DecorationSet as DecorationSet4 } from "@tiptap/pm/view";
5232
+ import { closeHistory as closeHistory2 } from "@tiptap/pm/history";
5233
+
5234
+ // src/extensions/find-replace/pattern.ts
5235
+ var FIND_PARAGRAPH_MARK = "\r";
5236
+ var MAX_FIND_PATTERN_LENGTH = 1024;
5237
+ var MAX_COUNT = 1e3;
5238
+ var MAX_PROGRAM_SIZE = 2e4;
5239
+ var now = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
5240
+ function createSearchBudget(options = {}) {
5241
+ return {
5242
+ deadline: now() + (options.timeLimitMs ?? 250),
5243
+ steps: options.maxSteps ?? 5e7,
5244
+ exhausted: false
5245
+ };
5246
+ }
5247
+ var PARA = 13;
5248
+ var ANY = (cp) => cp !== PARA;
5249
+ var LETTER = /\p{L}/u;
5250
+ var PUNCT = /\p{P}/u;
5251
+ var WORD = /[\p{L}\p{M}\p{Nd}\p{Pc}]/u;
5252
+ var foldCache = /* @__PURE__ */ new Map();
5253
+ function foldCodePoint(cp) {
5254
+ if (cp < 128) return cp >= 65 && cp <= 90 ? cp + 32 : cp;
5255
+ const cached = foldCache.get(cp);
5256
+ if (cached !== void 0) return cached;
5257
+ const lower = String.fromCodePoint(cp).toLowerCase();
5258
+ const folded = [...lower].length === 1 ? lower.codePointAt(0) : cp;
5259
+ if (foldCache.size < 4096) foldCache.set(cp, folded);
5260
+ return folded;
5261
+ }
5262
+ function isWordChar(cp) {
5263
+ if (cp < 0) return false;
5264
+ if (cp < 128) {
5265
+ return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 95;
5266
+ }
5267
+ return WORD.test(String.fromCodePoint(cp));
5268
+ }
5269
+ var isLetter = (cp) => cp < 128 ? cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 : LETTER.test(String.fromCodePoint(cp));
5270
+ function isPunct(cp) {
5271
+ if (cp < 128) {
5272
+ return cp >= 33 && cp <= 47 || cp >= 58 && cp <= 64 || cp >= 91 && cp <= 96 || cp >= 123 && cp <= 126;
5273
+ }
5274
+ return cp >= 8208 && cp <= 8231 || cp === 161 || cp === 191 || cp === 171 || cp === 187 || PUNCT.test(String.fromCodePoint(cp));
5275
+ }
5276
+ var isSpace = (cp) => cp === 32 || cp === 9 || cp === 160;
5277
+ function cpBefore(hay, pos) {
5278
+ if (pos <= 0) return -1;
5279
+ const low = hay.charCodeAt(pos - 1);
5280
+ if (low >= 56320 && low <= 57343 && pos >= 2) {
5281
+ const high = hay.charCodeAt(pos - 2);
5282
+ if (high >= 55296 && high <= 56319) return hay.codePointAt(pos - 2);
5283
+ }
5284
+ return low;
5285
+ }
5286
+ var cpAt = (hay, pos) => pos < hay.length ? hay.codePointAt(pos) : -1;
5287
+ var PatternError = class extends Error {
5288
+ constructor(code, message) {
5289
+ super(message);
5290
+ this.code = code;
5291
+ }
5292
+ code;
5293
+ };
5294
+ var charNode = (test) => ({ k: "char", test });
5295
+ var exact = (cp) => charNode((c) => c === cp);
5296
+ var literalNode = (cp, caseInsensitive) => {
5297
+ if (!caseInsensitive) return exact(cp);
5298
+ const f = foldCodePoint(cp);
5299
+ return charNode((_c, folded) => folded === f);
5300
+ };
5301
+ var star = (body, lazy) => ({ k: "rep", body, min: 0, max: -1, lazy });
5302
+ function findCode(c) {
5303
+ switch (c) {
5304
+ case "p":
5305
+ return exact(PARA);
5306
+ case "t":
5307
+ return exact(9);
5308
+ case "?":
5309
+ return charNode(ANY);
5310
+ case "#":
5311
+ return charNode((cp) => cp >= 48 && cp <= 57);
5312
+ case "$":
5313
+ return charNode((cp) => isLetter(cp));
5314
+ case "^":
5315
+ return exact(94);
5316
+ case "l":
5317
+ return exact(10);
5318
+ case "m":
5319
+ return exact(12);
5320
+ case "n":
5321
+ return exact(14);
5322
+ case "+":
5323
+ return exact(8212);
5324
+ case "=":
5325
+ return exact(8211);
5326
+ case "s":
5327
+ return exact(160);
5328
+ case "~":
5329
+ return exact(8209);
5330
+ case "-":
5331
+ return exact(173);
5332
+ case "w":
5333
+ return { k: "rep", body: charNode((cp) => isSpace(cp)), min: 1, max: -1, lazy: false };
5334
+ case "g":
5335
+ return exact(65532);
5336
+ case "%":
5337
+ return exact(167);
5338
+ case "v":
5339
+ return exact(182);
5340
+ default:
5341
+ return null;
5342
+ }
5343
+ }
5344
+ function replaceCode(c) {
5345
+ switch (c) {
5346
+ case "p":
5347
+ return FIND_PARAGRAPH_MARK;
5348
+ case "t":
5349
+ return " ";
5350
+ case "^":
5351
+ return "^";
5352
+ case "l":
5353
+ return "\n";
5354
+ case "m":
5355
+ return "\f";
5356
+ case "n":
5357
+ return "";
5358
+ case "+":
5359
+ return "\u2014";
5360
+ case "=":
5361
+ return "\u2013";
5362
+ case "s":
5363
+ return "\xA0";
5364
+ case "~":
5365
+ return "\u2011";
5366
+ case "-":
5367
+ return "\xAD";
5368
+ case "%":
5369
+ return "\xA7";
5370
+ case "v":
5371
+ return "\xB6";
5372
+ default:
5373
+ return null;
5374
+ }
5375
+ }
5376
+ function codeChar(n) {
5377
+ switch (n) {
5378
+ case 13:
5379
+ return PARA;
5380
+ case 11:
5381
+ return 10;
5382
+ case 12:
5383
+ return 12;
5384
+ case 14:
5385
+ return 14;
5386
+ case 30:
5387
+ return 8209;
5388
+ case 31:
5389
+ return 173;
5390
+ }
5391
+ if (n > 1114111 || n >= 55296 && n <= 57343) return null;
5392
+ if (n < 32 && n !== 9 || n >= 127 && n < 160) return null;
5393
+ return n;
5394
+ }
5395
+ function numericCode(chars, i) {
5396
+ const unicode = chars[i] === "u";
5397
+ const start2 = unicode ? i + 1 : i;
5398
+ const max = unicode ? 5 : 4;
5399
+ let digits = "";
5400
+ for (let j = start2; j < chars.length && digits.length < max && /[0-9]/.test(chars[j]); j++) digits += chars[j];
5401
+ if (!digits) return null;
5402
+ const cp = codeChar(parseInt(digits, 10));
5403
+ return cp === null ? null : { cp, used: start2 - i + digits.length };
5404
+ }
5405
+ var toChars = (s) => Array.from(s);
5406
+ var cpOf = (ch) => ch.codePointAt(0);
5407
+ function parseSpecial(query, o, caseInsensitive) {
5408
+ const chars = toChars(query);
5409
+ const atoms = [];
5410
+ let spans = false;
5411
+ let i = 0;
5412
+ while (i < chars.length) {
5413
+ const c = chars[i++];
5414
+ if (c === "^" && !o.literal && i < chars.length) {
5415
+ const n = chars[i];
5416
+ const code = findCode(n);
5417
+ if (code) {
5418
+ if (n === "p") spans = true;
5419
+ atoms.push(code);
5420
+ i++;
5421
+ continue;
5422
+ }
5423
+ const num = numericCode(chars, i);
5424
+ if (num) {
5425
+ if (num.cp === PARA) spans = true;
5426
+ atoms.push(literalNode(num.cp, caseInsensitive));
5427
+ i += num.used;
5428
+ continue;
5429
+ }
5430
+ }
5431
+ const cp = cpOf(c);
5432
+ if (o.ignorePunctuation && isPunct(cp) || o.ignoreWhitespace && isSpace(cp)) continue;
5433
+ atoms.push(literalNode(cp, caseInsensitive));
5434
+ }
5435
+ const filler = o.ignorePunctuation && o.ignoreWhitespace ? (cp) => isPunct(cp) || isSpace(cp) : o.ignorePunctuation ? (cp) => isPunct(cp) : o.ignoreWhitespace ? (cp) => isSpace(cp) : null;
5436
+ const items = [];
5437
+ atoms.forEach((atom, index) => {
5438
+ if (index > 0 && filler) items.push(star(charNode(filler), false));
5439
+ items.push(atom);
5440
+ });
5441
+ return { node: { k: "cat", items }, spans };
5442
+ }
5443
+ function parseCount(body) {
5444
+ const bad = () => new PatternError("invalid_pattern", `{${body}} is not a valid count`);
5445
+ const num = (s) => {
5446
+ const t = s.trim();
5447
+ if (!t) return null;
5448
+ if (!/^[0-9]+$/.test(t)) throw bad();
5449
+ const n = parseInt(t, 10);
5450
+ if (n > MAX_COUNT) throw new PatternError("invalid_pattern", `counts go up to ${MAX_COUNT}`);
5451
+ return n;
5452
+ };
5453
+ const sep = body.search(/[,;]/);
5454
+ if (sep < 0) {
5455
+ const n = num(body);
5456
+ if (n === null) throw bad();
5457
+ return { min: n, max: n };
5458
+ }
5459
+ const a = num(body.slice(0, sep)) ?? 0;
5460
+ const b = num(body.slice(sep + 1));
5461
+ if (b !== null && b < a) throw bad();
5462
+ return { min: a, max: b ?? -1 };
5463
+ }
5464
+ function parseClass(inner) {
5465
+ let negated = false;
5466
+ if (inner[0] === "!") {
5467
+ negated = true;
5468
+ inner = inner.slice(1);
5469
+ }
5470
+ if (inner.length === 0) throw new PatternError("invalid_pattern", "[ ] needs at least one character");
5471
+ const singles = /* @__PURE__ */ new Set();
5472
+ const ranges = [];
5473
+ let i = 0;
5474
+ while (i < inner.length) {
5475
+ let c = inner[i];
5476
+ if (c === "\\" && i + 1 < inner.length) c = inner[++i];
5477
+ i++;
5478
+ if (inner[i] === "-" && i + 1 < inner.length) {
5479
+ const hi = inner[i + 1];
5480
+ if (cpOf(hi) < cpOf(c)) throw new PatternError("invalid_pattern", `[${c}-${hi}] is not in ascending order`);
5481
+ ranges.push([cpOf(c), cpOf(hi)]);
5482
+ i += 2;
5483
+ } else {
5484
+ singles.add(cpOf(c));
5485
+ }
5486
+ }
5487
+ const inSet = (cp) => singles.has(cp) || ranges.some(([lo, hi]) => cp >= lo && cp <= hi);
5488
+ return negated ? (cp) => cp !== PARA && !inSet(cp) : (cp) => inSet(cp);
5489
+ }
5490
+ function parseWildcards(query) {
5491
+ const chars = toChars(query);
5492
+ const stack = [{ items: [], group: 0 }];
5493
+ let groups = 0;
5494
+ let spans = false;
5495
+ const top = () => stack[stack.length - 1].items;
5496
+ const quantify = (min, max, what) => {
5497
+ const items = top();
5498
+ const last = items[items.length - 1];
5499
+ if (!last || last.k === "assert" || last.k === "rep") {
5500
+ throw new PatternError("invalid_pattern", `${what} needs something to repeat before it`);
5501
+ }
5502
+ items[items.length - 1] = { k: "rep", body: last, min, max, lazy: false };
5503
+ };
5504
+ let i = 0;
5505
+ while (i < chars.length) {
5506
+ const c = chars[i++];
5507
+ switch (c) {
5508
+ case "?":
5509
+ top().push(charNode(ANY));
5510
+ break;
5511
+ case "*":
5512
+ top().push(star(charNode(ANY), true));
5513
+ break;
5514
+ case "@":
5515
+ quantify(1, -1, "@");
5516
+ break;
5517
+ case "<":
5518
+ top().push({ k: "assert", kind: "wordStart" });
5519
+ break;
5520
+ case ">":
5521
+ top().push({ k: "assert", kind: "wordEnd" });
5522
+ break;
5523
+ case "(":
5524
+ stack.push({ items: [], group: ++groups });
5525
+ break;
5526
+ case ")": {
5527
+ if (stack.length === 1) throw new PatternError("invalid_pattern", "a ) has no opening (");
5528
+ const frame = stack.pop();
5529
+ top().push({ k: "group", index: frame.group, body: { k: "cat", items: frame.items } });
5530
+ break;
5531
+ }
5532
+ case "{": {
5533
+ const end = chars.indexOf("}", i);
5534
+ if (end < 0) throw new PatternError("invalid_pattern", "a { needs a closing }");
5535
+ const { min, max } = parseCount(chars.slice(i, end).join(""));
5536
+ quantify(min, max, `{${chars.slice(i, end).join("")}}`);
5537
+ i = end + 1;
5538
+ break;
5539
+ }
5540
+ case "[": {
5541
+ const end = chars.indexOf("]", i);
5542
+ if (end < 0) throw new PatternError("invalid_pattern", "a [ needs a closing ]");
5543
+ top().push(charNode(parseClass(chars.slice(i, end))));
5544
+ i = end + 1;
5545
+ break;
5546
+ }
5547
+ case "\\": {
5548
+ if (i >= chars.length) {
5549
+ top().push(exact(92));
5550
+ } else if (/[0-9]/.test(chars[i])) {
5551
+ throw new PatternError("invalid_pattern", "back-references (\\1) work in Replace with, not in Find what");
5552
+ } else {
5553
+ top().push(exact(cpOf(chars[i++])));
5554
+ }
5555
+ break;
5556
+ }
5557
+ case "^": {
5558
+ if (i >= chars.length) {
5559
+ top().push(exact(94));
5560
+ break;
5561
+ }
5562
+ const n = chars[i];
5563
+ const code = findCode(n);
5564
+ if (code) {
5565
+ if (n === "p") spans = true;
5566
+ top().push(code);
5567
+ i++;
5568
+ break;
5569
+ }
5570
+ const num = numericCode(chars, i);
5571
+ if (num) {
5572
+ if (num.cp === PARA) spans = true;
5573
+ top().push(exact(num.cp));
5574
+ i += num.used;
5575
+ } else {
5576
+ top().push(exact(94));
5577
+ }
5578
+ break;
5579
+ }
5580
+ default:
5581
+ top().push(exact(cpOf(c)));
5582
+ }
5583
+ }
5584
+ if (stack.length > 1) throw new PatternError("invalid_pattern", "a ( needs a closing )");
5585
+ return { node: { k: "cat", items: stack[0].items }, spans, groups };
5586
+ }
5587
+ function compileProgram(node) {
5588
+ const prog = [];
5589
+ const push = (inst) => {
5590
+ if (prog.length >= MAX_PROGRAM_SIZE) {
5591
+ throw new PatternError("too_complex", "the pattern is too complex (too many repeats)");
5592
+ }
5593
+ prog.push(inst);
5594
+ return prog.length - 1;
5595
+ };
5596
+ const emit = (n) => {
5597
+ switch (n.k) {
5598
+ case "char":
5599
+ push({ op: 0 /* Char */, test: n.test });
5600
+ return;
5601
+ case "cat":
5602
+ n.items.forEach(emit);
5603
+ return;
5604
+ case "group":
5605
+ push({ op: 3 /* Save */, n: 2 * n.index });
5606
+ emit(n.body);
5607
+ push({ op: 3 /* Save */, n: 2 * n.index + 1 });
5608
+ return;
5609
+ case "assert":
5610
+ push({ op: 4 /* Assert */, kind: n.kind });
5611
+ return;
5612
+ case "rep": {
5613
+ for (let k = 0; k < n.min; k++) emit(n.body);
5614
+ if (n.max < 0) {
5615
+ const split = push({ op: 1 /* Split */, x: 0, y: 0 });
5616
+ emit(n.body);
5617
+ push({ op: 2 /* Jmp */, x: split });
5618
+ const exit2 = prog.length;
5619
+ const inst = prog[split];
5620
+ inst.x = n.lazy ? exit2 : split + 1;
5621
+ inst.y = n.lazy ? split + 1 : exit2;
5622
+ return;
5623
+ }
5624
+ const splits = [];
5625
+ for (let k = n.min; k < n.max; k++) {
5626
+ splits.push(push({ op: 1 /* Split */, x: 0, y: 0 }));
5627
+ emit(n.body);
5628
+ }
5629
+ const exit = prog.length;
5630
+ for (const s of splits) {
5631
+ const inst = prog[s];
5632
+ inst.x = n.lazy ? exit : s + 1;
5633
+ inst.y = n.lazy ? s + 1 : exit;
5634
+ }
5635
+ return;
5636
+ }
5637
+ }
5638
+ };
5639
+ push({ op: 3 /* Save */, n: 0 });
5640
+ emit(node);
5641
+ push({ op: 3 /* Save */, n: 1 });
5642
+ push({ op: 5 /* Match */ });
5643
+ return prog;
5644
+ }
5645
+ function checkAssert(kind, hay, pos) {
5646
+ const before = isWordChar(cpBefore(hay, pos));
5647
+ const after = isWordChar(cpAt(hay, pos));
5648
+ switch (kind) {
5649
+ case "boundary":
5650
+ return before !== after;
5651
+ case "wordStart":
5652
+ return !before && after;
5653
+ case "wordEnd":
5654
+ return before && !after;
5655
+ }
5656
+ }
5657
+ function pikeExec(prog, groupCount, caseInsensitive, hay, start2, end, budget) {
5658
+ const ncap = 2 * (groupCount + 1);
5659
+ const mark = new Int32Array(prog.length);
5660
+ let gen = 1;
5661
+ let clistPc = [];
5662
+ let clistCaps = [];
5663
+ let nlistPc = [];
5664
+ let nlistCaps = [];
5665
+ const stackPc = [];
5666
+ const stackCaps = [];
5667
+ let matched = null;
5668
+ const initial = new Int32Array(ncap).fill(-1);
5669
+ const add = (listPc, listCaps, pc0, caps0, pos) => {
5670
+ stackPc.push(pc0);
5671
+ stackCaps.push(caps0);
5672
+ while (stackPc.length) {
5673
+ const pc = stackPc.pop();
5674
+ const caps = stackCaps.pop();
5675
+ if (mark[pc] === gen) continue;
5676
+ mark[pc] = gen;
5677
+ const inst = prog[pc];
5678
+ switch (inst.op) {
5679
+ case 2 /* Jmp */:
5680
+ stackPc.push(inst.x);
5681
+ stackCaps.push(caps);
5682
+ break;
5683
+ case 1 /* Split */:
5684
+ stackPc.push(inst.y, inst.x);
5685
+ stackCaps.push(caps, caps);
5686
+ break;
5687
+ case 3 /* Save */: {
5688
+ const next = caps.slice();
5689
+ next[inst.n] = pos;
5690
+ stackPc.push(pc + 1);
5691
+ stackCaps.push(next);
5692
+ break;
5693
+ }
5694
+ case 4 /* Assert */:
5695
+ if (checkAssert(inst.kind, hay, pos)) {
5696
+ stackPc.push(pc + 1);
5697
+ stackCaps.push(caps);
5698
+ }
5699
+ break;
5700
+ default:
5701
+ listPc.push(pc);
5702
+ listCaps.push(caps);
5703
+ }
5704
+ }
5705
+ };
5706
+ let i = start2;
5707
+ if (budget.steps <= 0 || now() > budget.deadline) {
5708
+ budget.exhausted = true;
5709
+ return "budget";
5710
+ }
5711
+ let steps = 0;
5712
+ for (; ; ) {
5713
+ if (!matched) add(clistPc, clistCaps, 0, initial, i);
5714
+ const cp = i < end ? hay.codePointAt(i) : -1;
5715
+ const width = cp > 65535 ? 2 : 1;
5716
+ if (clistPc.length === 0) {
5717
+ if (matched || i >= end) break;
5718
+ gen++;
5719
+ i += width;
5720
+ continue;
5721
+ }
5722
+ const folded = cp >= 0 && caseInsensitive ? foldCodePoint(cp) : cp;
5723
+ gen++;
5724
+ nlistPc = [];
5725
+ nlistCaps = [];
5726
+ for (let t = 0; t < clistPc.length; t++) {
5727
+ if (++steps >= 4096) {
5728
+ budget.steps -= steps;
5729
+ steps = 0;
5730
+ if (budget.steps <= 0 || now() > budget.deadline) {
5731
+ budget.exhausted = true;
5732
+ return "budget";
5733
+ }
5734
+ }
5735
+ const inst = prog[clistPc[t]];
5736
+ if (inst.op === 0 /* Char */) {
5737
+ if (cp >= 0 && inst.test(cp, folded)) add(nlistPc, nlistCaps, clistPc[t] + 1, clistCaps[t], i + width);
5738
+ } else if (inst.op === 5 /* Match */) {
5739
+ matched = clistCaps[t];
5740
+ break;
5741
+ }
5742
+ }
5743
+ clistPc = nlistPc;
5744
+ clistCaps = nlistCaps;
5745
+ if (i >= end) break;
5746
+ i += width;
5747
+ }
5748
+ budget.steps -= steps;
5749
+ if (!matched) return null;
5750
+ const groups = [];
5751
+ for (let g = 0; g <= groupCount; g++) {
5752
+ const a = matched[2 * g];
5753
+ const b = matched[2 * g + 1];
5754
+ groups.push(a >= 0 && b >= 0 ? hay.slice(a, b) : void 0);
5755
+ }
5756
+ return { start: matched[0], end: matched[1], groups };
5757
+ }
5758
+ var WORD_CLASS = "[\\p{L}\\p{M}\\p{Nd}\\p{Pc}]";
5759
+ var REGEX_BOUNDARY = `(?:(?<=${WORD_CLASS})(?!${WORD_CLASS})|(?<!${WORD_CLASS})(?=${WORD_CLASS}))`;
5760
+ function hasNestedRepeat(source) {
5761
+ const quantifierAt = (i) => {
5762
+ const c = source[i];
5763
+ if (c === "*" || c === "+") return { repeats: true, many: true };
5764
+ if (c === "{") {
5765
+ const m = /^\{(\d*)(,?)(\d*)\}/.exec(source.slice(i));
5766
+ if (m) {
5767
+ const max = m[2] ? m[3] ? Number(m[3]) : Infinity : Number(m[1]);
5768
+ return { repeats: max > 1, many: max > 1 };
5769
+ }
5770
+ }
5771
+ return { repeats: false, many: false };
5772
+ };
5773
+ const stack = [];
5774
+ let inClass = false;
5775
+ for (let i = 0; i < source.length; i++) {
5776
+ const c = source[i];
5777
+ if (c === "\\") {
5778
+ i++;
5779
+ continue;
5780
+ }
5781
+ if (inClass) {
5782
+ if (c === "]") inClass = false;
5783
+ continue;
5784
+ }
5785
+ if (c === "[") {
5786
+ inClass = true;
5787
+ } else if (c === "(") {
5788
+ stack.push(false);
5789
+ } else if (c === ")") {
5790
+ const inner = stack.pop() ?? false;
5791
+ const q = quantifierAt(i + 1);
5792
+ if (inner && q.many) return true;
5793
+ if (stack.length && (inner || q.repeats)) stack[stack.length - 1] = true;
5794
+ } else if (stack.length && quantifierAt(i).repeats) {
5795
+ stack[stack.length - 1] = true;
5796
+ }
5797
+ }
5798
+ return false;
5799
+ }
5800
+ function compileRegex(query, o) {
5801
+ if (hasNestedRepeat(query)) {
5802
+ throw new PatternError(
5803
+ "too_complex",
5804
+ "a repeated group containing a repeat, like (a+)+, can take exponential time; rewrite it without nesting"
5805
+ );
5806
+ }
5807
+ let source = query;
5808
+ if (o.wholeWord || o.matchPrefix && o.matchSuffix) source = `${REGEX_BOUNDARY}(?:${query})${REGEX_BOUNDARY}`;
5809
+ else if (o.matchPrefix) source = `${REGEX_BOUNDARY}(?:${query})`;
5810
+ else if (o.matchSuffix) source = `(?:${query})${REGEX_BOUNDARY}`;
5811
+ let re;
5812
+ try {
5813
+ re = new RegExp(source, o.matchCase ? "gu" : "giu");
5814
+ } catch (error) {
5815
+ throw new PatternError("invalid_pattern", `bad pattern: ${error instanceof Error ? error.message : String(error)}`);
5816
+ }
5817
+ let slicedFor = null;
5818
+ return {
5819
+ mode: "regex",
5820
+ spansParagraphs: false,
5821
+ caseInsensitive: !o.matchCase,
5822
+ groupCount: 0,
5823
+ exec(hay, start2, end, budget) {
5824
+ if (now() > budget.deadline) {
5825
+ budget.exhausted = true;
5826
+ return "budget";
5827
+ }
5828
+ let text = hay;
5829
+ if (end < hay.length) {
5830
+ if (!slicedFor || slicedFor.hay !== hay || slicedFor.end !== end) {
5831
+ slicedFor = { hay, end, text: hay.slice(0, end) };
5832
+ }
5833
+ text = slicedFor.text;
5834
+ }
5835
+ re.lastIndex = start2;
5836
+ const m = re.exec(text);
5837
+ if (!m) return null;
5838
+ return { start: m.index, end: m.index + m[0].length, groups: Array.from(m) };
5839
+ }
5840
+ };
5841
+ }
5842
+ function compileFindPattern(query, options = {}) {
5843
+ try {
5844
+ if (Array.from(query).length > MAX_FIND_PATTERN_LENGTH) {
5845
+ throw new PatternError("too_long", `the Find what text is longer than ${MAX_FIND_PATTERN_LENGTH} characters`);
5846
+ }
5847
+ if (options.regex) return { ok: true, pattern: compileRegex(query, options) };
5848
+ const wildcards = !!options.wildcards && !options.literal;
5849
+ const caseInsensitive = !options.matchCase && !wildcards;
5850
+ let node;
5851
+ let spans;
5852
+ let groups = 0;
5853
+ if (wildcards) {
5854
+ ({ node, spans, groups } = parseWildcards(query));
5855
+ } else {
5856
+ ({ node, spans } = parseSpecial(query, options, caseInsensitive));
5857
+ const before = options.wholeWord || options.matchPrefix;
5858
+ const after = options.wholeWord || options.matchSuffix;
5859
+ if (before || after) {
5860
+ const items = [];
5861
+ if (before) items.push({ k: "assert", kind: "boundary" });
5862
+ items.push(node);
5863
+ if (after) items.push({ k: "assert", kind: "boundary" });
5864
+ node = { k: "cat", items };
5865
+ }
5866
+ }
5867
+ const prog = compileProgram(node);
5868
+ return {
5869
+ ok: true,
5870
+ pattern: {
5871
+ mode: wildcards ? "wildcards" : "special",
5872
+ spansParagraphs: spans,
5873
+ caseInsensitive,
5874
+ groupCount: groups,
5875
+ exec: (hay, start2, end, budget) => pikeExec(prog, groups, caseInsensitive, hay, start2, end, budget)
5876
+ }
5877
+ };
5878
+ } catch (error) {
5879
+ if (error instanceof PatternError) return { ok: false, error: { code: error.code, message: error.message } };
5880
+ return { ok: false, error: { code: "invalid_pattern", message: error instanceof Error ? error.message : String(error) } };
5881
+ }
5882
+ }
5883
+ function findAllMatches(pattern, hay, options = {}) {
5884
+ const budget = options.budget ?? createSearchBudget();
5885
+ const maxMatches = options.maxMatches ?? 1e4;
5886
+ const cuts = [...options.cuts ?? [], hay.length].sort((a, b) => a - b);
5887
+ const matches = [];
5888
+ let from = 0;
5889
+ for (const cut of cuts) {
5890
+ if (cut <= from) continue;
5891
+ let pos = from;
5892
+ from = cut;
5893
+ for (; ; ) {
5894
+ const m = pattern.exec(hay, pos, cut, budget);
5895
+ if (m === "budget") return { matches, truncated: true };
5896
+ if (!m) break;
5897
+ const empty = m.end === m.start;
5898
+ const next = empty ? m.end + (cpAt(hay, m.end) > 65535 ? 2 : 1) : m.end;
5899
+ if (next > cut) break;
5900
+ pos = next;
5901
+ if (empty) continue;
5902
+ matches.push(m);
5903
+ if (matches.length >= maxMatches) return { matches, truncated: true };
5904
+ }
5905
+ }
5906
+ return { matches, truncated: false };
5907
+ }
5908
+ function parseReplacement(replacement, options = {}) {
5909
+ if (options.literal || options.regex) return replacement ? [{ type: "text", text: replacement }] : [];
5910
+ const chars = toChars(replacement);
5911
+ const out = [];
5912
+ let cur = "";
5913
+ const flush = () => {
5914
+ if (cur) out.push({ type: "text", text: cur });
5915
+ cur = "";
5916
+ };
5917
+ let i = 0;
5918
+ while (i < chars.length) {
5919
+ const c = chars[i++];
5920
+ if (c === "\\" && options.wildcards && i < chars.length) {
5921
+ const d = chars[i];
5922
+ if (/[1-9]/.test(d)) {
5923
+ flush();
5924
+ out.push({ type: "group", index: Number(d) });
5925
+ } else {
5926
+ cur += d;
5927
+ }
5928
+ i++;
5929
+ continue;
5930
+ }
5931
+ if (c === "^" && i < chars.length) {
5932
+ const n = chars[i];
5933
+ if (n === "&" || n === "c") {
5934
+ flush();
5935
+ out.push(n === "&" ? { type: "found" } : { type: "clipboard" });
5936
+ i++;
5937
+ continue;
5938
+ }
5939
+ const code = replaceCode(n);
5940
+ if (code !== null) {
5941
+ cur += code;
5942
+ i++;
5943
+ continue;
5944
+ }
5945
+ const num = numericCode(chars, i);
5946
+ if (num) {
5947
+ cur += String.fromCodePoint(num.cp);
5948
+ i += num.used;
5949
+ continue;
5950
+ }
5951
+ }
5952
+ cur += c;
5953
+ }
5954
+ flush();
5955
+ return out;
5956
+ }
5957
+ function expandReplacement(pieces, match, clipboardText = "") {
5958
+ let out = "";
5959
+ for (const piece of pieces) {
5960
+ switch (piece.type) {
5961
+ case "text":
5962
+ out += piece.text;
5963
+ break;
5964
+ case "found":
5965
+ out += match.groups[0] ?? "";
5966
+ break;
5967
+ case "group":
5968
+ out += match.groups[piece.index] ?? "";
5969
+ break;
5970
+ case "clipboard":
5971
+ out += clipboardText.replace(/\r\n/g, "\r").replace(/\n/g, "\r");
5972
+ break;
5973
+ }
5974
+ }
5975
+ return out;
5976
+ }
5977
+
5978
+ // src/extensions/find-replace/search.ts
5979
+ var DELETION_MARK = "deletion";
5980
+ var DROPPED_REPLACEMENT_MARKS = /* @__PURE__ */ new Set([DELETION_MARK, "formatChange"]);
5981
+ var OBJECT_CHAR = "\uFFFC";
5982
+ function searchDocument(doc, query, options = {}, searchOptions = {}) {
5983
+ if (!query) return { matches: [], truncated: false, error: null };
5984
+ const compiled = compileFindPattern(query, options);
5985
+ if (!compiled.ok) return { matches: [], truncated: false, error: compiled.error };
5986
+ const pattern = compiled.pattern;
5987
+ const pieces = parseReplacement(searchOptions.replacement ?? "", options);
5988
+ const budget = createSearchBudget({ timeLimitMs: searchOptions.timeLimitMs });
5989
+ const maxMatches = searchOptions.maxMatches ?? 1e4;
5990
+ const blocks = [];
5991
+ doc.descendants((node, pos, parent, index) => {
5992
+ if (!node.isTextblock) return true;
5993
+ blocks.push({ node, pos, parent, index });
5994
+ return false;
5995
+ });
5996
+ const chunks = [];
5997
+ blocks.forEach((block, i) => {
5998
+ const prev = blocks[i - 1];
5999
+ const joins = pattern.spansParagraphs && prev && prev.parent === block.parent && prev.index + 1 === block.index;
6000
+ if (joins) chunks[chunks.length - 1].push(block);
6001
+ else chunks.push([block]);
6002
+ });
6003
+ const matches = [];
6004
+ let truncated = false;
6005
+ for (const chunk of chunks) {
6006
+ let hay = "";
6007
+ const posOf = [];
6008
+ const endOf = [];
6009
+ const cuts = [];
6010
+ chunk.forEach((block, k) => {
6011
+ const contentStart = block.pos + 1;
6012
+ block.node.forEach((child, offset) => {
6013
+ const at = contentStart + offset;
6014
+ if (child.marks.some((m) => m.type.name === DELETION_MARK)) {
6015
+ if (cuts[cuts.length - 1] !== hay.length) cuts.push(hay.length);
6016
+ return;
6017
+ }
6018
+ if (child.isText) {
6019
+ const text = child.text ?? "";
6020
+ for (let j = 0; j < text.length; j++) {
6021
+ posOf.push(at + j);
6022
+ endOf.push(at + j + 1);
6023
+ }
6024
+ hay += text;
6025
+ } else {
6026
+ posOf.push(at);
6027
+ endOf.push(at + child.nodeSize);
6028
+ hay += child.type.name === "hardBreak" ? "\n" : OBJECT_CHAR;
6029
+ }
6030
+ });
6031
+ const next = chunk[k + 1];
6032
+ if (next) {
6033
+ posOf.push(contentStart + block.node.content.size);
6034
+ endOf.push(next.pos + 1);
6035
+ hay += FIND_PARAGRAPH_MARK;
6036
+ }
6037
+ });
6038
+ if (!hay) continue;
6039
+ const result = findAllMatches(pattern, hay, {
6040
+ cuts,
6041
+ budget,
6042
+ maxMatches: maxMatches - matches.length
6043
+ });
6044
+ for (const m of result.matches) {
6045
+ matches.push({
6046
+ from: posOf[m.start],
6047
+ to: endOf[m.end - 1],
6048
+ text: m.groups[0] ?? hay.slice(m.start, m.end),
6049
+ replacement: expandReplacement(pieces, m, searchOptions.clipboardText ?? "")
6050
+ });
6051
+ }
6052
+ if (result.truncated) {
6053
+ truncated = true;
6054
+ break;
6055
+ }
6056
+ }
6057
+ return { matches, truncated, error: null };
6058
+ }
6059
+ function replacementMarks(doc, from, to) {
6060
+ const $from = doc.resolve(from);
6061
+ const node = from < to ? $from.nodeAfter : null;
6062
+ const marks = node ? node.marks : $from.marks();
6063
+ return marks.filter((m) => !DROPPED_REPLACEMENT_MARKS.has(m.type.name));
6064
+ }
6065
+ function inlineContent(schema, text, marks) {
6066
+ const nodes = [];
6067
+ const hardBreak = schema.nodes.hardBreak;
6068
+ const parts = hardBreak ? text.split("\n") : [text];
6069
+ parts.forEach((part, i) => {
6070
+ if (i > 0) nodes.push(hardBreak.create(null, null, marks));
6071
+ if (part) nodes.push(schema.text(part, marks));
6072
+ });
6073
+ return nodes;
6074
+ }
6075
+ function applyReplacements(tr, matches) {
6076
+ const ends = new Array(matches.length);
6077
+ const schema = tr.doc.type.schema;
6078
+ for (let i = matches.length - 1; i >= 0; i--) {
6079
+ const { from, to, replacement } = matches[i];
6080
+ const marks = replacementMarks(tr.doc, from, to);
6081
+ const parts = replacement.split(/[\r\u2029]/);
6082
+ const stepsBefore = tr.steps.length;
6083
+ const first = inlineContent(schema, parts[0], marks);
6084
+ if (first.length) tr.replaceWith(from, to, first);
6085
+ else if (to > from) tr.delete(from, to);
6086
+ let pos = tr.mapping.slice(stepsBefore).map(to, 1);
6087
+ for (let k = 1; k < parts.length; k++) {
6088
+ tr.split(pos);
6089
+ pos += 2;
6090
+ const content = inlineContent(schema, parts[k], marks);
6091
+ if (content.length) {
6092
+ tr.insert(pos, content);
6093
+ pos += content.reduce((size, node) => size + node.nodeSize, 0);
6094
+ }
6095
+ }
6096
+ const map = tr.mapping.slice(stepsBefore);
6097
+ for (let j = i + 1; j < matches.length; j++) ends[j] = map.map(ends[j], 1);
6098
+ ends[i] = pos;
6099
+ }
6100
+ return ends;
6101
+ }
6102
+
6103
+ // src/extensions/find-replace/extension.ts
6104
+ var EMPTY_OPTIONS = Object.freeze({});
6105
+ var EMPTY_FIND_REPLACE_SNAPSHOT = Object.freeze({
6106
+ open: false,
6107
+ mode: "find",
6108
+ query: "",
6109
+ replacement: "",
6110
+ options: EMPTY_OPTIONS,
6111
+ matches: Object.freeze([]),
6112
+ currentIndex: -1,
6113
+ error: null,
6114
+ truncated: false,
6115
+ lastReplaceCount: null,
6116
+ focusRequest: 0
6117
+ });
6118
+ var FindReplaceStore = class {
6119
+ snapshot = EMPTY_FIND_REPLACE_SNAPSHOT;
6120
+ listeners = /* @__PURE__ */ new Set();
6121
+ subscribe = (listener) => {
6122
+ this.listeners.add(listener);
6123
+ listener(this.snapshot);
6124
+ return () => {
6125
+ this.listeners.delete(listener);
6126
+ };
6127
+ };
6128
+ getSnapshot = () => this.snapshot;
6129
+ /** @internal Called by the extension's plugin view. */
6130
+ set(snapshot) {
6131
+ if (snapshot === this.snapshot) return;
6132
+ this.snapshot = snapshot;
6133
+ this.listeners.forEach((listener) => {
6134
+ try {
6135
+ listener(snapshot);
6136
+ } catch (err) {
6137
+ console.error("[FindReplaceStore] Error in listener:", err);
6138
+ }
6139
+ });
6140
+ }
6141
+ };
6142
+ var findReplacePluginKey = new PluginKey11("findReplace");
6143
+ function getFindReplaceState(source) {
6144
+ const state = source?.state ?? source;
6145
+ if (!state || typeof state.plugins === "undefined") return null;
6146
+ const plugin = findReplacePluginKey.getState(state);
6147
+ return plugin ? toSnapshot(plugin) : null;
6148
+ }
6149
+ function getFindReplaceStore(editor) {
6150
+ return editor?.storage?.findReplace?.store ?? null;
6151
+ }
6152
+ var snapshotCache = /* @__PURE__ */ new WeakMap();
6153
+ function toSnapshot(s) {
6154
+ let snapshot = snapshotCache.get(s);
6155
+ if (!snapshot) {
6156
+ snapshot = Object.freeze({
6157
+ open: s.open,
6158
+ mode: s.mode,
6159
+ query: s.query,
6160
+ replacement: s.replacement,
6161
+ options: s.options,
6162
+ matches: s.active ? s.matches : EMPTY_FIND_REPLACE_SNAPSHOT.matches,
6163
+ currentIndex: s.active ? s.currentIndex : -1,
6164
+ error: s.error,
6165
+ truncated: s.truncated,
6166
+ lastReplaceCount: s.lastReplaceCount,
6167
+ focusRequest: s.focusRequest
6168
+ });
6169
+ snapshotCache.set(s, snapshot);
6170
+ }
6171
+ return snapshot;
6172
+ }
6173
+ var FIND_OPTION_TOGGLES = Object.freeze([
6174
+ { key: "matchCase", label: "Match case", short: "Aa", advanced: false },
6175
+ { key: "wholeWord", label: "Whole words only", short: "ab", advanced: false },
6176
+ { key: "wildcards", label: "Use wildcards", short: "*?", advanced: false },
6177
+ { key: "regex", label: "Regular expression", short: ".*", advanced: false },
6178
+ { key: "matchPrefix", label: "Match prefix", short: "ab-", advanced: true },
6179
+ { key: "matchSuffix", label: "Match suffix", short: "-ab", advanced: true },
6180
+ { key: "ignorePunctuation", label: "Ignore punctuation", short: ".,", advanced: true },
6181
+ { key: "ignoreWhitespace", label: "Ignore white space", short: "_", advanced: true },
6182
+ { key: "literal", label: "No special characters (^)", short: "^", advanced: true }
6183
+ ]);
6184
+ function formatFindStatus(s) {
6185
+ if (!s.query) return "";
6186
+ if (s.error) return s.error.message;
6187
+ const n = s.matches.length;
6188
+ if (n === 0) return "No results";
6189
+ const total = s.truncated ? `${n}+` : `${n}`;
6190
+ return s.currentIndex >= 0 ? `${s.currentIndex + 1} of ${total}` : `${total} results`;
6191
+ }
6192
+ function indexFrom(matches, pos) {
6193
+ if (!matches.length) return -1;
6194
+ const i = matches.findIndex((m) => m.from >= pos);
6195
+ return i < 0 ? 0 : i;
6196
+ }
6197
+ function selectedQuery(state, maxLength) {
6198
+ const { from, to, $from, $to } = state.selection;
6199
+ if (from === to || !$from.sameParent($to)) return void 0;
6200
+ const text = state.doc.textBetween(from, to, "", "");
6201
+ return text && text.length <= maxLength && !/[\r\n]/.test(text) ? text : void 0;
6202
+ }
6203
+ var FindReplace = Extension12.create({
6204
+ name: "findReplace",
6205
+ addOptions() {
6206
+ return {
6207
+ shortcuts: true,
6208
+ matchClass: "pixerate-find-match",
6209
+ currentMatchClass: "pixerate-find-match-current",
6210
+ timeLimitMs: 250,
6211
+ maxMatches: 1e4,
6212
+ getClipboardText: () => "",
6213
+ maxPrefillLength: 256
6214
+ };
6215
+ },
6216
+ addStorage() {
6217
+ return { store: new FindReplaceStore() };
6218
+ },
6219
+ addCommands() {
6220
+ const meta = (tr, value) => tr.setMeta(findReplacePluginKey, value);
6221
+ const current = (state) => findReplacePluginKey.getState(state);
6222
+ const maxPrefill = () => this.options.maxPrefillLength;
6223
+ const select = (tr, match) => {
6224
+ tr.setSelection(TextSelection7.create(tr.doc, match.from, match.to)).scrollIntoView();
6225
+ };
6226
+ return {
6227
+ setSearch: (params) => ({ tr, state, dispatch }) => {
6228
+ if (!current(state)) return false;
6229
+ if (dispatch) meta(tr, { type: "set", params, anchor: state.selection.from });
6230
+ return true;
6231
+ },
6232
+ openFindReplace: (params = {}) => ({ tr, state, dispatch }) => {
6233
+ if (!current(state)) return false;
6234
+ if (dispatch) {
6235
+ meta(tr, {
6236
+ type: "open",
6237
+ mode: params.mode ?? "find",
6238
+ query: params.query ?? selectedQuery(state, maxPrefill()),
6239
+ anchor: state.selection.from
6240
+ });
6241
+ }
6242
+ return true;
6243
+ },
6244
+ closeFindReplace: () => ({ tr, state, dispatch }) => {
6245
+ if (!current(state)) return false;
6246
+ if (dispatch) meta(tr, { type: "close" });
6247
+ return true;
6248
+ },
6249
+ clearSearch: () => ({ tr, state, dispatch }) => {
6250
+ if (!current(state)) return false;
6251
+ if (dispatch) meta(tr, { type: "clear" });
6252
+ return true;
6253
+ },
6254
+ findNext: () => ({ tr, state, dispatch }) => {
6255
+ const s = current(state);
6256
+ if (!s || !s.active || !s.matches.length) return false;
6257
+ const { from, to } = state.selection;
6258
+ const cur = s.matches[s.currentIndex];
6259
+ const onCurrent = cur && cur.from === from && cur.to === to;
6260
+ const index = onCurrent ? (s.currentIndex + 1) % s.matches.length : indexFrom(s.matches, to);
6261
+ if (dispatch) {
6262
+ meta(tr, { type: "current", index });
6263
+ select(tr, s.matches[index]);
6264
+ }
6265
+ return true;
6266
+ },
6267
+ findPrevious: () => ({ tr, state, dispatch }) => {
6268
+ const s = current(state);
6269
+ if (!s || !s.active || !s.matches.length) return false;
6270
+ const { from, to } = state.selection;
6271
+ const n = s.matches.length;
6272
+ const cur = s.matches[s.currentIndex];
6273
+ const onCurrent = cur && cur.from === from && cur.to === to;
6274
+ let index;
6275
+ if (onCurrent) {
6276
+ index = (s.currentIndex - 1 + n) % n;
6277
+ } else {
6278
+ index = -1;
6279
+ for (let i = n - 1; i >= 0; i--) {
6280
+ if (s.matches[i].to <= from) {
6281
+ index = i;
6282
+ break;
6283
+ }
6284
+ }
6285
+ if (index < 0) index = n - 1;
6286
+ }
6287
+ if (dispatch) {
6288
+ meta(tr, { type: "current", index });
6289
+ select(tr, s.matches[index]);
6290
+ }
6291
+ return true;
6292
+ },
6293
+ replaceCurrent: () => ({ tr, state, dispatch }) => {
6294
+ const s = current(state);
6295
+ if (!s || !s.active || s.currentIndex < 0 || !s.matches[s.currentIndex]) return false;
6296
+ if (dispatch) {
6297
+ closeHistory2(tr);
6298
+ const [end] = applyReplacements(tr, [s.matches[s.currentIndex]]);
6299
+ tr.setSelection(TextSelection7.create(tr.doc, end)).scrollIntoView();
6300
+ meta(tr, { type: "replaced", anchor: end, count: 1 });
6301
+ }
6302
+ return true;
6303
+ },
6304
+ replaceAll: () => ({ tr, state, dispatch }) => {
6305
+ const s = current(state);
6306
+ if (!s || !s.active || !s.matches.length) return false;
6307
+ if (dispatch) {
6308
+ closeHistory2(tr);
6309
+ const ends = applyReplacements(tr, s.matches);
6310
+ meta(tr, { type: "replaced", anchor: ends[ends.length - 1], count: s.matches.length });
6311
+ }
6312
+ return true;
6313
+ }
6314
+ };
6315
+ },
6316
+ addKeyboardShortcuts() {
6317
+ if (!this.options.shortcuts) return {};
6318
+ const open = (mode) => () => this.editor.commands.openFindReplace({ mode });
6319
+ const step = (forward) => () => {
6320
+ const s = findReplacePluginKey.getState(this.editor.state);
6321
+ if (!s?.active || !s.matches.length) return false;
6322
+ return forward ? this.editor.commands.findNext() : this.editor.commands.findPrevious();
6323
+ };
6324
+ return {
6325
+ "Mod-f": open("find"),
6326
+ "Mod-h": open("replace"),
6327
+ "Mod-Shift-h": open("replace"),
6328
+ F3: step(true),
6329
+ "Shift-F3": step(false),
6330
+ "Mod-g": step(true),
6331
+ "Mod-Shift-g": step(false)
6332
+ };
6333
+ },
6334
+ addProseMirrorPlugins() {
6335
+ const options = this.options;
6336
+ const store = this.storage.store;
6337
+ const search = (s, doc) => {
6338
+ if (!s.active || !s.query) {
6339
+ return { ...s, matches: [], currentIndex: -1, error: null, truncated: false };
6340
+ }
6341
+ const result = searchDocument(doc, s.query, s.options, {
6342
+ replacement: s.replacement,
6343
+ clipboardText: safeClipboard(options.getClipboardText),
6344
+ timeLimitMs: options.timeLimitMs,
6345
+ maxMatches: options.maxMatches
6346
+ });
6347
+ return {
6348
+ ...s,
6349
+ matches: result.matches,
6350
+ currentIndex: indexFrom(result.matches, s.anchor),
6351
+ error: result.error,
6352
+ truncated: result.truncated
6353
+ };
6354
+ };
6355
+ const decorate = (s, doc) => {
6356
+ if (!s.active || !s.matches.length) return { ...s, decorations: DecorationSet4.empty };
6357
+ const decorations = s.matches.map(
6358
+ (m, i) => Decoration4.inline(m.from, m.to, {
6359
+ class: i === s.currentIndex ? `${options.matchClass} ${options.currentMatchClass}` : options.matchClass
6360
+ })
6361
+ );
6362
+ return { ...s, decorations: DecorationSet4.create(doc, decorations) };
6363
+ };
6364
+ return [
6365
+ new Plugin14({
6366
+ key: findReplacePluginKey,
6367
+ state: {
6368
+ init: () => ({
6369
+ active: false,
6370
+ open: false,
6371
+ mode: "find",
6372
+ query: "",
6373
+ replacement: "",
6374
+ options: EMPTY_OPTIONS,
6375
+ matches: [],
6376
+ currentIndex: -1,
6377
+ anchor: 0,
6378
+ error: null,
6379
+ truncated: false,
6380
+ lastReplaceCount: null,
6381
+ focusRequest: 0,
6382
+ decorations: DecorationSet4.empty
6383
+ }),
6384
+ apply: (tr, prev, _oldState, newState) => {
6385
+ const m = tr.getMeta(findReplacePluginKey);
6386
+ if (!m && !tr.docChanged) return prev;
6387
+ let s = prev;
6388
+ let research = false;
6389
+ let redecorate = false;
6390
+ if (tr.docChanged) {
6391
+ s = { ...s, anchor: tr.mapping.map(s.anchor) };
6392
+ research = s.active;
6393
+ }
6394
+ if (m) {
6395
+ switch (m.type) {
6396
+ case "set": {
6397
+ const p = m.params;
6398
+ s = {
6399
+ ...s,
6400
+ active: true,
6401
+ query: p.query ?? s.query,
6402
+ replacement: p.replacement ?? s.replacement,
6403
+ options: p.options ? Object.freeze({ ...s.options, ...p.options }) : s.options,
6404
+ anchor: m.anchor,
6405
+ lastReplaceCount: null
6406
+ };
6407
+ research = true;
6408
+ break;
6409
+ }
6410
+ case "open":
6411
+ s = {
6412
+ ...s,
6413
+ active: true,
6414
+ open: true,
6415
+ mode: m.mode,
6416
+ query: m.query ?? s.query,
6417
+ anchor: m.anchor,
6418
+ focusRequest: s.focusRequest + 1
6419
+ };
6420
+ research = true;
6421
+ break;
6422
+ case "close":
6423
+ s = { ...s, open: false, active: false };
6424
+ research = true;
6425
+ break;
6426
+ case "clear":
6427
+ s = { ...s, active: false, query: "", lastReplaceCount: null };
6428
+ research = true;
6429
+ break;
6430
+ case "current":
6431
+ s = {
6432
+ ...s,
6433
+ currentIndex: m.index,
6434
+ anchor: s.matches[m.index]?.from ?? s.anchor
6435
+ };
6436
+ redecorate = true;
6437
+ break;
6438
+ case "replaced":
6439
+ s = { ...s, anchor: m.anchor, lastReplaceCount: m.count };
6440
+ research = true;
6441
+ break;
6442
+ }
6443
+ }
6444
+ if (research) s = search(s, newState.doc);
6445
+ if (research || redecorate) s = decorate(s, newState.doc);
6446
+ return s;
6447
+ }
6448
+ },
6449
+ props: {
6450
+ decorations: (state) => findReplacePluginKey.getState(state)?.decorations ?? DecorationSet4.empty
6451
+ },
6452
+ view: (view) => {
6453
+ const sync = () => {
6454
+ const s = findReplacePluginKey.getState(view.state);
6455
+ if (s) store.set(toSnapshot(s));
6456
+ };
6457
+ sync();
6458
+ return { update: sync };
6459
+ }
6460
+ })
6461
+ ];
6462
+ }
6463
+ });
6464
+ function safeClipboard(get) {
6465
+ try {
6466
+ return String(get() ?? "");
6467
+ } catch {
6468
+ return "";
6469
+ }
6470
+ }
6471
+
5172
6472
  // src/extensions/rich-text-preset.ts
5173
6473
  var resolveExt3 = (mod, name) => mod?.[name] || mod?.default?.[name] || mod?.default?.default || mod?.default || mod;
5174
6474
  var StarterKit = resolveExt3(_StarterKit, "StarterKit");
@@ -5325,7 +6625,8 @@ function createRichTextPreset(options = {}) {
5325
6625
  }
5326
6626
  if (options.trackChanges) {
5327
6627
  extensions2.push(
5328
- typeof options.trackChanges === "object" ? TrackChanges.configure(options.trackChanges) : TrackChanges
6628
+ typeof options.trackChanges === "object" ? TrackChanges.configure(options.trackChanges) : TrackChanges,
6629
+ DocumentCompare
5329
6630
  );
5330
6631
  }
5331
6632
  if (options.fileImport) {
@@ -5364,9 +6665,149 @@ function createRichTextPreset(options = {}) {
5364
6665
  if (options.crossReferences) {
5365
6666
  extensions2.push(CrossReference.configure(optionObject(options.crossReferences)));
5366
6667
  }
6668
+ if (options.findReplace) {
6669
+ extensions2.push(FindReplace.configure(optionObject(options.findReplace)));
6670
+ }
5367
6671
  return extensions2;
5368
6672
  }
5369
6673
 
6674
+ // src/extensions/find-replace/commands.ts
6675
+ var OPTION_KEYS = [
6676
+ "matchCase",
6677
+ "wholeWord",
6678
+ "matchPrefix",
6679
+ "matchSuffix",
6680
+ "ignorePunctuation",
6681
+ "ignoreWhitespace",
6682
+ "wildcards",
6683
+ "regex",
6684
+ "literal"
6685
+ ];
6686
+ var searchParams = (withReplacement) => ({
6687
+ type: "object",
6688
+ properties: {
6689
+ query: { type: "string", description: "Find what. Word ^ codes (^p, ^t, ^#) unless literal." },
6690
+ ...withReplacement ? {
6691
+ replacement: {
6692
+ type: "string",
6693
+ description: "Replace with. ^& is the found text; with wildcards, \\1-\\9 are groups."
6694
+ }
6695
+ } : {},
6696
+ ...Object.fromEntries(OPTION_KEYS.map((key) => [key, { type: "boolean" }]))
6697
+ },
6698
+ additionalProperties: false
6699
+ });
6700
+ function splitParams(params) {
6701
+ if (!params) return null;
6702
+ const options = {};
6703
+ for (const key of OPTION_KEYS) if (params[key] !== void 0) options[key] = params[key];
6704
+ return {
6705
+ ...params.query !== void 0 ? { query: params.query } : {},
6706
+ ...params.replacement !== void 0 ? { replacement: params.replacement } : {},
6707
+ options
6708
+ };
6709
+ }
6710
+ var usable = (editor) => !editor.isDestroyed && findReplacePluginKey.getState(editor.state) ? true : "Find and Replace is not available.";
6711
+ function createFindReplaceCommands(editor, options = {}) {
6712
+ const prefix = options.prefix ?? "findReplace.";
6713
+ const group = options.group ?? "Edit";
6714
+ const scope = options.scope ? { scope: options.scope } : {};
6715
+ const state = () => getFindReplaceState(editor);
6716
+ const hasMatches = () => {
6717
+ const ok = usable(editor);
6718
+ if (ok !== true) return ok;
6719
+ return state()?.matches.length ? true : "No matches.";
6720
+ };
6721
+ const apply = (params) => {
6722
+ const split = splitParams(params);
6723
+ if (split) editor.commands.setSearch(split);
6724
+ };
6725
+ const failIfInvalid = () => {
6726
+ const s = state();
6727
+ if (s?.error) throw new Error(s.error.message);
6728
+ };
6729
+ return [
6730
+ {
6731
+ id: `${prefix}open`,
6732
+ label: "Find",
6733
+ group,
6734
+ keywords: ["search", "find"],
6735
+ description: "Shows the find bar.",
6736
+ ...options.shortcuts ? { shortcut: "Mod+F" } : {},
6737
+ ...scope,
6738
+ enabled: () => usable(editor),
6739
+ run: () => editor.commands.openFindReplace({ mode: "find" })
6740
+ },
6741
+ {
6742
+ id: `${prefix}openReplace`,
6743
+ label: "Replace",
6744
+ group,
6745
+ keywords: ["search", "substitute"],
6746
+ description: "Shows the find bar with the replace field.",
6747
+ ...options.shortcuts ? { shortcut: "Mod+H" } : {},
6748
+ ...scope,
6749
+ enabled: () => usable(editor),
6750
+ run: () => editor.commands.openFindReplace({ mode: "replace" })
6751
+ },
6752
+ {
6753
+ id: `${prefix}find`,
6754
+ label: "Find text",
6755
+ group,
6756
+ description: "Searches the document and returns the number of matches.",
6757
+ params: searchParams(false),
6758
+ readOnly: true,
6759
+ ...scope,
6760
+ enabled: () => usable(editor),
6761
+ run: (_ctx, params) => {
6762
+ apply(params);
6763
+ failIfInvalid();
6764
+ const s = state();
6765
+ return {
6766
+ count: s?.matches.length ?? 0,
6767
+ truncated: s?.truncated ?? false,
6768
+ matches: (s?.matches ?? []).slice(0, 200).map(({ from, to, text }) => ({ from, to, text }))
6769
+ };
6770
+ }
6771
+ },
6772
+ {
6773
+ id: `${prefix}next`,
6774
+ label: "Find next",
6775
+ group,
6776
+ ...scope,
6777
+ enabled: hasMatches,
6778
+ run: () => editor.commands.findNext()
6779
+ },
6780
+ {
6781
+ id: `${prefix}previous`,
6782
+ label: "Find previous",
6783
+ group,
6784
+ ...scope,
6785
+ enabled: hasMatches,
6786
+ run: () => editor.commands.findPrevious()
6787
+ },
6788
+ {
6789
+ id: `${prefix}replaceAll`,
6790
+ label: "Replace all",
6791
+ group,
6792
+ description: "Replaces every match (one undo step). Tracked when Track Changes is on.",
6793
+ params: searchParams(true),
6794
+ ...scope,
6795
+ enabled: (_ctx, params) => params?.query !== void 0 ? usable(editor) : hasMatches(),
6796
+ run: (_ctx, params) => {
6797
+ apply(params);
6798
+ failIfInvalid();
6799
+ const count = state()?.matches.length ?? 0;
6800
+ if (count) editor.commands.replaceAll();
6801
+ return { replaced: count };
6802
+ }
6803
+ }
6804
+ ];
6805
+ }
6806
+ function validateFindPattern(query, options = {}) {
6807
+ const result = compileFindPattern(query, options);
6808
+ return result.ok ? null : result.error;
6809
+ }
6810
+
5370
6811
  export {
5371
6812
  GradientText,
5372
6813
  SlashCommands,
@@ -5395,6 +6836,9 @@ export {
5395
6836
  getCommentStore,
5396
6837
  Comments,
5397
6838
  getCommentAuthor,
6839
+ compareInEditor,
6840
+ applyDocumentComparison,
6841
+ DocumentCompare,
5398
6842
  ImportError,
5399
6843
  createImportContext,
5400
6844
  ImportAdapterRegistry,
@@ -5467,6 +6911,26 @@ export {
5467
6911
  CrossReference,
5468
6912
  documentStructureCommandItems,
5469
6913
  getDocumentStructureCommandItems,
5470
- createRichTextPreset
6914
+ FIND_PARAGRAPH_MARK,
6915
+ MAX_FIND_PATTERN_LENGTH,
6916
+ createSearchBudget,
6917
+ foldCodePoint,
6918
+ compileFindPattern,
6919
+ findAllMatches,
6920
+ parseReplacement,
6921
+ expandReplacement,
6922
+ searchDocument,
6923
+ applyReplacements,
6924
+ EMPTY_FIND_REPLACE_SNAPSHOT,
6925
+ FindReplaceStore,
6926
+ findReplacePluginKey,
6927
+ getFindReplaceState,
6928
+ getFindReplaceStore,
6929
+ FIND_OPTION_TOGGLES,
6930
+ formatFindStatus,
6931
+ FindReplace,
6932
+ createRichTextPreset,
6933
+ createFindReplaceCommands,
6934
+ validateFindPattern
5471
6935
  };
5472
- //# sourceMappingURL=chunk-QGHGJ56O.js.map
6936
+ //# sourceMappingURL=chunk-ITBSKI26.js.map