@vscode/markdown-editor 0.0.2-5 → 0.0.2-6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -338,6 +338,13 @@ export declare class CursorView extends Disposable {
338
338
  export declare interface CursorViewOptions {
339
339
  readonly offset: IObservable<SourceOffset | undefined>;
340
340
  readonly visualLineMap: IObservable<VisualLineMap>;
341
+ /**
342
+ * When set, the caret is drawn over the transient empty paragraph instead
343
+ * of at {@link offset} — its rect (in client coordinates) comes straight
344
+ * from that synthetic element's geometry, since it has no visual-line-map
345
+ * entry. Takes priority over the normal offset-based placement.
346
+ */
347
+ readonly pendingCaretRect?: IObservable<Rect2D | undefined>;
341
348
  }
342
349
 
343
350
  export declare class CursorViewRendering {
@@ -383,13 +390,14 @@ declare interface DocumentBlockViewData {
383
390
  readonly view: BlockViewData;
384
391
  }
385
392
 
386
- /** A mounted document child: a block or a run of inter-block glue. */
393
+ /** A mounted document child: a block, a run of inter-block glue, or the
394
+ * transient empty paragraph (see {@link PendingParagraphViewData}). */
387
395
  declare interface DocumentChildViewData {
388
396
  readonly absoluteStart: number;
389
397
  /** For a block: selection reaches it. For glue: always false (unowned, hidden). */
390
398
  readonly isActive: boolean;
391
- readonly view: BlockViewData | GlueViewData;
392
- readonly kind: 'block' | 'glue';
399
+ readonly view: BlockViewData | GlueViewData | PendingParagraphViewData;
400
+ readonly kind: 'block' | 'glue' | 'pendingParagraph';
393
401
  }
394
402
 
395
403
  /**
@@ -445,6 +453,8 @@ declare class DocumentViewData {
445
453
  */
446
454
  export declare class DocumentViewNode extends ViewNode {
447
455
  readonly blocks: readonly DocumentBlock[];
456
+ /** The transient empty-paragraph element, when one is armed. */
457
+ readonly pendingElement?: HTMLElement | undefined;
448
458
  static create(viewData: DocumentViewData, options: BlockViewOptions | undefined, previous: DocumentViewNode | undefined): DocumentViewNode;
449
459
  private constructor();
450
460
  /** The stable content element this document mounts its children into. */
@@ -492,7 +502,14 @@ export declare class EditorController extends Disposable {
492
502
  /** Move the cursor up one visual line (Arrow Up). */
493
503
  cursorUp(extend?: boolean): void;
494
504
  private _selectedText;
505
+ private readonly _updateModifierState;
506
+ private readonly _clearModifierState;
495
507
  private readonly _handleKeyDown;
508
+ /**
509
+ * Context-aware Enter: splits / line-breaks via {@link insertSmartEnter}, or
510
+ * arms a transient empty paragraph when at the end of a paragraph.
511
+ */
512
+ private _smartEnter;
496
513
  }
497
514
 
498
515
  /** Options for an {@link EditorController}. */
@@ -520,6 +537,20 @@ export declare class EditorModel {
520
537
  * (e.g. an inactive/unfocused rendering).
521
538
  */
522
539
  readonly selection: ISettableObservable<Selection_2 | undefined, void>;
540
+ /**
541
+ * Whether a Ctrl/Cmd modifier is currently held. Set by the controller from
542
+ * live keyboard state; the view reads it to show the link-open affordance
543
+ * (underline + pointer cursor) only while a Ctrl/Cmd+click would open a link
544
+ * whose block is active.
545
+ */
546
+ readonly ctrlOrMetaDown: ISettableObservable<boolean, void>;
547
+ /**
548
+ * Gutter markers (source-control style change indicators) painted in the
549
+ * left gutter. Each entry maps a source {@link OffsetRange} to a change kind
550
+ * — see {@link GutterMarker}. Purely decorative: markers never affect the
551
+ * parsed {@link document}, selection, or layout. Empty by default.
552
+ */
553
+ readonly gutterMarkers: ISettableObservable<readonly GutterMarker[], void>;
523
554
  /**
524
555
  * Forces the rendered active-block set. `undefined` (the default)
525
556
  * derives the set from the current selection range (see
@@ -528,6 +559,13 @@ export declare class EditorModel {
528
559
  * collapsed/inactive rendering.
529
560
  */
530
561
  readonly activeBlocksOverride: ISettableObservable<readonly BlockAstNode[] | typeof NO_ACTIVE_BLOCKS | undefined, void>;
562
+ /**
563
+ * The transient empty-paragraph editing state, or `undefined` when none is
564
+ * armed. See {@link PendingParagraph}. This is *not* document data — it is
565
+ * cleared by any source edit and lives only between the Enter that armed it
566
+ * and the next keystroke.
567
+ */
568
+ readonly pendingParagraph: ISettableObservable<PendingParagraph | undefined, void>;
531
569
  readonly cursorOffset: IObservableWithChange<number | undefined, void>;
532
570
  /**
533
571
  * The parsed document. Threads the previous document into the parser so
@@ -551,6 +589,24 @@ export declare class EditorModel {
551
589
  * collapsed this is a one-element set holding {@link activeBlock}.
552
590
  */
553
591
  readonly activeBlocks: IObservableWithChange<Set<BlockAstNode>, void>;
592
+ /**
593
+ * Arm a {@link PendingParagraph} at the given gap, minting a fresh synthetic
594
+ * AST node for it, and park the caret at the gap start. No source edit is
595
+ * applied — the blank line exists only in the view until it is materialized.
596
+ */
597
+ armPendingParagraph(req: {
598
+ anchorBlock: BlockAstNode;
599
+ replaceRange: OffsetRange;
600
+ atEof: boolean;
601
+ }): void;
602
+ /** Discard the pending paragraph (if any) without touching the source. */
603
+ cancelPendingParagraph(): void;
604
+ /**
605
+ * Turn the pending paragraph into real source: rewrite its gap so the typed
606
+ * `text` becomes its own paragraph, separated from its neighbours by blank
607
+ * lines, and place the caret after the inserted text.
608
+ */
609
+ materializePendingParagraph(text: string): void;
554
610
  applyEdit(edit: StringEdit): void;
555
611
  applyEditForSelection(edit: StringEdit): void;
556
612
  }
@@ -593,6 +649,7 @@ export declare class EditorView extends Disposable {
593
649
  private readonly _contentContainer;
594
650
  private readonly _cursorView;
595
651
  private readonly _selectionView;
652
+ private readonly _gutterMarkersView;
596
653
  /**
597
654
  * The mounted block sequence, in source order. Rebuilt (not mutated) each
598
655
  * frame by {@link DocumentViewNode.create}; the view just swaps one
@@ -612,6 +669,13 @@ export declare class EditorView extends Disposable {
612
669
  /** The current view-data tree (AST overlaid with selection flags), for debugging. */
613
670
  private readonly _viewData;
614
671
  get viewData(): IObservable<DocumentViewData | undefined>;
672
+ /**
673
+ * Caret rect (client coords) for the transient empty paragraph, or
674
+ * `undefined` when none is armed. Set each frame from the synthetic
675
+ * paragraph element's geometry and fed to the {@link CursorView}, which has
676
+ * no visual-line-map entry to place the caret from otherwise.
677
+ */
678
+ private readonly _pendingCaretRect;
615
679
  /**
616
680
  * The block cache projected for views (selection painting) that need to
617
681
  * react to mount/unmount. Derived from {@link _document}, so it stays in
@@ -619,6 +683,13 @@ export declare class EditorView extends Disposable {
619
683
  */
620
684
  private readonly _selectionBlocksObs;
621
685
  constructor(_model: EditorModel, _options?: EditorViewOptions | undefined);
686
+ /**
687
+ * Mirrors the model's live Ctrl/Cmd state onto the editor root as
688
+ * `.md-mod-down` so CSS can show the link-open underline and pointer cursor
689
+ * only while a click would actually open the link: an inactive link opens on
690
+ * a plain click, but an active link only opens with the modifier held.
691
+ */
692
+ private _setupModifierTracking;
622
693
  focus(): void;
623
694
  /**
624
695
  * Client coordinates → absolute source offset (any block). Used during
@@ -731,6 +802,29 @@ declare class GlueViewData {
731
802
  decorateNewline: boolean);
732
803
  }
733
804
 
805
+ /**
806
+ * A single gutter marker: a source {@link OffsetRange} tagged with a
807
+ * {@link GutterMarkerType}. The view resolves the range to the visual lines it
808
+ * covers and paints a bar (or, for `deleted`, a wedge at the range position) in
809
+ * the left gutter.
810
+ *
811
+ * A `deleted` marker is normally an empty range (`range.isEmpty`) sitting at the
812
+ * boundary where the removed text used to be — there is nothing left to span,
813
+ * so it is drawn as a caret between lines rather than a bar.
814
+ */
815
+ export declare interface GutterMarker {
816
+ readonly range: OffsetRange;
817
+ readonly type: GutterMarkerType;
818
+ }
819
+
820
+ /**
821
+ * The kind of change a gutter marker represents, mirroring the three states a
822
+ * source-control diff distinguishes (the git change markers in the editor
823
+ * gutter): a freshly inserted region, an edited region, and a point where
824
+ * content was removed.
825
+ */
826
+ export declare type GutterMarkerType = 'added' | 'modified' | 'deleted';
827
+
734
828
  export declare class HeadingAstNode extends BlockAstNodeBase {
735
829
  readonly level: 1 | 2 | 3 | 4 | 5 | 6;
736
830
  readonly marker: MarkerAstNode;
@@ -881,6 +975,21 @@ export declare const insertLineBreak: EditCommand;
881
975
 
882
976
  export declare const insertParagraph: EditCommand;
883
977
 
978
+ /**
979
+ * Context-aware Enter. The behaviour is chosen from the active block:
980
+ * - paragraph / heading / thematic break — the "rich text" thing: at the
981
+ * block's end arm a transient empty paragraph (see {@link SmartEnterResult});
982
+ * elsewhere split into two paragraphs (`\n\n`).
983
+ * - code block — insert a newline that preserves the current line's indentation,
984
+ * staying inside the fence.
985
+ * - block quote — continue the quote (`\n> `); an empty quote line exits it.
986
+ * - list — continue the list with the next marker (incrementing ordered
987
+ * numbers, re-emitting task checkboxes); an empty item exits the list.
988
+ * A non-collapsed selection, or any other block, falls back to a plain soft line
989
+ * break, preserving today's behaviour.
990
+ */
991
+ export declare const insertSmartEnter: (ctx: CursorCommandContext) => SmartEnterResult;
992
+
884
993
  export declare function insertText(text: string): EditCommand;
885
994
 
886
995
  /**
@@ -1296,6 +1405,45 @@ declare class ParagraphViewData {
1296
1405
  constructor(ast: ParagraphAstNode, content: readonly AnyViewData[]);
1297
1406
  }
1298
1407
 
1408
+ /**
1409
+ * A *transient* editing state: the empty paragraph the user conjured by
1410
+ * pressing Enter at the end of a paragraph. Markdown has no empty-paragraph
1411
+ * node, so this never lives in {@link EditorModel.sourceText} or the parsed
1412
+ * {@link EditorModel.document} — it is pure edit intent that the view renders
1413
+ * as a synthetic blank line and that the controller either *materializes* (the
1414
+ * user types) or *cancels* (the user navigates away / backspaces).
1415
+ */
1416
+ declare interface PendingParagraph {
1417
+ /** The paragraph the blank line is rendered directly after. */
1418
+ readonly anchorBlock: BlockAstNode;
1419
+ /**
1420
+ * Source region rewritten when the pending paragraph is materialized — the
1421
+ * gap between {@link anchorBlock}'s text and whatever follows it.
1422
+ */
1423
+ readonly replaceRange: OffsetRange;
1424
+ /** Whether {@link replaceRange} ends at the end of the document. */
1425
+ readonly atEof: boolean;
1426
+ /**
1427
+ * A throwaway AST node that exists only to give the synthetic view child a
1428
+ * stable identity across render frames (the view pairs nodes by `ast.id`).
1429
+ * It is never part of {@link document}.
1430
+ */
1431
+ readonly syntheticAst: ParagraphAstNode;
1432
+ }
1433
+
1434
+ /**
1435
+ * View-data for the transient empty paragraph (see `PendingParagraph` in the
1436
+ * model). It carries only the throwaway {@link ParagraphAstNode} that gives the
1437
+ * rendered blank line a stable identity across frames; it has no content and is
1438
+ * never measured or part of the selection geometry — the caret is positioned
1439
+ * over it via a dedicated rect, not via the visual-line map.
1440
+ */
1441
+ declare class PendingParagraphViewData {
1442
+ readonly ast: ParagraphAstNode;
1443
+ readonly kind = "pendingParagraph";
1444
+ constructor(ast: ParagraphAstNode);
1445
+ }
1446
+
1299
1447
  /**
1300
1448
  * Immutable point in 2D space, in CSS-pixel client coordinates.
1301
1449
  */
@@ -1413,6 +1561,25 @@ export declare class SelectionViewRendering {
1413
1561
 
1414
1562
  export declare const selectWord: SelectionCommand;
1415
1563
 
1564
+ /**
1565
+ * The outcome of {@link insertSmartEnter}: either a concrete source edit (the
1566
+ * ordinary cases), or a request to arm a transient empty paragraph (Enter at
1567
+ * the very end of a paragraph), which the controller turns into
1568
+ * {@link EditorModel.armPendingParagraph} rather than a source edit. Modelling
1569
+ * the empty paragraph as state instead of source keeps the document valid
1570
+ * Markdown — which has no empty-paragraph node — until the user actually types.
1571
+ */
1572
+ export declare type SmartEnterResult = {
1573
+ readonly kind: 'edit';
1574
+ readonly edit: StringEdit;
1575
+ readonly selection: Selection_2;
1576
+ } | {
1577
+ readonly kind: 'pending';
1578
+ readonly anchorBlock: BlockAstNode;
1579
+ readonly replaceRange: OffsetRange;
1580
+ readonly atEof: boolean;
1581
+ };
1582
+
1416
1583
  /**
1417
1584
  * A run of {@link Token}s together with the exact {@link OffsetRange} they
1418
1585
  * cover.