@vscode/markdown-editor 0.0.2-57 → 0.0.2-59

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
@@ -150,8 +150,12 @@ export declare class BlockQuoteAstNode extends BlockAstNodeBase {
150
150
  declare class BlockQuoteViewData {
151
151
  readonly ast: BlockQuoteAstNode;
152
152
  readonly content: readonly AnyViewData[];
153
+ /** False while a pending paragraph replaces the final marker-only line. */
154
+ readonly showFinalMarkerOnlyLine: boolean;
153
155
  readonly kind = "blockQuote";
154
- constructor(ast: BlockQuoteAstNode, content: readonly AnyViewData[]);
156
+ constructor(ast: BlockQuoteAstNode, content: readonly AnyViewData[],
157
+ /** False while a pending paragraph replaces the final marker-only line. */
158
+ showFinalMarkerOnlyLine: boolean);
155
159
  }
156
160
 
157
161
  /**
@@ -605,7 +609,7 @@ declare interface CompleteHtmlCommentSource extends HtmlCommentSourceBase {
605
609
  */
606
610
  export declare function createDefaultMonacoSyntaxHighlighter(monaco: IMonarchApi, grammars: IDefaultMonarchGrammars): MonacoSyntaxHighlighter;
607
611
 
608
- export declare type CursorCommand = (ctx: CursorCommandContext) => SourceOffset;
612
+ export declare type CursorCommand = (ctx: CursorCommandContext) => CursorPosition;
609
613
 
610
614
  export declare interface CursorCommandContext {
611
615
  readonly text: string;
@@ -614,6 +618,7 @@ export declare interface CursorCommandContext {
614
618
  readonly activeBlock: BlockAstNode | undefined;
615
619
  readonly markerVisibleBlocks: ReadonlySet<BlockAstNode>;
616
620
  readonly wordNavigationConfig: WordNavigationConfig;
621
+ readonly cursorPosition: CursorPosition;
617
622
  }
618
623
 
619
624
  export declare const cursorDocumentEnd: CursorCommand;
@@ -633,12 +638,26 @@ export declare const cursorLineStart: CursorCommand;
633
638
  export declare const cursorMoveLeft: CursorCommand;
634
639
 
635
640
  export declare interface CursorMoveResult {
636
- readonly offset: SourceOffset;
641
+ readonly position: CursorPosition;
637
642
  readonly desiredColumn: number | undefined;
638
643
  }
639
644
 
640
645
  export declare const cursorMoveRight: CursorCommand;
641
646
 
647
+ /** The cursor's position in either source text or a source-less visual line. */
648
+ export declare type CursorPosition = {
649
+ readonly kind: 'source';
650
+ readonly offset: SourceOffset;
651
+ } | {
652
+ readonly kind: 'virtual';
653
+ readonly line: VirtualCursorLine;
654
+ };
655
+
656
+ export declare namespace CursorPosition {
657
+ export function source(offset: SourceOffset): CursorPosition;
658
+ export function virtual(line: VirtualCursorLine): CursorPosition;
659
+ }
660
+
642
661
  export declare const cursorRight: CursorCommand;
643
662
 
644
663
  export declare const cursorUp: VisualCursorCommand;
@@ -647,8 +666,8 @@ export declare const cursorUp: VisualCursorCommand;
647
666
  * Owns the blinking cursor DOM element.
648
667
  *
649
668
  * The rendering pipeline is a single `derived` whose compute callback
650
- * asks the {@link VisualLineMap} for the caret rect at the current
651
- * offset, writes it to {@link element}, and returns a
669
+ * asks the {@link VisualLineMap} for the caret rect at the current source or
670
+ * virtual position, writes it to {@link element}, and returns a
652
671
  * {@link CursorViewRendering} value as proof. An autorun keeps the
653
672
  * derived subscribed.
654
673
  */
@@ -659,7 +678,7 @@ export declare class CursorView extends Disposable {
659
678
  }
660
679
 
661
680
  export declare interface CursorViewOptions {
662
- readonly offset: IObservable<SourceOffset | undefined>;
681
+ readonly position: IObservable<CursorPosition | undefined>;
663
682
  readonly visualLineMap: IObservable<VisualLineMap>;
664
683
  /**
665
684
  * The mounted blocks, used to hide the caret when it sits at an offset that
@@ -667,20 +686,13 @@ export declare interface CursorViewOptions {
667
686
  * matching how the selection is clipped there.
668
687
  */
669
688
  readonly blocks?: IObservable<readonly SelectionBlock[]>;
670
- /**
671
- * When set, the caret is drawn over the transient empty paragraph instead
672
- * of at {@link offset} — its editor-local rect comes straight
673
- * from that synthetic element's geometry, since it has no visual-line-map
674
- * entry. Takes priority over the normal offset-based placement.
675
- */
676
- readonly pendingCaretRect?: IObservable<Rect2D | undefined>;
677
689
  }
678
690
 
679
691
  export declare class CursorViewRendering {
680
- readonly offset: SourceOffset;
692
+ readonly position: CursorPosition;
681
693
  readonly visible: boolean;
682
694
  readonly rect: Rect2D;
683
- constructor(offset: SourceOffset, visible: boolean, rect: Rect2D);
695
+ constructor(position: CursorPosition, visible: boolean, rect: Rect2D);
684
696
  }
685
697
 
686
698
  export declare const cursorVisualLineEnd: VisualCursorCommand;
@@ -872,7 +884,7 @@ declare class DocumentViewData {
872
884
  export declare class DocumentViewNode extends ViewNode {
873
885
  readonly blocks: readonly DocumentBlock[];
874
886
  /** The transient empty-paragraph element, when one is armed. */
875
- readonly pendingElement?: HTMLElement | undefined;
887
+ readonly pendingParagraph?: PendingParagraphViewNode | undefined;
876
888
  static create(viewData: DocumentViewData, options: BlockViewOptions | undefined, previous: DocumentViewNode | undefined): DocumentViewNode;
877
889
  private constructor();
878
890
  /** The stable content element this document mounts its children into. */
@@ -951,7 +963,9 @@ export declare class EditorController extends Disposable {
951
963
  private _executeEditCommand;
952
964
  private _runUndoableEdit;
953
965
  private _executeVisualCursorCommand;
966
+ private _cursorDown;
954
967
  private _setUserSelection;
968
+ private _applyCursorPosition;
955
969
  /** Move the cursor down one visual line (Arrow Down). */
956
970
  cursorDown(extend?: boolean): void;
957
971
  /** Move the cursor up one visual line (Arrow Up). */
@@ -1133,6 +1147,7 @@ export declare class EditorModel {
1133
1147
  */
1134
1148
  readonly pendingParagraph: ISettableObservable<PendingParagraph | undefined, void>;
1135
1149
  readonly cursorOffset: IObservableWithChange<number | undefined, void>;
1150
+ readonly cursorPosition: IObservableWithChange<CursorPosition | undefined, void>;
1136
1151
  /**
1137
1152
  * The parsed document. Threads the previous document into the parser so
1138
1153
  * unchanged blocks keep their object identity across reparses (see
@@ -1183,11 +1198,7 @@ export declare class EditorModel {
1183
1198
  * AST node for it, and park the caret at the gap start. No source edit is
1184
1199
  * applied — the blank line exists only in the view until it is materialized.
1185
1200
  */
1186
- armPendingParagraph(req: {
1187
- anchorBlock: BlockAstNode;
1188
- replaceRange: OffsetRange;
1189
- atEof: boolean;
1190
- }): void;
1201
+ armPendingParagraph(req: Omit<PendingParagraph, 'syntheticAst' | 'cursorLine'>): void;
1191
1202
  /** Discard the pending paragraph (if any) without touching the source. */
1192
1203
  cancelPendingParagraph(): void;
1193
1204
  /**
@@ -1289,13 +1300,6 @@ export declare class EditorView extends Disposable {
1289
1300
  */
1290
1301
  private readonly _focused;
1291
1302
  get focused(): IObservable<boolean>;
1292
- /**
1293
- * Caret rect (editor-local coordinates) for the transient empty paragraph, or
1294
- * `undefined` when none is armed. Set each frame from the synthetic
1295
- * paragraph element's geometry and fed to the {@link CursorView}, which has
1296
- * no visual-line-map entry to place the caret from otherwise.
1297
- */
1298
- private readonly _pendingCaretRect;
1299
1303
  /**
1300
1304
  * The block cache projected for views (selection painting) that need to
1301
1305
  * react to mount/unmount. Derived from {@link _document}, so it stays in
@@ -2419,13 +2423,16 @@ export declare interface MeasuredLayoutDebugViewOptions {
2419
2423
  * through this model and never touches view fields directly.
2420
2424
  */
2421
2425
  export declare class MeasuredLayoutModel {
2422
- readonly measurements: ISettableObservable<readonly BlockMeasurement[], void>;
2426
+ private readonly _measurements;
2427
+ readonly measurements: IObservable<readonly BlockMeasurement[]>;
2428
+ private readonly _virtualLines;
2423
2429
  /**
2424
2430
  * Concatenated visual line map across all mounted blocks. Every per-block
2425
2431
  * map uses the same editor-local coordinate space, so concatenation is
2426
2432
  * well-formed without translation or re-sorting.
2427
2433
  */
2428
2434
  readonly visualLineMap: IObservableWithChange<VisualLineMap, void>;
2435
+ setMeasurements(measurements: readonly BlockMeasurement[], virtualLines: readonly VirtualLineMeasurement[]): void;
2429
2436
  }
2430
2437
 
2431
2438
  /**
@@ -2537,23 +2544,27 @@ declare class ParagraphViewData {
2537
2544
  }
2538
2545
 
2539
2546
  /**
2540
- * A *transient* editing state: the empty paragraph the user conjured by
2541
- * pressing Enter at the end of a paragraph. Markdown has no empty-paragraph
2542
- * node, so this never lives in {@link EditorModel['sourceText']} or the parsed
2543
- * {@link EditorModel.document} — it is pure edit intent that the view renders
2544
- * as a synthetic blank line and that the controller either *materializes* (the
2545
- * user types) or *cancels* (the user navigates away / backspaces).
2547
+ * A *transient* editing state: an empty paragraph adjacent to a real block.
2548
+ * Markdown has no empty-paragraph node, so this never lives in
2549
+ * {@link EditorModel['sourceText']} or the parsed {@link EditorModel.document}
2550
+ * — it is pure edit intent that the view renders as a synthetic blank line and
2551
+ * that the controller either *materializes* (the user types) or *cancels* (the
2552
+ * user navigates away / backspaces).
2546
2553
  */
2547
2554
  declare interface PendingParagraph {
2548
- /** The paragraph the blank line is rendered directly after. */
2555
+ /** The block the blank line is rendered directly after. */
2549
2556
  readonly anchorBlock: BlockAstNode;
2550
2557
  /**
2551
2558
  * Source region rewritten when the pending paragraph is materialized — the
2552
2559
  * gap between {@link anchorBlock}'s text and whatever follows it.
2553
2560
  */
2554
2561
  readonly replaceRange: OffsetRange;
2562
+ /** Whether materialized text needs a blank-line separator before it. */
2563
+ readonly separateFromPreviousBlock: boolean;
2555
2564
  /** Whether {@link replaceRange} ends at the end of the document. */
2556
2565
  readonly atEof: boolean;
2566
+ /** The source-less visual line occupied by the pending caret. */
2567
+ readonly cursorLine: VirtualCursorLine;
2557
2568
  /**
2558
2569
  * A throwaway AST node that exists only to give the synthetic view child a
2559
2570
  * stable identity across render frames (the view pairs nodes by `ast.id`).
@@ -2562,17 +2573,40 @@ declare interface PendingParagraph {
2562
2573
  readonly syntheticAst: ParagraphAstNode;
2563
2574
  }
2564
2575
 
2576
+ declare interface PendingParagraphResult {
2577
+ readonly kind: 'pending';
2578
+ readonly anchorBlock: BlockAstNode;
2579
+ readonly replaceRange: OffsetRange;
2580
+ /** Whether materialized text needs a blank-line separator before it. */
2581
+ readonly separateFromPreviousBlock: boolean;
2582
+ readonly atEof: boolean;
2583
+ }
2584
+
2565
2585
  /**
2566
2586
  * View-data for the transient empty paragraph (see `PendingParagraph` in the
2567
2587
  * model). It carries only the throwaway {@link ParagraphAstNode} that gives the
2568
- * rendered blank line a stable identity across frames; it has no content and is
2569
- * never measured or part of the selection geometry the caret is positioned
2570
- * over it via a dedicated rect, not via the visual-line map.
2588
+ * rendered blank line a stable identity across frames, its anchor block, and
2589
+ * its source-less cursor line. It has no source content or selection range.
2571
2590
  */
2572
2591
  declare class PendingParagraphViewData {
2573
2592
  readonly ast: ParagraphAstNode;
2593
+ readonly anchorBlock: BlockAstNode;
2594
+ readonly cursorLine: VirtualCursorLine;
2574
2595
  readonly kind = "pendingParagraph";
2575
- constructor(ast: ParagraphAstNode);
2596
+ constructor(ast: ParagraphAstNode, anchorBlock: BlockAstNode, cursorLine: VirtualCursorLine);
2597
+ }
2598
+
2599
+ /**
2600
+ * The mounted transient empty paragraph: a `<p class="md-pending-paragraph">`
2601
+ * holding a single `<br>` so it occupies a line's height. It is a leaf view
2602
+ * node with no inline source content; the document view publishes its element
2603
+ * geometry as a virtual visual line.
2604
+ */
2605
+ declare class PendingParagraphViewNode extends ViewNode {
2606
+ readonly element: HTMLElement;
2607
+ readonly anchorBlock: BlockAstNode;
2608
+ readonly cursorLine: VirtualCursorLine;
2609
+ constructor(view: PendingParagraphViewData);
2576
2610
  }
2577
2611
 
2578
2612
  /**
@@ -2730,12 +2764,7 @@ export declare type SmartEnterResult = {
2730
2764
  readonly kind: 'edit';
2731
2765
  readonly edit: StringEdit;
2732
2766
  readonly selection: Selection_2;
2733
- } | {
2734
- readonly kind: 'pending';
2735
- readonly anchorBlock: BlockAstNode;
2736
- readonly replaceRange: OffsetRange;
2737
- readonly atEof: boolean;
2738
- };
2767
+ } | PendingParagraphResult;
2739
2768
 
2740
2769
  /**
2741
2770
  * A run of {@link Token}s together with the exact {@link OffsetRange} they
@@ -3134,6 +3163,24 @@ export declare class ViewNode extends Disposable {
3134
3163
  forEachTextLeaf(nodeOffset: number, visitor: (leaf: ViewNode, leafOffset: number) => void): void;
3135
3164
  }
3136
3165
 
3166
+ /**
3167
+ * A visual cursor line that has no representation in the source text.
3168
+ *
3169
+ * The two source offsets are the positions immediately before and after the
3170
+ * virtual line. The object itself is the stable identity of the line.
3171
+ */
3172
+ export declare class VirtualCursorLine {
3173
+ readonly sourceOffsetBefore: SourceOffset;
3174
+ readonly sourceOffsetAfter: SourceOffset;
3175
+ constructor(sourceOffsetBefore: SourceOffset, sourceOffsetAfter: SourceOffset);
3176
+ }
3177
+
3178
+ /** A measured source-less line inserted directly after a source block. */
3179
+ declare interface VirtualLineMeasurement {
3180
+ readonly afterBlock: BlockAstNode;
3181
+ readonly line: VisualLine;
3182
+ }
3183
+
3137
3184
  export declare type VisualCursorCommand = (ctx: VisualCursorCommandContext) => CursorMoveResult;
3138
3185
 
3139
3186
  export declare interface VisualCursorCommandContext extends CursorCommandContext {
@@ -3151,7 +3198,9 @@ export declare function visualizeAst(root: AstNode, source: string): AstVisualiz
3151
3198
  export declare class VisualLine {
3152
3199
  readonly rect: Rect2D;
3153
3200
  readonly runs: readonly VisualRun[];
3154
- constructor(rect: Rect2D, runs: readonly VisualRun[]);
3201
+ readonly virtualCursorLine?: VirtualCursorLine | undefined;
3202
+ static virtual(cursorLine: VirtualCursorLine, rect: Rect2D): VisualLine;
3203
+ constructor(rect: Rect2D, runs: readonly VisualRun[], virtualCursorLine?: VirtualCursorLine | undefined);
3155
3204
  containsOffset(offset: SourceOffset): boolean;
3156
3205
  /**
3157
3206
  * How `offset` relates to this line's runs:
@@ -3176,10 +3225,15 @@ export declare class VisualLine {
3176
3225
  * source offset (hidden-marker runs are appended last). So this scans all
3177
3226
  * runs rather than assuming any ordering:
3178
3227
  *
3179
- * - If some run *covers* `offset`, its own geometry places the caret
3180
- * (exact glyph boundary for text runs). In the active, markers-visible
3181
- * form every offset is covered, so this branch keeps distinct offsets
3182
- * distinct.
3228
+ * - A zero-source visual anchor owns its exact offset, so a marker-only line
3229
+ * wins over the preceding line's inclusive end boundary.
3230
+ * - Otherwise a run starting at `offset` owns that seam. This keeps an
3231
+ * out-of-flow prefix from placing the caret at its trailing edge when the
3232
+ * following body starts at a visually separate x.
3233
+ * - Otherwise, if some run *covers* `offset`, its own geometry places the
3234
+ * caret (exact glyph boundary for text runs). In the active,
3235
+ * markers-visible form every interior offset is covered, so this branch
3236
+ * keeps distinct offsets distinct.
3183
3237
  * - Otherwise `offset` sits in a gap — a hidden inline marker such as the
3184
3238
  * `**` of `**bold**`, or before/after the painted text. It snaps to the
3185
3239
  * seam between the source-nearest runs on either side: the right edge of
@@ -3236,6 +3290,8 @@ export declare class VisualLineMap {
3236
3290
  readonly absoluteStart: number;
3237
3291
  readonly viewNode: ViewNode;
3238
3292
  }[], coordinateSpace: EditorCoordinateSpace, transform?: EditorCoordinateTransform): VisualLineMap;
3293
+ /** Lines backed by source ranges, excluding source-less cursor lines. */
3294
+ readonly sourceLines: readonly VisualLine[];
3239
3295
  constructor(lines: readonly VisualLine[]);
3240
3296
  get lineCount(): number;
3241
3297
  get isEmpty(): boolean;
@@ -3260,6 +3316,12 @@ export declare class VisualLineMap {
3260
3316
  * {@link lineIndexOfOffset}. Returns `0` when the map is empty.
3261
3317
  */
3262
3318
  xAtOffset(offset: SourceOffset): number;
3319
+ /**
3320
+ * Line occupied by a source or virtual cursor position. A virtual position
3321
+ * returns `undefined` until its corresponding DOM line has been measured.
3322
+ */
3323
+ lineIndexOfPosition(position: CursorPosition): number | undefined;
3324
+ xAtPosition(position: CursorPosition): number;
3263
3325
  /**
3264
3326
  * Line whose vertical band contains `y`, clamped to the first/last
3265
3327
  * line when `y` is outside the document.
@@ -3273,6 +3335,7 @@ export declare class VisualLineMap {
3273
3335
  offsetAtPoint(point: Point2D): SourceOffset;
3274
3336
  /** Snap `x` to the nearest offset on a specific line. */
3275
3337
  offsetInLineAtX(lineIndex: number, x: number): SourceOffset;
3338
+ positionInLineAtX(lineIndex: number, x: number): CursorPosition;
3276
3339
  lineStartOffset(lineIndex: number): SourceOffset | undefined;
3277
3340
  lineEndOffset(lineIndex: number): SourceOffset | undefined;
3278
3341
  }