@inkandswitch/patchwork-pkg-base 0.0.126 → 0.0.128

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.
@@ -1269,23 +1269,23 @@ var FlattenedDoc = class _FlattenedDoc {
1269
1269
  get to() {
1270
1270
  return this.from + this.text.length;
1271
1271
  }
1272
- static get(doc, from, to) {
1273
- let cached = flattened.get(doc);
1272
+ static get(doc2, from, to) {
1273
+ let cached = flattened.get(doc2);
1274
1274
  if (!cached || cached.from >= to || cached.to <= from) {
1275
- let flat = new _FlattenedDoc(from, doc.sliceString(from, to));
1276
- flattened.set(doc, flat);
1275
+ let flat = new _FlattenedDoc(from, doc2.sliceString(from, to));
1276
+ flattened.set(doc2, flat);
1277
1277
  return flat;
1278
1278
  }
1279
1279
  if (cached.from == from && cached.to == to)
1280
1280
  return cached;
1281
1281
  let { text, from: cachedFrom } = cached;
1282
1282
  if (cachedFrom > from) {
1283
- text = doc.sliceString(from, cachedFrom) + text;
1283
+ text = doc2.sliceString(from, cachedFrom) + text;
1284
1284
  cachedFrom = from;
1285
1285
  }
1286
1286
  if (cached.to < to)
1287
- text += doc.sliceString(cached.to, to);
1288
- flattened.set(doc, new _FlattenedDoc(cachedFrom, text));
1287
+ text += doc2.sliceString(cached.to, to);
1288
+ flattened.set(doc2, new _FlattenedDoc(cachedFrom, text));
1289
1289
  return new _FlattenedDoc(from, text.slice(from - cachedFrom, to - cachedFrom));
1290
1290
  }
1291
1291
  };
@@ -1511,11 +1511,11 @@ function stringCursor(spec, state, from, to) {
1511
1511
  test = wrapStringTest(spec.test, state, test);
1512
1512
  return new SearchCursor(state.doc, spec.unquoted, from, to, spec.caseSensitive ? void 0 : (x) => x.toLowerCase(), test);
1513
1513
  }
1514
- function stringWordTest(doc, categorizer) {
1514
+ function stringWordTest(doc2, categorizer) {
1515
1515
  return (from, to, buf, bufPos) => {
1516
1516
  if (bufPos > from || bufPos + buf.length < to) {
1517
1517
  bufPos = Math.max(0, from - 2);
1518
- buf = doc.sliceString(bufPos, Math.min(doc.length, to + 2));
1518
+ buf = doc2.sliceString(bufPos, Math.min(doc2.length, to + 2));
1519
1519
  }
1520
1520
  return (categorizer(charBefore(buf, from - bufPos)) != CharCategory.Word || categorizer(charAfter(buf, from - bufPos)) != CharCategory.Word) && (categorizer(charAfter(buf, to - bufPos)) != CharCategory.Word || categorizer(charBefore(buf, to - bufPos)) != CharCategory.Word);
1521
1521
  };
@@ -2066,7 +2066,7 @@ var searchExtensions = [
2066
2066
  ];
2067
2067
 
2068
2068
  // src/extensions/markdown.ts
2069
- import { EditorView as EditorView7, keymap as keymap3 } from "@codemirror/view";
2069
+ import { EditorView as EditorView9, keymap as keymap6 } from "@codemirror/view";
2070
2070
 
2071
2071
  // src/extensions/formatting.ts
2072
2072
  import { EditorSelection as EditorSelection2 } from "@codemirror/state";
@@ -2189,14 +2189,14 @@ function toggle(view, from) {
2189
2189
  var doneMark = Decoration2.mark({ class: "cm-task-done" });
2190
2190
  function build(view) {
2191
2191
  const builder = new RangeSetBuilder2();
2192
- const { doc } = view.state;
2192
+ const { doc: doc2 } = view.state;
2193
2193
  for (const { from, to } of view.visibleRanges) {
2194
2194
  syntaxTree(view.state).iterate({
2195
2195
  from,
2196
2196
  to,
2197
2197
  enter: (node) => {
2198
2198
  if (node.name !== "TaskMarker") return;
2199
- const checked = doc.sliceString(node.from + 1, node.to - 1) !== " ";
2199
+ const checked = doc2.sliceString(node.from + 1, node.to - 1) !== " ";
2200
2200
  builder.add(
2201
2201
  node.from,
2202
2202
  node.to,
@@ -2234,8 +2234,6 @@ import {
2234
2234
  ViewPlugin as ViewPlugin3,
2235
2235
  WidgetType as WidgetType2
2236
2236
  } from "@codemirror/view";
2237
- var numberMark = Decoration3.mark({ class: "cm-md-hang cm-md-hang-number" });
2238
- var quoteMark = Decoration3.mark({ class: "cm-md-hang cm-md-hang-quote" });
2239
2237
  var hidden = Decoration3.replace({});
2240
2238
  var taskMark = Decoration3.mark({ class: "cm-md-hang", inclusive: true });
2241
2239
  var HeadingLabel = class extends WidgetType2 {
@@ -2299,16 +2297,50 @@ function renderedNumber(state, mark) {
2299
2297
  }
2300
2298
  const firstMark = first.getChild("ListMark");
2301
2299
  const start = firstMark ? parseInt(state.doc.sliceString(firstMark.from, firstMark.to), 10) : 1;
2302
- return `${(Number.isNaN(start) ? 1 : start) + index}${delimiter}`;
2300
+ const n = (Number.isNaN(start) ? 1 : start) + index;
2301
+ let depth = 0;
2302
+ for (let p = item.parent?.parent; p; p = p.parent)
2303
+ if (p.name === "OrderedList") depth++;
2304
+ return `${counter(n, depth)}${delimiter}`;
2303
2305
  }
2304
- function caretLines(state) {
2305
- const lines = /* @__PURE__ */ new Set();
2306
- for (const r of state.selection.ranges) {
2307
- const first = state.doc.lineAt(r.from).number;
2308
- const last = state.doc.lineAt(r.to).number;
2309
- for (let n = first; n <= last; n++) lines.add(n);
2306
+ function counter(n, depth) {
2307
+ const style = depth % 3;
2308
+ if (style === 1 && n > 0 && n < 4e3) return roman(n);
2309
+ if (style === 2 && n > 0) return alpha(n);
2310
+ return String(n);
2311
+ }
2312
+ function roman(n) {
2313
+ const numerals = [
2314
+ [1e3, "m"],
2315
+ [900, "cm"],
2316
+ [500, "d"],
2317
+ [400, "cd"],
2318
+ [100, "c"],
2319
+ [90, "xc"],
2320
+ [50, "l"],
2321
+ [40, "xl"],
2322
+ [10, "x"],
2323
+ [9, "ix"],
2324
+ [5, "v"],
2325
+ [4, "iv"],
2326
+ [1, "i"]
2327
+ ];
2328
+ let out = "";
2329
+ for (const [value, numeral] of numerals)
2330
+ while (n >= value) {
2331
+ out += numeral;
2332
+ n -= value;
2333
+ }
2334
+ return out;
2335
+ }
2336
+ function alpha(n) {
2337
+ let out = "";
2338
+ while (n > 0) {
2339
+ n--;
2340
+ out = String.fromCharCode(97 + n % 26) + out;
2341
+ n = Math.floor(n / 26);
2310
2342
  }
2311
- return lines;
2343
+ return out;
2312
2344
  }
2313
2345
  function skipSpaces(state, pos) {
2314
2346
  const line = state.doc.lineAt(pos);
@@ -2317,8 +2349,7 @@ function skipSpaces(state, pos) {
2317
2349
  }
2318
2350
  function build2(view) {
2319
2351
  const { state } = view;
2320
- const { doc } = state;
2321
- const editing = caretLines(state);
2352
+ const { doc: doc2 } = state;
2322
2353
  const decos = [];
2323
2354
  for (const { from, to } of view.visibleRanges) {
2324
2355
  syntaxTree2(state).iterate({
@@ -2329,32 +2360,31 @@ function build2(view) {
2329
2360
  const heading = /^ATXHeading(\d)$/.exec(name);
2330
2361
  if (heading) {
2331
2362
  const mark = node.node.firstChild;
2332
- if (!mark || mark.name !== "HeaderMark" || mark.from !== node.from)
2333
- return;
2363
+ if (!mark || mark.name !== "HeaderMark") return;
2334
2364
  decos.push(
2335
2365
  Decoration3.replace({
2336
2366
  widget: new HeadingLabel(Number(heading[1]))
2337
- }).range(mark.from, skipSpaces(state, mark.to))
2367
+ }).range(doc2.lineAt(node.from).from, skipSpaces(state, mark.to))
2338
2368
  );
2339
2369
  return;
2340
2370
  }
2341
2371
  if (name === "ListMark") {
2342
2372
  const end = skipSpaces(state, node.to);
2343
- const char = doc.sliceString(node.from, node.to);
2373
+ const char = doc2.sliceString(node.from, node.to);
2344
2374
  const bullet = ["-", "+", "*"].includes(char);
2345
2375
  const task = node.node.nextSibling?.firstChild;
2346
- const isTask = bullet && task?.name === "TaskMarker" && doc.sliceString(end, task.from).trim() === "";
2376
+ const isTask = bullet && task?.name === "TaskMarker" && doc2.sliceString(end, task.from).trim() === "";
2347
2377
  if (isTask && task) {
2348
2378
  if (end > node.from) decos.push(hidden.range(node.from, end));
2349
- decos.push(taskMark.range(task.from, skipSpaces(state, task.to)));
2379
+ decos.push(taskMark.range(task.from, task.to));
2380
+ const after = skipSpaces(state, task.to);
2381
+ if (after > task.to) decos.push(hidden.range(task.to, after));
2350
2382
  return;
2351
2383
  }
2352
2384
  if (bullet) {
2353
2385
  decos.push(
2354
2386
  Decoration3.replace({ widget: new Bullet() }).range(node.from, end)
2355
2387
  );
2356
- } else if (editing.has(doc.lineAt(node.from).number)) {
2357
- decos.push(numberMark.range(node.from, end));
2358
2388
  } else {
2359
2389
  decos.push(
2360
2390
  Decoration3.replace({
@@ -2367,10 +2397,10 @@ function build2(view) {
2367
2397
  if (name === "Blockquote") {
2368
2398
  for (let p = node.node.parent; p; p = p.parent)
2369
2399
  if (p.name === "Blockquote") return;
2370
- const first = doc.lineAt(node.from).number;
2371
- const last = doc.lineAt(node.to).number;
2400
+ const first = doc2.lineAt(node.from).number;
2401
+ const last = doc2.lineAt(node.to).number;
2372
2402
  for (let n = first; n <= last; n++) {
2373
- const line = doc.line(n);
2403
+ const line = doc2.line(n);
2374
2404
  const classes = ["cm-md-quote"];
2375
2405
  if (n === first) classes.push("cm-md-quote-first");
2376
2406
  if (n === last) classes.push("cm-md-quote-last");
@@ -2381,22 +2411,17 @@ function build2(view) {
2381
2411
  return;
2382
2412
  }
2383
2413
  if (name === "QuoteMark") {
2384
- const line = doc.lineAt(node.from);
2385
- const before = doc.sliceString(line.from, node.from);
2414
+ const line = doc2.lineAt(node.from);
2415
+ const before = doc2.sliceString(line.from, node.from);
2386
2416
  if (before.trim() !== "") return;
2387
2417
  let end = node.to;
2388
2418
  for (; ; ) {
2389
2419
  const next = skipSpaces(state, end);
2390
- if (doc.sliceString(next, next + 1) !== ">") break;
2420
+ if (doc2.sliceString(next, next + 1) !== ">") break;
2391
2421
  end = next + 1;
2392
2422
  }
2393
2423
  end = skipSpaces(state, end);
2394
- decos.push(
2395
- (editing.has(line.number) ? quoteMark : hidden).range(
2396
- line.from,
2397
- end
2398
- )
2399
- );
2424
+ decos.push(hidden.range(line.from, end));
2400
2425
  }
2401
2426
  }
2402
2427
  });
@@ -2410,7 +2435,7 @@ var marginPlugin = ViewPlugin3.fromClass(
2410
2435
  this.decorations = build2(view);
2411
2436
  }
2412
2437
  update(update) {
2413
- if (update.docChanged || update.selectionSet || update.viewportChanged || syntaxTree2(update.startState) !== syntaxTree2(update.state)) {
2438
+ if (update.docChanged || update.viewportChanged || syntaxTree2(update.startState) !== syntaxTree2(update.state)) {
2414
2439
  this.decorations = build2(update.view);
2415
2440
  }
2416
2441
  }
@@ -2475,8 +2500,9 @@ var marginTheme = EditorView3.baseTheme({
2475
2500
  ".cm-md-quote::before": {
2476
2501
  content: '""',
2477
2502
  position: "absolute",
2478
- // centred in the left half of the margin, clear of a hung `>`.
2479
- left: "calc(-0.5 * var(--markdown-hang))",
2503
+ // on the bullets' column: centred on where a hung dot sits (the hang's
2504
+ // right padding, then half a dot at the hang's 0.8rem).
2505
+ left: `calc(-1 * (${zoomed("0.6rem")} + ${zoomed("0.16rem")}) - 1.5px)`,
2480
2506
  top: "0",
2481
2507
  bottom: "0",
2482
2508
  width: "3px",
@@ -2500,7 +2526,6 @@ var margin = [marginPlugin, marginTheme];
2500
2526
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
2501
2527
  import {
2502
2528
  EditorSelection as EditorSelection3,
2503
- EditorState as EditorState2,
2504
2529
  Prec as Prec2
2505
2530
  } from "@codemirror/state";
2506
2531
  import { keymap } from "@codemirror/view";
@@ -2517,31 +2542,6 @@ function headingPrefix(state, line) {
2517
2542
  }
2518
2543
  return null;
2519
2544
  }
2520
- var keepOutOfPrefix = EditorState2.transactionFilter.of((tr) => {
2521
- if (!tr.selection) return tr;
2522
- const { state } = tr;
2523
- const before = tr.startState.selection;
2524
- let moved = false;
2525
- const ranges = tr.selection.ranges.map((r, i) => {
2526
- if (!r.empty) return r;
2527
- const line = state.doc.lineAt(r.head);
2528
- if (r.head >= line.to && line.length > 0) return r;
2529
- const prefix = headingPrefix(state, line);
2530
- if (!prefix || r.head >= prefix.to) return r;
2531
- const old = before.ranges[i] ?? before.main;
2532
- const leaving = !tr.docChanged && old.empty && old.head === prefix.to && line.from > 0;
2533
- moved = true;
2534
- return EditorSelection3.cursor(leaving ? line.from - 1 : prefix.to);
2535
- });
2536
- if (!moved) return tr;
2537
- return [
2538
- tr,
2539
- {
2540
- selection: EditorSelection3.create(ranges, tr.selection.mainIndex),
2541
- sequential: true
2542
- }
2543
- ];
2544
- });
2545
2545
  function selectedLines(state) {
2546
2546
  const seen = /* @__PURE__ */ new Set();
2547
2547
  const lines = [];
@@ -2556,12 +2556,12 @@ function selectedLines(state) {
2556
2556
  }
2557
2557
  var setHeading = (level) => ({ state, dispatch }) => {
2558
2558
  const lines = selectedLines(state);
2559
- const prefixes = lines.map((line) => headingPrefix(state, line));
2560
- const already = level > 0 && prefixes.every((p) => p && p.level === level);
2559
+ const prefixes2 = lines.map((line) => headingPrefix(state, line));
2560
+ const already = level > 0 && prefixes2.every((p) => p && p.level === level);
2561
2561
  const target = already ? 0 : level;
2562
2562
  const insert = target ? "#".repeat(target) + " " : "";
2563
2563
  const changes = lines.map((line, i) => {
2564
- const p = prefixes[i];
2564
+ const p = prefixes2[i];
2565
2565
  return { from: line.from, to: p ? p.to : line.from, insert };
2566
2566
  });
2567
2567
  dispatch(
@@ -2580,18 +2580,6 @@ function atHeadingStart(state) {
2580
2580
  const prefix = headingPrefix(state, line);
2581
2581
  return prefix && sel.main.head === prefix.to ? prefix : null;
2582
2582
  }
2583
- var backspace = ({ state, dispatch }) => {
2584
- const prefix = atHeadingStart(state);
2585
- if (!prefix) return false;
2586
- dispatch(
2587
- state.update({
2588
- changes: { from: prefix.from, to: prefix.to },
2589
- selection: EditorSelection3.cursor(prefix.from),
2590
- userEvent: "delete.backward"
2591
- })
2592
- );
2593
- return true;
2594
- };
2595
2583
  var enter = ({ state, dispatch }) => {
2596
2584
  const prefix = atHeadingStart(state);
2597
2585
  if (!prefix) return false;
@@ -2607,29 +2595,11 @@ var enter = ({ state, dispatch }) => {
2607
2595
  );
2608
2596
  return true;
2609
2597
  };
2610
- var deleteForward = ({ state, dispatch }) => {
2611
- const sel = state.selection;
2612
- if (sel.ranges.length !== 1 || !sel.main.empty) return false;
2613
- const line = state.doc.lineAt(sel.main.head);
2614
- if (sel.main.head !== line.to || line.number >= state.doc.lines) return false;
2615
- const prefix = headingPrefix(state, state.doc.line(line.number + 1));
2616
- if (!prefix) return false;
2617
- dispatch(
2618
- state.update({
2619
- changes: { from: line.to, to: prefix.to },
2620
- userEvent: "delete.forward"
2621
- })
2622
- );
2623
- return true;
2624
- };
2625
2598
  var headings = [
2626
- keepOutOfPrefix,
2627
- // above lang-markdown's own (Prec.high) Enter and Backspace.
2599
+ // above lang-markdown's own (Prec.high) Enter.
2628
2600
  Prec2.highest(
2629
2601
  keymap.of([
2630
- { key: "Backspace", run: backspace },
2631
2602
  { key: "Enter", run: enter },
2632
- { key: "Delete", run: deleteForward },
2633
2603
  { key: "Mod-Shift-h", run: setHeading(2), preventDefault: true },
2634
2604
  { key: "Mod-Shift-j", run: setHeading(3), preventDefault: true },
2635
2605
  { key: "Mod-Shift-b", run: setHeading(0), preventDefault: true },
@@ -2642,8 +2612,10 @@ var headings = [
2642
2612
  ];
2643
2613
 
2644
2614
  // src/extensions/lists.ts
2645
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2615
+ import { ensureSyntaxTree, syntaxTree as syntaxTree4 } from "@codemirror/language";
2616
+ import { indentMore } from "@codemirror/commands";
2646
2617
  import {
2618
+ Prec as Prec3,
2647
2619
  StateEffect as StateEffect2,
2648
2620
  StateField as StateField2
2649
2621
  } from "@codemirror/state";
@@ -2651,7 +2623,8 @@ import {
2651
2623
  Decoration as Decoration4,
2652
2624
  EditorView as EditorView4,
2653
2625
  ViewPlugin as ViewPlugin4,
2654
- WidgetType as WidgetType3
2626
+ WidgetType as WidgetType3,
2627
+ keymap as keymap2
2655
2628
  } from "@codemirror/view";
2656
2629
  function listAt(state, pos) {
2657
2630
  for (let n = syntaxTree4(state).resolveInner(pos, 1); n; n = n.parent) {
@@ -2692,7 +2665,8 @@ function renumber(state, list) {
2692
2665
  const all = items(list);
2693
2666
  const firstMark = all[0]?.getChild("ListMark");
2694
2667
  if (!firstMark) return changes;
2695
- const start = parseInt(state.doc.sliceString(firstMark.from, firstMark.to), 10) || 0;
2668
+ const nested = list.parent?.name === "ListItem";
2669
+ const start = nested ? 1 : parseInt(state.doc.sliceString(firstMark.from, firstMark.to), 10) || 0;
2696
2670
  all.forEach((item, i) => {
2697
2671
  const mark = item.getChild("ListMark");
2698
2672
  if (!mark) return;
@@ -2740,6 +2714,31 @@ function moveDoneDown(state, list) {
2740
2714
  ];
2741
2715
  }
2742
2716
  var countDone = (state, list) => items(list).filter((it) => done(state, it)).length;
2717
+ var textStart = (line) => line.from + /^\s*/.exec(line.text)[0].length;
2718
+ var tabInOrderedList = (view) => {
2719
+ const before = view.state;
2720
+ const line = before.doc.lineAt(before.selection.main.head);
2721
+ const was = listAt(before, textStart(line));
2722
+ if (!was || was.name !== "OrderedList" || before.selection.ranges.length !== 1)
2723
+ return false;
2724
+ if (!indentMore(view)) return false;
2725
+ const { state } = view;
2726
+ const now = state.doc.lineAt(state.selection.main.head);
2727
+ ensureSyntaxTree(state, now.to, 100);
2728
+ const list = listAt(state, textStart(now));
2729
+ const first = list && items(list)[0];
2730
+ const mark = first?.getChild("ListMark");
2731
+ if (!list || !mark || list.name !== "OrderedList" || list.parent?.name !== "ListItem" || state.doc.lineAt(first.from).number !== now.number)
2732
+ return true;
2733
+ const text = state.doc.sliceString(mark.from, mark.to);
2734
+ const want = `1${text.slice(-1)}`;
2735
+ if (text !== want)
2736
+ view.dispatch({
2737
+ changes: { from: mark.from, to: mark.to, insert: want },
2738
+ userEvent: "input.renumber"
2739
+ });
2740
+ return true;
2741
+ };
2743
2742
  var setHideDone = StateEffect2.define();
2744
2743
  var HiddenDone = class extends WidgetType3 {
2745
2744
  constructor(count) {
@@ -2958,11 +2957,190 @@ var listsTheme = EditorView4.baseTheme({
2958
2957
  textDecoration: "underline"
2959
2958
  }
2960
2959
  });
2961
- var lists = [hideDoneField, menuPlugin, listsTheme];
2960
+ var lists = [
2961
+ hideDoneField,
2962
+ menuPlugin,
2963
+ listsTheme,
2964
+ // ahead of indentWithTab in the main keymap
2965
+ Prec3.high(keymap2.of([{ key: "Tab", run: tabInOrderedList }]))
2966
+ ];
2967
+
2968
+ // src/extensions/prefix.ts
2969
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2970
+ import {
2971
+ EditorSelection as EditorSelection4,
2972
+ EditorState as EditorState2,
2973
+ Prec as Prec4
2974
+ } from "@codemirror/state";
2975
+ import { EditorView as EditorView5, keymap as keymap3 } from "@codemirror/view";
2976
+ var MARKS2 = /* @__PURE__ */ new Set(["QuoteMark", "ListMark", "HeaderMark", "TaskMarker"]);
2977
+ function skipSpaces2(state, pos, end) {
2978
+ while (pos < end && /[ \t]/.test(state.doc.sliceString(pos, pos + 1))) pos++;
2979
+ return pos;
2980
+ }
2981
+ function blockPrefix(state, line) {
2982
+ const tree = syntaxTree5(state);
2983
+ const marks = [];
2984
+ const starts = [];
2985
+ let pos = line.from;
2986
+ for (; ; ) {
2987
+ const at = skipSpaces2(state, pos, line.to);
2988
+ const node = tree.resolveInner(at, 1);
2989
+ if (!MARKS2.has(node.name) || node.from !== at || node.to <= at) break;
2990
+ if (doc(state, pos, at).trim() !== "") break;
2991
+ marks.push(node.name);
2992
+ starts.push(at);
2993
+ pos = node.to;
2994
+ }
2995
+ if (!marks.length) return null;
2996
+ return { from: line.from, to: skipSpaces2(state, pos, line.to), marks, starts };
2997
+ }
2998
+ var doc = (state, from, to) => state.doc.sliceString(from, to);
2999
+ var keepOut = EditorState2.transactionFilter.of((tr) => {
3000
+ if (!tr.selection) return tr;
3001
+ const { state } = tr;
3002
+ const before = tr.startState.selection;
3003
+ let moved = false;
3004
+ const ranges = tr.selection.ranges.map((r, i) => {
3005
+ if (!r.empty) return r;
3006
+ const line = state.doc.lineAt(r.head);
3007
+ const prefix = blockPrefix(state, line);
3008
+ if (!prefix || r.head >= prefix.to) return r;
3009
+ const old = before.ranges[i] ?? before.main;
3010
+ const leaving = !tr.docChanged && old.empty && old.head === prefix.to && line.from > 0;
3011
+ moved = true;
3012
+ return EditorSelection4.cursor(leaving ? line.from - 1 : prefix.to);
3013
+ });
3014
+ if (!moved) return tr;
3015
+ return [
3016
+ tr,
3017
+ {
3018
+ selection: EditorSelection4.create(ranges, tr.selection.mainIndex),
3019
+ sequential: true
3020
+ }
3021
+ ];
3022
+ });
3023
+ function atTextStart(state) {
3024
+ const sel = state.selection;
3025
+ if (sel.ranges.length !== 1 || !sel.main.empty) return null;
3026
+ const prefix = blockPrefix(state, state.doc.lineAt(sel.main.head));
3027
+ return prefix && sel.main.head === prefix.to ? prefix : null;
3028
+ }
3029
+ var backspace = ({ state, dispatch }) => {
3030
+ const prefix = atTextStart(state);
3031
+ if (!prefix) return false;
3032
+ dispatch(
3033
+ state.update({
3034
+ changes: { from: prefix.starts.at(-1), to: prefix.to },
3035
+ selection: EditorSelection4.cursor(prefix.starts.at(-1)),
3036
+ userEvent: "delete.backward"
3037
+ })
3038
+ );
3039
+ return true;
3040
+ };
3041
+ var deleteForward = ({ state, dispatch }) => {
3042
+ const sel = state.selection;
3043
+ if (sel.ranges.length !== 1 || !sel.main.empty) return false;
3044
+ const line = state.doc.lineAt(sel.main.head);
3045
+ if (sel.main.head !== line.to || line.number >= state.doc.lines) return false;
3046
+ const prefix = blockPrefix(state, state.doc.line(line.number + 1));
3047
+ if (!prefix) return false;
3048
+ dispatch(
3049
+ state.update({
3050
+ changes: { from: line.to, to: prefix.to },
3051
+ userEvent: "delete.forward"
3052
+ })
3053
+ );
3054
+ return true;
3055
+ };
3056
+ var inCode = (state, pos) => {
3057
+ for (let n = syntaxTree5(state).resolveInner(pos, -1); n; n = n.parent) {
3058
+ if (/^(FencedCode|CodeBlock|CodeText|InlineCode)$/.test(n.name)) return true;
3059
+ }
3060
+ return false;
3061
+ };
3062
+ var LIST_OR_HEADING = /^(\d{1,9}[.)]|[-*+]|#{1,6})$/;
3063
+ var HEADING = /^#{1,6}$/;
3064
+ var replaceMarker = EditorView5.inputHandler.of((view, from, to, text) => {
3065
+ if (text !== " " || from !== to) return false;
3066
+ const { state } = view;
3067
+ const line = state.doc.lineAt(from);
3068
+ const prefix = blockPrefix(state, line);
3069
+ if (!prefix || inCode(state, from)) return false;
3070
+ const { marks, starts } = prefix;
3071
+ let typed = doc(state, prefix.to, from);
3072
+ let mine = marks.length - 1;
3073
+ if (!typed && prefix.to === from && marks.length > 1) {
3074
+ typed = doc(state, starts[mine], from);
3075
+ mine--;
3076
+ }
3077
+ if (!typed || marks[mine] === "QuoteMark") return false;
3078
+ if (marks[mine] === "TaskMarker" && marks[mine - 1] === "ListMark") mine--;
3079
+ const ok = marks[mine] === "HeaderMark" ? HEADING : LIST_OR_HEADING;
3080
+ if (!ok.test(typed)) return false;
3081
+ view.dispatch({
3082
+ changes: { from: starts[mine], to: from, insert: typed + " " },
3083
+ selection: EditorSelection4.cursor(starts[mine] + typed.length + 1),
3084
+ userEvent: "input.type"
3085
+ });
3086
+ return true;
3087
+ });
3088
+ var prefixes = [
3089
+ keepOut,
3090
+ replaceMarker,
3091
+ // above lang-markdown's own (Prec.high) Backspace.
3092
+ Prec4.highest(
3093
+ keymap3.of([
3094
+ { key: "Backspace", run: backspace },
3095
+ { key: "Delete", run: deleteForward }
3096
+ ])
3097
+ )
3098
+ ];
3099
+
3100
+ // src/extensions/vertical.ts
3101
+ import { EditorSelection as EditorSelection5, Prec as Prec5 } from "@codemirror/state";
3102
+ import { cursorLineDown, cursorLineUp } from "@codemirror/commands";
3103
+ import { keymap as keymap4 } from "@codemirror/view";
3104
+ var streaks = /* @__PURE__ */ new WeakMap();
3105
+ var vertical = (move) => (view) => {
3106
+ const { state } = view;
3107
+ const sel = state.selection;
3108
+ if (sel.ranges.length !== 1 || !sel.main.empty) return move(view);
3109
+ let streak = streaks.get(view);
3110
+ if (!streak || streak.head !== sel.main.head || streak.doc !== state.doc) {
3111
+ streak = { visited: /* @__PURE__ */ new Map(), head: sel.main.head, doc: state.doc };
3112
+ }
3113
+ const from = state.doc.lineAt(sel.main.head).number;
3114
+ if (!streak.visited.has(from)) streak.visited.set(from, sel.main.head);
3115
+ if (!move(view)) return false;
3116
+ const now = view.state.selection.main;
3117
+ const to = view.state.doc.lineAt(now.head).number;
3118
+ const back = to !== from ? streak.visited.get(to) : void 0;
3119
+ if (to === from) streak.visited.set(to, now.head);
3120
+ if (back !== void 0 && back !== now.head && view.state.doc === streak.doc) {
3121
+ view.dispatch({
3122
+ selection: EditorSelection5.cursor(back),
3123
+ scrollIntoView: true,
3124
+ userEvent: "select"
3125
+ });
3126
+ }
3127
+ streak.head = view.state.selection.main.head;
3128
+ streak.doc = view.state.doc;
3129
+ streaks.set(view, streak);
3130
+ return true;
3131
+ };
3132
+ var verticalMemory = Prec5.high(
3133
+ keymap4.of([
3134
+ { key: "ArrowUp", run: vertical(cursorLineUp) },
3135
+ { key: "ArrowDown", run: vertical(cursorLineDown) },
3136
+ { mac: "Ctrl-p", run: vertical(cursorLineUp) },
3137
+ { mac: "Ctrl-n", run: vertical(cursorLineDown) }
3138
+ ])
3139
+ );
2962
3140
 
2963
3141
  // src/extensions/zoom.ts
2964
- import { Prec as Prec3 } from "@codemirror/state";
2965
- import { keymap as keymap2 } from "@codemirror/view";
3142
+ import { Prec as Prec6 } from "@codemirror/state";
3143
+ import { keymap as keymap5 } from "@codemirror/view";
2966
3144
  var MIN_FONT_SIZE = 6;
2967
3145
  var FALLBACK_FONT_SIZE = 16;
2968
3146
  var px = (value) => parseFloat(value) || FALLBACK_FONT_SIZE;
@@ -2991,8 +3169,8 @@ function step(view, by) {
2991
3169
  var zoomIn = (view) => step(view, 1);
2992
3170
  var zoomOut = (view) => step(view, -1);
2993
3171
  var zoomReset = (view) => step(view, 0);
2994
- var markdownZoom = Prec3.high(
2995
- keymap2.of([
3172
+ var markdownZoom = Prec6.high(
3173
+ keymap5.of([
2996
3174
  // `+` and `_` are the shifted keys, for keyboards that need Shift.
2997
3175
  { key: "Mod-=", run: zoomIn, preventDefault: true },
2998
3176
  { key: "Mod-+", run: zoomIn, preventDefault: true },
@@ -3004,7 +3182,7 @@ var markdownZoom = Prec3.high(
3004
3182
 
3005
3183
  // src/themes/markdown.ts
3006
3184
  import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
3007
- import { EditorView as EditorView6 } from "@codemirror/view";
3185
+ import { EditorView as EditorView8 } from "@codemirror/view";
3008
3186
  var bodyFont = (style) => style == "serif" ? 'var(--text-editor-family-serif, "Merriweather", serif)' : "var(--text-editor-family-sans)";
3009
3187
  var zoomed2 = (length) => `calc(${length} * var(--markdown-zoom, 1))`;
3010
3188
  var markdownStyles = (style) => ({
@@ -3219,7 +3397,7 @@ var markdownSyntaxHighlighting = (style) => HighlightStyle.define([
3219
3397
  { tag: tags.monospace, ...baseCodeStyles }
3220
3398
  ]);
3221
3399
  var theme = (style) => [
3222
- EditorView6.theme(markdownStyles(style)),
3400
+ EditorView8.theme(markdownStyles(style)),
3223
3401
  syntaxHighlighting(markdownSyntaxHighlighting(style))
3224
3402
  ];
3225
3403
 
@@ -3229,7 +3407,7 @@ function markdownExtensions() {
3229
3407
  ...theme("sans"),
3230
3408
  indentOnInput(),
3231
3409
  markdownZoom,
3232
- keymap3.of([
3410
+ keymap6.of([
3233
3411
  ...markdownFormattingKeymap,
3234
3412
  ...defaultKeymap,
3235
3413
  ...searchKeymap,
@@ -3237,7 +3415,7 @@ function markdownExtensions() {
3237
3415
  ...completionKeymap,
3238
3416
  indentWithTab
3239
3417
  ]),
3240
- EditorView7.lineWrapping,
3418
+ EditorView9.lineWrapping,
3241
3419
  // GFM base: task lists, tables, strikethrough, autolinks.
3242
3420
  markdown({
3243
3421
  base: markdownLanguage,
@@ -3246,6 +3424,8 @@ function markdownExtensions() {
3246
3424
  }),
3247
3425
  taskCheckboxes,
3248
3426
  margin,
3427
+ prefixes,
3428
+ verticalMemory,
3249
3429
  headings,
3250
3430
  lists,
3251
3431
  indentUnit.of(" ")