@vscode/markdown-editor 0.0.2-7 → 0.0.2-71

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 (76) hide show
  1. package/README.md +26 -0
  2. package/dist/commands.d.ts +65 -0
  3. package/dist/commands.js +159 -0
  4. package/dist/commands.js.map +1 -0
  5. package/dist/config-BGeaJqWk.js +286 -0
  6. package/dist/config-BGeaJqWk.js.map +1 -0
  7. package/dist/config.d.ts +10 -0
  8. package/dist/config.js +6 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/index.d.ts +1490 -116
  11. package/dist/index.js +6170 -2006
  12. package/dist/index.js.map +1 -1
  13. package/dist/markdown-editor.css +1 -0
  14. package/dist/stringEdit-CVDbCUBY.js +215 -0
  15. package/dist/stringEdit-CVDbCUBY.js.map +1 -0
  16. package/dist/web-editors.d.ts +282 -0
  17. package/dist/web-editors.js +7240 -0
  18. package/dist/web-editors.js.map +1 -0
  19. package/package.json +60 -17
  20. package/src/contrib/comments/commentInput.css +150 -0
  21. package/src/contrib/comments/comments.css +129 -0
  22. package/src/contrib/commentsVscode/vscodeCommentWidgetV2.css +171 -0
  23. package/src/contrib/find/find.css +347 -0
  24. package/src/view/editor.css +555 -25
  25. package/src/view/themes/default.css +13 -4
  26. package/src/view/themes/github.css +16 -13
  27. package/src/view/themes/vscode-default.css +397 -0
  28. package/src/view/themes/vscode-github.css +393 -0
  29. package/dist/_observables/assert.d.ts +0 -2
  30. package/dist/_observables/deps.d.ts +0 -28
  31. package/dist/_observables/disposables.d.ts +0 -19
  32. package/dist/_observables/equals.d.ts +0 -32
  33. package/dist/_observables/index.d.ts +0 -2
  34. package/dist/_observables/observableInternal/base.d.ts +0 -172
  35. package/dist/_observables/observableInternal/changeTracker.d.ts +0 -44
  36. package/dist/_observables/observableInternal/commonFacade/cancellation.d.ts +0 -24
  37. package/dist/_observables/observableInternal/commonFacade/deps.d.ts +0 -24
  38. package/dist/_observables/observableInternal/debugLocation.d.ts +0 -21
  39. package/dist/_observables/observableInternal/debugName.d.ts +0 -33
  40. package/dist/_observables/observableInternal/experimental/deferUnobserve.d.ts +0 -16
  41. package/dist/_observables/observableInternal/experimental/reducer.d.ts +0 -37
  42. package/dist/_observables/observableInternal/experimental/utils.d.ts +0 -15
  43. package/dist/_observables/observableInternal/index.d.ts +0 -25
  44. package/dist/_observables/observableInternal/logging/consoleObservableLogger.d.ts +0 -40
  45. package/dist/_observables/observableInternal/logging/debugGetDependencyGraph.d.ts +0 -4
  46. package/dist/_observables/observableInternal/logging/debugger/debuggerRpc.d.ts +0 -4
  47. package/dist/_observables/observableInternal/logging/debugger/devToolsLogger.d.ts +0 -43
  48. package/dist/_observables/observableInternal/logging/debugger/rpc.d.ts +0 -41
  49. package/dist/_observables/observableInternal/logging/debugger/utils.d.ts +0 -13
  50. package/dist/_observables/observableInternal/logging/logging.d.ts +0 -30
  51. package/dist/_observables/observableInternal/map.d.ts +0 -18
  52. package/dist/_observables/observableInternal/observables/baseObservable.d.ts +0 -58
  53. package/dist/_observables/observableInternal/observables/constObservable.d.ts +0 -5
  54. package/dist/_observables/observableInternal/observables/derived.d.ts +0 -46
  55. package/dist/_observables/observableInternal/observables/derivedImpl.d.ts +0 -83
  56. package/dist/_observables/observableInternal/observables/lazyObservableValue.d.ts +0 -27
  57. package/dist/_observables/observableInternal/observables/observableFromEvent.d.ts +0 -37
  58. package/dist/_observables/observableInternal/observables/observableSignal.d.ts +0 -11
  59. package/dist/_observables/observableInternal/observables/observableSignalFromEvent.d.ts +0 -5
  60. package/dist/_observables/observableInternal/observables/observableValue.d.ts +0 -37
  61. package/dist/_observables/observableInternal/observables/observableValueOpts.d.ts +0 -8
  62. package/dist/_observables/observableInternal/reactions/autorun.d.ts +0 -56
  63. package/dist/_observables/observableInternal/reactions/autorunImpl.d.ts +0 -53
  64. package/dist/_observables/observableInternal/set.d.ts +0 -17
  65. package/dist/_observables/observableInternal/transaction.d.ts +0 -27
  66. package/dist/_observables/observableInternal/utils/promise.d.ts +0 -75
  67. package/dist/_observables/observableInternal/utils/runOnChange.d.ts +0 -7
  68. package/dist/_observables/observableInternal/utils/utils.d.ts +0 -43
  69. package/dist/_observables/observableInternal/utils/utilsCancellation.d.ts +0 -10
  70. package/dist/_observables/observableInternal/utils/valueWithChangeEvent.d.ts +0 -10
  71. package/dist/_observables/utils.d.ts +0 -15
  72. package/dist/observables.d.ts +0 -4
  73. package/dist/observables.js +0 -439
  74. package/dist/observables.js.map +0 -1
  75. package/dist/runOnChange-C00UIwqQ.js +0 -1538
  76. package/dist/runOnChange-C00UIwqQ.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,15 +1,32 @@
1
- import { Disposable } from './_observables/index';
2
- import { IDisposable } from './_observables/index';
3
- import { IObservable } from './_observables/index';
4
- import { IObservableWithChange } from './_observables/index';
5
- import { ISettableObservable } from './_observables/index';
6
- import { ITransaction } from './_observables/index';
1
+ import { Disposable } from '@vscode/observables';
2
+ import { IDisposable } from '@vscode/observables';
3
+ import { IObservable } from '@vscode/observables';
4
+ import { IObservableWithChange } from '@vscode/observables';
5
+ import { ISettableObservable } from '@vscode/observables';
6
+ import { ITransaction } from '@vscode/observables';
7
7
  import { MonarchTokenizer } from 'monaco-editor/esm/vs/editor/standalone/common/monarch/monarchLexer.js';
8
8
 
9
+ declare interface AddedItem {
10
+ readonly kind: 'added';
11
+ readonly node: AstNode;
12
+ readonly modifiedStart: number;
13
+ readonly insertedLocal: readonly AnnotatedRange[];
14
+ }
15
+
16
+ /**
17
+ * A word/character-level highlight inside a single block, in that block's
18
+ * *local* coordinate space (`0` = block start). `inserted` ranges live on a
19
+ * modified/added block, `deleted` ranges on an original/removed block.
20
+ */
21
+ declare interface AnnotatedRange {
22
+ readonly range: OffsetRange;
23
+ readonly kind: 'inserted' | 'deleted';
24
+ }
25
+
9
26
  /** Every concrete node kind, for exhaustive consumer-side dispatch. */
10
- export declare type AnyAstNode = TextAstNode | MarkerAstNode | GlueAstNode | ThematicBreakAstNode | StrongAstNode | EmphasisAstNode | StrikethroughAstNode | InlineCodeAstNode | InlineMathAstNode | LinkAstNode | ImageAstNode | HeadingAstNode | ParagraphAstNode | CodeBlockAstNode | MathBlockAstNode | BlockQuoteAstNode | ListAstNode | ListItemAstNode | TableAstNode | TableRowAstNode | TableCellAstNode | DocumentAstNode;
27
+ export declare type AnyAstNode = TextAstNode | MarkerAstNode | GlueAstNode | ThematicBreakAstNode | StrongAstNode | EmphasisAstNode | StrikethroughAstNode | InlineCodeAstNode | InlineMathAstNode | LinkAstNode | ImageAstNode | HeadingAstNode | ParagraphAstNode | FrontMatterAstNode | CodeBlockAstNode | MathBlockAstNode | BlockQuoteAstNode | ListAstNode | ListItemAstNode | TableAstNode | TableRowAstNode | TableCellAstNode | DocumentAstNode | UnhandledBlockAstNode;
11
28
 
12
- declare type AnyViewData = DocumentViewData | BlockViewData | InlineViewData | ListItemViewData | TableRowViewData | TableCellViewData | MarkerViewData | GlueViewData;
29
+ declare type AnyViewData = DocumentViewData | BlockViewData | InlineViewData | ListItemViewData | TableRowViewData | TableCellViewData | MarkerViewData | GlueViewData | DiffHunkViewData | DiffDecorationViewData;
13
30
 
14
31
  export declare abstract class AstNode {
15
32
  abstract readonly kind: string;
@@ -71,7 +88,7 @@ export declare class AsyncClipboardStrategy implements IClipboardStrategy {
71
88
  connect(context: IClipboardContext): IDisposable;
72
89
  }
73
90
 
74
- export declare type BlockAstNode = HeadingAstNode | ParagraphAstNode | CodeBlockAstNode | MathBlockAstNode | ThematicBreakAstNode | BlockQuoteAstNode | ListAstNode | TableAstNode;
91
+ export declare type BlockAstNode = HeadingAstNode | ParagraphAstNode | FrontMatterAstNode | CodeBlockAstNode | MathBlockAstNode | ThematicBreakAstNode | BlockQuoteAstNode | ListAstNode | TableAstNode | UnhandledBlockAstNode;
75
92
 
76
93
  /**
77
94
  * A block-level node. Every block may carry a {@link leadingTrivia} glue — the
@@ -92,7 +109,7 @@ declare abstract class BlockAstNodeBase extends AstNode {
92
109
  /**
93
110
  * One block's place in the rendered document.
94
111
  *
95
- * `height` is in CSS pixels. It is either a real DOM measurement
112
+ * Geometry is in editor-local CSS pixels. `height` is either a real DOM measurement
96
113
  * (`isMeasured: true`) or an estimate produced when the block is not
97
114
  * currently mounted (`isMeasured: false`). Estimates exist so virtual
98
115
  * rendering can size the scroll container without mounting every block.
@@ -107,6 +124,13 @@ export declare interface BlockMeasurement {
107
124
  readonly block: BlockAstNode;
108
125
  readonly absoluteStart: number;
109
126
  readonly height: number;
127
+ /** Local border box when mounted and measured. */
128
+ readonly rect: Rect2D | undefined;
129
+ /** Local horizontal padding-box clip when this block scrolls horizontally. */
130
+ readonly viewportClip: {
131
+ readonly left: number;
132
+ readonly right: number;
133
+ } | undefined;
110
134
  readonly isMeasured: boolean;
111
135
  readonly visualLineMap: VisualLineMap | undefined;
112
136
  readonly viewNode: ViewNode | undefined;
@@ -126,11 +150,22 @@ export declare class BlockQuoteAstNode extends BlockAstNodeBase {
126
150
  declare class BlockQuoteViewData {
127
151
  readonly ast: BlockQuoteAstNode;
128
152
  readonly content: readonly AnyViewData[];
153
+ /** False while a pending paragraph replaces the final marker-only line. */
154
+ readonly showFinalMarkerOnlyLine: boolean;
129
155
  readonly kind = "blockQuote";
130
- 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);
131
159
  }
132
160
 
133
- declare type BlockViewData = HeadingViewData | ParagraphViewData | CodeBlockViewData | MathBlockViewData | ThematicBreakViewData | BlockQuoteViewData | ListViewData | TableViewData;
161
+ /**
162
+ * All blocks whose source range intersects `[start, endExclusive]`. A
163
+ * collapsed range (start === endExclusive) matches the block containing
164
+ * that offset (with the same boundary rule as {@link findBlockAtOffset}).
165
+ */
166
+ export declare function blocksIntersecting(doc: DocumentAstNode, start: SourceOffset, endExclusive: SourceOffset): BlockAstNode[];
167
+
168
+ declare type BlockViewData = HeadingViewData | ParagraphViewData | FrontMatterViewData | CodeBlockViewData | MathBlockViewData | ThematicBreakViewData | BlockQuoteViewData | ListViewData | TableViewData | UnhandledBlockViewData;
134
169
 
135
170
  /**
136
171
  * Base view node for everything the editor renders, generic over the
@@ -151,6 +186,17 @@ export declare class BlockViewNode<T extends AnyViewData = AnyViewData> extends
151
186
  constructor(data: T, dom: globalThis.Node, children: readonly ViewNode[]);
152
187
  get block(): BlockAstNode;
153
188
  get element(): HTMLElement;
189
+ /**
190
+ * The horizontal scroll viewport for selection/caret clipping
191
+ * ({@link blockViewportClip}). For most blocks the scroller *is*
192
+ * {@link element} — a code / math / unhandled block's `element` is the very
193
+ * `overflow-x: auto` box that scrolls. A table is the exception: its
194
+ * `element` stays the inner `<table>` (so the active/markers classes and
195
+ * `.md-table` theme styling are unaffected), but the box that actually
196
+ * scrolls is the wrapping `.md-table-wrapper`, so {@link TableViewNode}
197
+ * overrides this to return that wrapper.
198
+ */
199
+ get scrollElement(): HTMLElement;
154
200
  /**
155
201
  * Whether this already-built node can stand in for `data` unchanged. The
156
202
  * builder preserves view-data identity for any subtree whose ast and
@@ -158,7 +204,7 @@ export declare class BlockViewNode<T extends AnyViewData = AnyViewData> extends
158
204
  * single identity check captures "nothing in my subtree changed" — and its
159
205
  * whole subtree, and any session it owns, are kept as-is.
160
206
  */
161
- canReuse(data: AnyViewData): boolean;
207
+ canReuse(data: AnyViewData, _options: BlockViewOptions | undefined): boolean;
162
208
  /**
163
209
  * Called by the view after this block is mounted and measured, with the
164
210
  * block's rendered height in px. The default is a no-op; subclasses whose
@@ -174,9 +220,10 @@ export declare interface BlockViewOptions {
174
220
  /**
175
221
  * Opens a link's URL. Called when the user activates a link: a plain click
176
222
  * while the link's block is inactive (rendered), or a Ctrl/Cmd+click while it
177
- * is active (source shown). Defaults to `window.open(url, '_blank')`.
223
+ * is active (source shown). Return `false` to use the anchor's native
224
+ * navigation behavior.
178
225
  */
179
- readonly onOpenLink?: (url: string, event: MouseEvent) => void;
226
+ readonly onOpenLink?: (url: string, event: MouseEvent) => false | void;
180
227
  /**
181
228
  * Colours fenced code blocks. When set, a code block's content is rendered
182
229
  * as a sequence of token spans instead of one plain text node. This is the
@@ -196,16 +243,43 @@ export declare interface BlockViewOptions {
196
243
  * `katexEditableIdentifiers.ts`).
197
244
  */
198
245
  readonly renderMath?: (request: MathRenderRequest) => MathRendering | undefined;
246
+ /**
247
+ * Pluggable factory for an in-place, interactive editor that replaces the
248
+ * *rendered* (inactive) form of a fenced code block — see
249
+ * {@link IEmbeddedCodeEditor}. When it returns an editor for the block's
250
+ * language, that editor's element is mounted instead of the highlighted
251
+ * code, and content flows both ways as string edits. Returning `undefined`
252
+ * falls back to the default rendering. EXPERIMENTAL.
253
+ */
254
+ readonly embeddedCodeEditorFactory?: IEmbeddedCodeEditorFactory;
255
+ /** Current read-only state forwarded to embedded code editors. */
256
+ readonly embeddedCodeEditorReadOnly?: boolean;
257
+ /** Identity used to invalidate previously created embedded editors. */
258
+ readonly embeddedCodeEditorFactoryVersion?: unknown;
259
+ /**
260
+ * Called when an {@link IEmbeddedCodeEditor} edits its content. `contentEdit`
261
+ * is in the block's *content* coordinates; the host translates it to a
262
+ * document edit (via {@link CodeBlockAstNode.codeOffset} and the block's
263
+ * offset) and applies it to the model.
264
+ */
265
+ readonly onEmbeddedCodeEditorEdit?: (block: CodeBlockAstNode, contentEdit: StringEdit) => void;
199
266
  }
200
267
 
201
268
  export declare class CodeBlockAstNode extends BlockAstNodeBase {
269
+ /** First token of the fenced code block info string, used for syntax highlighting. */
202
270
  readonly language: string;
271
+ /** Complete fenced code block info string, including metadata after the language token. */
272
+ readonly infoString: string;
203
273
  readonly content: readonly (MarkerAstNode | GlueAstNode)[];
204
274
  readonly leadingTrivia?: GlueAstNode | undefined;
205
275
  readonly kind = "codeBlock";
206
276
  private _previous?;
207
277
  private _contentEdit?;
208
- constructor(language: string, content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
278
+ constructor(
279
+ /** First token of the fenced code block info string, used for syntax highlighting. */
280
+ language: string,
281
+ /** Complete fenced code block info string, including metadata after the language token. */
282
+ infoString: string, content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
209
283
  get children(): readonly AstNode[];
210
284
  get openFence(): MarkerAstNode | undefined;
211
285
  get closeFence(): MarkerAstNode | undefined;
@@ -271,10 +345,260 @@ export declare class CodeBlockViewNode extends BlockViewNode<CodeBlockViewData>
271
345
  * its predecessor's subscription explicitly.
272
346
  */
273
347
  private _snapshotSub;
348
+ /**
349
+ * An in-place interactive editor (e.g. an iframe) mounted instead of the
350
+ * rendered code. Like {@link _session} it is adopted from `previous` across
351
+ * rebuilds so the underlying editor keeps its state, and must be disposed
352
+ * manually (a node reused as `previous` is never {@link dispose}d).
353
+ */
354
+ private _embeddedEditor;
355
+ private readonly _embeddedEditorFactoryVersion;
356
+ private readonly _embeddedEditorReadOnly;
357
+ canReuse(data: AnyViewData, options: BlockViewOptions | undefined): boolean;
274
358
  constructor(data: CodeBlockViewData, options: BlockViewOptions | undefined, previous: ViewNode | undefined);
275
359
  dispose(): void;
276
360
  }
277
361
 
362
+ /**
363
+ * Canonical editor command catalog. Standalone keyboard handling and host
364
+ * integrations derive their command registration and default keybindings from
365
+ * this list.
366
+ */
367
+ export declare const commands: readonly EditorCommandDefinition[];
368
+
369
+ /** A persistent comment anchored to a source range. */
370
+ declare interface Comment_2 {
371
+ readonly id: string;
372
+ /** Source range the comment refers to (its highlighted region). */
373
+ readonly range: OffsetRange;
374
+ /** The comment text. */
375
+ readonly body: string;
376
+ /** Display name of the author, if any. */
377
+ readonly author?: string;
378
+ /** Creation time (epoch ms), used to render a relative timestamp. */
379
+ readonly createdAt?: number;
380
+ }
381
+ export { Comment_2 as Comment }
382
+
383
+ /**
384
+ * A self-contained comment input box — a rounded panel with an auto-growing
385
+ * textarea and a send button, styled after the gdocs/Word "add a comment"
386
+ * affordance.
387
+ *
388
+ * This widget is *positioning-agnostic*: it only owns its own DOM and state.
389
+ * A host (the comment-mode controller, or a fixture) mounts {@link element}
390
+ * wherever it likes and is responsible for placing it relative to a selection.
391
+ *
392
+ * State is observable-driven (no framework): {@link value} reflects the live
393
+ * textarea content; submit/cancel are reported through the option callbacks.
394
+ */
395
+ export declare class CommentInputWidget extends Disposable {
396
+ private readonly _options?;
397
+ readonly element: HTMLElement;
398
+ private readonly _textarea;
399
+ private readonly _measure;
400
+ private readonly _submitButton;
401
+ private readonly _value;
402
+ /** Live, untrimmed textarea content. */
403
+ get value(): IObservable<string>;
404
+ /** The raw textarea, exposed so a host can move focus into it (e.g. on Tab). */
405
+ get inputElement(): HTMLTextAreaElement;
406
+ constructor(_options?: CommentInputWidgetOptions | undefined);
407
+ /** Move focus into the textarea (caret at the end). */
408
+ focus(): void;
409
+ /** Replace the textarea content. */
410
+ setText(text: string): void;
411
+ /** Clear the textarea. */
412
+ clear(): void;
413
+ private _submit;
414
+ private _autoSize;
415
+ }
416
+
417
+ export declare interface CommentInputWidgetOptions {
418
+ /** Placeholder shown while the textarea is empty. Defaults to "Add Comment". */
419
+ readonly placeholder?: string;
420
+ /** Called after the textarea changes size. */
421
+ readonly onDidChangeSize?: () => void;
422
+ /**
423
+ * Called when the user submits a non-empty comment (Enter or the send
424
+ * button). The text is trimmed; never called with an empty string.
425
+ */
426
+ readonly onSubmit?: (text: string) => void;
427
+ /** Called when the user dismisses the input (Escape). */
428
+ readonly onCancel?: () => void;
429
+ }
430
+
431
+ /**
432
+ * Comment mode — a gdocs/Word-style "add a comment" affordance layered on top of
433
+ * the editor *without modifying it*. It reads the editor's public observables
434
+ * ({@link EditorModel.readonlyMode}, {@link EditorModel.selection}) and the
435
+ * exposed {@link EditorView.caretRect} geometry, and mounts a
436
+ * {@link CommentInputWidget} into {@link EditorView.overlayContainer}.
437
+ *
438
+ * Behaviour:
439
+ * - Only active in read-only mode (the "review" view).
440
+ * - When a user-created selection is non-empty, the input box appears next to
441
+ * the caret (the selection's active end) but does NOT take focus, so keyboard
442
+ * selection keeps working. Programmatic selections such as find matches do
443
+ * not summon it. Press Tab to move focus into the box, then type.
444
+ * - The box appears on mouse-up, not mid-drag, so it doesn't flicker/jump
445
+ * while a selection is being dragged out (keyboard selection shows at once).
446
+ * - While the box has focus or holds a draft it is frozen in place (selection
447
+ * changes, drags and clicks no longer move it). It is dismissed by Escape,
448
+ * by submitting, or by blurring an empty box.
449
+ * - The editor's logical caret geometry remains available for anchoring in
450
+ * read-only mode even though the painted caret is hidden. While the box has
451
+ * focus, `.md-comment-active` also suppresses the painted caret in any mode.
452
+ */
453
+ export declare class CommentModeController extends Disposable {
454
+ private readonly _model;
455
+ private readonly _view;
456
+ private readonly _options?;
457
+ private static _isCommentableSelectionSource;
458
+ private readonly _widget;
459
+ private readonly _gap;
460
+ private _visible;
461
+ private _anchorX;
462
+ private _pinnedRange;
463
+ /**
464
+ * The range a comment was just submitted for. The box stays hidden for it
465
+ * until the selection changes, so submitting doesn't immediately re-summon an
466
+ * empty box on the still-selected text.
467
+ */
468
+ private _submittedRange;
469
+ constructor(_model: EditorModel, _view: EditorView, _options?: CommentModeControllerOptions | undefined);
470
+ private _update;
471
+ private _show;
472
+ private _layoutHorizontally;
473
+ /** Force-hide and clear the box (used by Escape and submit). */
474
+ private _hide;
475
+ /**
476
+ * Hide unless the user is engaged with the box: it has focus or holds a
477
+ * non-empty draft. This preserves in-progress text and keeps a focused box
478
+ * open (it is dismissed explicitly via Escape/submit, or by blurring it).
479
+ */
480
+ private _autoHide;
481
+ private _widgetHasFocus;
482
+ /**
483
+ * The visible viewport (client coords) used for the flip-above decision: the
484
+ * nearest scrollable ancestor of the editor. `.md-editor` itself spans the
485
+ * full document height and never clips, so measuring against it would always
486
+ * report room below. Falls back to the window when nothing scrolls.
487
+ */
488
+ private _getViewportRect;
489
+ private _hideAndRefocus;
490
+ private _submit;
491
+ }
492
+
493
+ export declare interface CommentModeControllerOptions {
494
+ /** Called when the user submits a comment for the current selection. */
495
+ readonly onSubmit?: (submission: CommentSubmission) => void;
496
+ /** Gap (px) between the bottom of the selection and the top of the input box. */
497
+ readonly gap?: number;
498
+ }
499
+
500
+ /** Human-readable labels (for pickers / dropdowns). */
501
+ export declare const COMMENTS_DESIGN_LABELS: Record<CommentsDesign, string>;
502
+
503
+ /** design id → presenter factory over a shared CommentsModel + EditorView. */
504
+ export declare const COMMENTS_DESIGNS: Record<CommentsDesign, CommentsPresenterFactory>;
505
+
506
+ /** The available comment rendering designs. */
507
+ export declare type CommentsDesign = 'connected' | 'vscode' | 'vscode-v2';
508
+
509
+ /**
510
+ * Seedable store of {@link Comment}s for the comment-mode contribution. Owns the
511
+ * comment list and the shared hover state; it has no opinion on rendering or
512
+ * persistence — a host seeds it via {@link set}/{@link add} and observes
513
+ * {@link comments}.
514
+ */
515
+ export declare class CommentsModel {
516
+ private readonly _comments;
517
+ /** Monotonic counter for ids of comments created via {@link create}. */
518
+ private _sequence;
519
+ /** The current comments, in insertion order. */
520
+ get comments(): IObservable<readonly Comment_2[]>;
521
+ /**
522
+ * The comment currently hovered (by its card or its highlight), or
523
+ * `undefined`. Shared so the card and the highlight can react together.
524
+ */
525
+ readonly hoveredId: ISettableObservable<string | undefined>;
526
+ /** Replace the whole comment set. */
527
+ set(comments: readonly Comment_2[]): void;
528
+ /**
529
+ * Create a comment from a user submission and append it, generating its `id`
530
+ * and `createdAt` here so id/time allocation stays the store's concern (the
531
+ * UI only supplies the range and text). Returns the created comment.
532
+ */
533
+ create(input: {
534
+ range: OffsetRange;
535
+ body: string;
536
+ author?: string;
537
+ }): Comment_2;
538
+ /** Append a comment. */
539
+ add(comment: Comment_2): void;
540
+ /** Remove a comment by id. */
541
+ remove(id: string): void;
542
+ }
543
+
544
+ /** Optional, design-specific context a presenter may use (ignored by others). */
545
+ export declare interface CommentsPresenterContext {
546
+ /** Light/dark hint for the token-wrapped VS Code widget designs. */
547
+ readonly theme?: 'light' | 'dark';
548
+ /**
549
+ * Resolves a source offset to a 1-based line number, for designs that show
550
+ * line info (the VS Code V1 card). Optional because the model itself carries
551
+ * no text; the host (which owns the source) supplies it.
552
+ */
553
+ readonly resolveLine?: (offset: number) => number;
554
+ }
555
+
556
+ /** Builds a presenter for a given model + editor view. */
557
+ export declare type CommentsPresenterFactory = (model: CommentsModel, view: EditorView, context?: CommentsPresenterContext) => ICommentsPresenter;
558
+
559
+ /** A comment the user submitted, with the source range it was anchored to. */
560
+ export declare interface CommentSubmission {
561
+ readonly text: string;
562
+ readonly range: OffsetRange;
563
+ }
564
+
565
+ /**
566
+ * Renders persistent comments as a gdocs-style side rail: each comment's range
567
+ * is highlighted (reusing the editor's selection geometry via
568
+ * {@link EditorView.rangeRects}), a leader line curves from the bottom of that
569
+ * highlight to a card stacked in the right rail, and cards never overlap.
570
+ *
571
+ * Everything is mounted into {@link EditorView.overlayContainer} so it shares
572
+ * the selection/caret coordinate space and scrolls with the document. When the
573
+ * editor's natural right margin is too narrow for the rail, the view reserves
574
+ * proportional space by padding the editor on the right — but only while there
575
+ * are comments.
576
+ */
577
+ export declare class CommentsView extends Disposable {
578
+ private readonly _model;
579
+ private readonly _view;
580
+ private readonly _layer;
581
+ private readonly _entries;
582
+ constructor(_model: CommentsModel, _view: EditorView);
583
+ private _createLayer;
584
+ private _update;
585
+ /** Create/update/remove per-comment DOM to match `comments`. */
586
+ private _reconcile;
587
+ private _createEntry;
588
+ private _fillCard;
589
+ private _disposeEntry;
590
+ /** Position highlights, cards (stacked) and leader lines. */
591
+ private _layout;
592
+ private _applyHover;
593
+ }
594
+
595
+ /** The lossless source slices of a complete block HTML comment. */
596
+ declare interface CompleteHtmlCommentSource extends HtmlCommentSourceBase {
597
+ readonly kind: 'complete';
598
+ readonly closing: '-->';
599
+ readonly trailingWhitespace: string;
600
+ }
601
+
278
602
  /**
279
603
  * A {@link MonacoSyntaxHighlighter} preloaded with a handful of common Monarch
280
604
  * grammars (plus the usual short aliases). Unknown languages fall back to an
@@ -285,13 +609,16 @@ export declare class CodeBlockViewNode extends BlockViewNode<CodeBlockViewData>
285
609
  */
286
610
  export declare function createDefaultMonacoSyntaxHighlighter(monaco: IMonarchApi, grammars: IDefaultMonarchGrammars): MonacoSyntaxHighlighter;
287
611
 
288
- export declare type CursorCommand = (ctx: CursorCommandContext) => SourceOffset;
612
+ export declare type CursorCommand = (ctx: CursorCommandContext) => CursorPosition;
289
613
 
290
614
  export declare interface CursorCommandContext {
291
615
  readonly text: string;
292
616
  readonly selection: Selection_2;
293
617
  readonly document: DocumentAstNode;
294
618
  readonly activeBlock: BlockAstNode | undefined;
619
+ readonly markerVisibleBlocks: ReadonlySet<BlockAstNode>;
620
+ readonly wordNavigationConfig: WordNavigationConfig;
621
+ readonly cursorPosition: CursorPosition;
295
622
  }
296
623
 
297
624
  export declare const cursorDocumentEnd: CursorCommand;
@@ -300,6 +627,8 @@ export declare const cursorDocumentStart: CursorCommand;
300
627
 
301
628
  export declare const cursorDown: VisualCursorCommand;
302
629
 
630
+ export declare type CursorKeyboardAction = 'left' | 'right' | 'up' | 'down' | 'wordLeft' | 'wordRight' | 'visualLineStart' | 'visualLineEnd' | 'logicalLineStart' | 'logicalLineEnd' | 'documentStart' | 'documentEnd';
631
+
303
632
  export declare const cursorLeft: CursorCommand;
304
633
 
305
634
  export declare const cursorLineEnd: CursorCommand;
@@ -309,12 +638,26 @@ export declare const cursorLineStart: CursorCommand;
309
638
  export declare const cursorMoveLeft: CursorCommand;
310
639
 
311
640
  export declare interface CursorMoveResult {
312
- readonly offset: SourceOffset;
641
+ readonly position: CursorPosition;
313
642
  readonly desiredColumn: number | undefined;
314
643
  }
315
644
 
316
645
  export declare const cursorMoveRight: CursorCommand;
317
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
+
318
661
  export declare const cursorRight: CursorCommand;
319
662
 
320
663
  export declare const cursorUp: VisualCursorCommand;
@@ -323,49 +666,129 @@ export declare const cursorUp: VisualCursorCommand;
323
666
  * Owns the blinking cursor DOM element.
324
667
  *
325
668
  * The rendering pipeline is a single `derived` whose compute callback
326
- * asks the {@link VisualLineMap} for the caret rect at the current
327
- * 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
328
671
  * {@link CursorViewRendering} value as proof. An autorun keeps the
329
672
  * derived subscribed.
330
673
  */
331
674
  export declare class CursorView extends Disposable {
332
- private readonly _parent;
333
675
  readonly element: HTMLElement;
334
676
  readonly rendering: IObservable<CursorViewRendering>;
335
- constructor(_parent: HTMLElement, options: CursorViewOptions);
677
+ constructor(options: CursorViewOptions);
336
678
  }
337
679
 
338
680
  export declare interface CursorViewOptions {
339
- readonly offset: IObservable<SourceOffset | undefined>;
681
+ readonly position: IObservable<CursorPosition | undefined>;
340
682
  readonly visualLineMap: IObservable<VisualLineMap>;
341
683
  /**
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.
684
+ * The mounted blocks, used to hide the caret when it sits at an offset that
685
+ * has been scrolled out of its (horizontally scrolling) block's viewport —
686
+ * matching how the selection is clipped there.
346
687
  */
347
- readonly pendingCaretRect?: IObservable<Rect2D | undefined>;
688
+ readonly blocks?: IObservable<readonly SelectionBlock[]>;
348
689
  }
349
690
 
350
691
  export declare class CursorViewRendering {
351
- readonly offset: SourceOffset;
692
+ readonly position: CursorPosition;
352
693
  readonly visible: boolean;
353
694
  readonly rect: Rect2D;
354
- constructor(offset: SourceOffset, visible: boolean, rect: Rect2D);
695
+ constructor(position: CursorPosition, visible: boolean, rect: Rect2D);
355
696
  }
356
697
 
698
+ export declare const cursorVisualLineEnd: VisualCursorCommand;
699
+
700
+ export declare const cursorVisualLineStart: VisualCursorCommand;
701
+
357
702
  export declare const cursorWordLeft: CursorCommand;
358
703
 
359
704
  export declare const cursorWordRight: CursorCommand;
360
705
 
706
+ export declare const DEFAULT_INDENTATION_CONFIG: IndentationConfig;
707
+
708
+ export declare const DEFAULT_WORD_NAVIGATION_CONFIG: WordNavigationConfig;
709
+
710
+ export declare const DEFAULT_WORD_SEPARATORS = "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?";
711
+
361
712
  export declare const deleteLeft: EditCommand;
362
713
 
714
+ export declare const deleteLineLeft: EditCommand;
715
+
716
+ export declare const deleteLineRight: EditCommand;
717
+
363
718
  export declare const deleteRight: EditCommand;
364
719
 
365
720
  export declare const deleteWordLeft: EditCommand;
366
721
 
367
722
  export declare const deleteWordRight: EditCommand;
368
723
 
724
+ /**
725
+ * A read-only "removed" decoration: an original block rendered (red) above its
726
+ * place in the modified document, occupying vertical space like a view-zone but
727
+ * contributing **zero** source length, so the editor's source mapping stays the
728
+ * modified document and editing is unaffected. Used for `removed` and the
729
+ * original side of a `replaced` block in editor diff mode.
730
+ */
731
+ declare class DiffDecorationViewData {
732
+ readonly ast: AstNode;
733
+ readonly side: BlockViewData;
734
+ readonly deletedRanges: readonly DiffHighlightRange[];
735
+ /** True when the whole block was removed: solid red band, no word rects. */
736
+ readonly whole: boolean;
737
+ /** Absolute offset of this block in the *original* document. */
738
+ readonly originalStart: number;
739
+ readonly kind = "diffDecoration";
740
+ constructor(ast: AstNode, side: BlockViewData, deletedRanges: readonly DiffHighlightRange[],
741
+ /** True when the whole block was removed: solid red band, no word rects. */
742
+ whole: boolean,
743
+ /** Absolute offset of this block in the *original* document. */
744
+ originalStart: number);
745
+ }
746
+
747
+ /** A word/character highlight inside one diff side, in block-local coords. */
748
+ declare interface DiffHighlightRange {
749
+ readonly range: OffsetRange;
750
+ readonly kind: 'inserted' | 'deleted';
751
+ }
752
+
753
+ /**
754
+ * A changed block rendered as its original form stacked over its modified form
755
+ * (either side may be absent for a pure deletion/insertion). It is itself a
756
+ * document child the renderer mounts like a block; its {@link ast} is the
757
+ * surviving side's ast, used only for view-node identity/reuse.
758
+ */
759
+ declare class DiffHunkViewData {
760
+ readonly ast: AstNode;
761
+ readonly original: DiffSideViewData | undefined;
762
+ readonly modified: DiffSideViewData | undefined;
763
+ readonly kind = "diffHunk";
764
+ constructor(ast: AstNode, original: DiffSideViewData | undefined, modified: DiffSideViewData | undefined);
765
+ }
766
+
767
+ /**
768
+ * The recursive classification of a diff. Each item describes one aligned
769
+ * position in the merged document:
770
+ *
771
+ * - `unchanged` — render the (modified) node once, neutral.
772
+ * - `added` — exists only in the modified document (green).
773
+ * - `removed` — exists only in the original document (red).
774
+ * - `replaced` — a *leaf* block changed in place → render original over
775
+ * modified, with word-level {@link AnnotatedRange}s on each.
776
+ * - `nested` — a *container* changed → render it once and diff its
777
+ * {@link NestedItem.children} recursively.
778
+ *
779
+ * Offsets ({@link UnchangedItem.modifiedStart} etc.) are absolute in their
780
+ * respective documents, so a renderer/visualizer can slice the source text.
781
+ */
782
+ declare type DiffItem = UnchangedItem | AddedItem | RemovedItem | ReplacedItem | NestedItem;
783
+
784
+ /** One side (original or modified) of a {@link DiffHunkViewData}. */
785
+ declare interface DiffSideViewData {
786
+ readonly view: BlockViewData;
787
+ /** Render in active form (markers/whitespace visible). */
788
+ readonly active: boolean;
789
+ readonly ranges: readonly DiffHighlightRange[];
790
+ }
791
+
369
792
  export declare class DocumentAstNode extends AstNode {
370
793
  readonly content: readonly (BlockAstNode | GlueAstNode)[];
371
794
  readonly kind = "document";
@@ -390,14 +813,21 @@ declare interface DocumentBlockViewData {
390
813
  readonly view: BlockViewData;
391
814
  }
392
815
 
393
- /** A mounted document child: a block, a run of inter-block glue, or the
394
- * transient empty paragraph (see {@link PendingParagraphViewData}). */
816
+ /** A mounted document child: a block, a run of inter-block glue, the
817
+ * transient empty paragraph (see {@link PendingParagraphViewData}), or a
818
+ * {@link DiffHunkViewData diff hunk} (stacked original/modified blocks). */
395
819
  declare interface DocumentChildViewData {
396
820
  readonly absoluteStart: number;
397
821
  /** For a block: selection reaches it. For glue: always false (unowned, hidden). */
398
822
  readonly isActive: boolean;
399
- readonly view: BlockViewData | GlueViewData | PendingParagraphViewData;
400
- readonly kind: 'block' | 'glue' | 'pendingParagraph';
823
+ readonly view: BlockViewData | GlueViewData | PendingParagraphViewData | DiffHunkViewData | DiffDecorationViewData;
824
+ readonly kind: 'block' | 'glue' | 'pendingParagraph' | 'diffHunk' | 'diffDecoration';
825
+ /**
826
+ * Diff mode: how this (modified) block changed. `added` = a whole new block
827
+ * (strong green band, no inline rects); `modified` = a partial change (light
828
+ * band + inline rects on the changed words).
829
+ */
830
+ readonly diffKind?: 'added' | 'modified';
401
831
  }
402
832
 
403
833
  /**
@@ -454,7 +884,7 @@ declare class DocumentViewData {
454
884
  export declare class DocumentViewNode extends ViewNode {
455
885
  readonly blocks: readonly DocumentBlock[];
456
886
  /** The transient empty-paragraph element, when one is armed. */
457
- readonly pendingElement?: HTMLElement | undefined;
887
+ readonly pendingParagraph?: PendingParagraphViewNode | undefined;
458
888
  static create(viewData: DocumentViewData, options: BlockViewOptions | undefined, previous: DocumentViewNode | undefined): DocumentViewNode;
459
889
  private constructor();
460
890
  /** The stable content element this document mounts its children into. */
@@ -476,6 +906,26 @@ export declare type EditCommand = (ctx: CursorCommandContext) => {
476
906
  readonly selection: Selection_2;
477
907
  } | undefined;
478
908
 
909
+ export declare type EditKeyboardAction = 'deleteLeft' | 'deleteRight' | 'deleteWordLeft' | 'deleteWordRight' | 'deleteLineLeft' | 'deleteLineRight';
910
+
911
+ export declare interface EditorCommandDefinition {
912
+ readonly id: `markdown.editor.${string}`;
913
+ readonly title: string;
914
+ readonly action: EditorKeyboardAction;
915
+ readonly keybindings: readonly EditorCommandKeybinding[];
916
+ /**
917
+ * Local commands must execute synchronously in the webview instead of being
918
+ * forwarded through the VS Code keybinding service.
919
+ */
920
+ readonly routing?: 'host' | 'local';
921
+ }
922
+
923
+ export declare interface EditorCommandKeybinding {
924
+ readonly key: string;
925
+ readonly modifiers?: KeyboardModifiers;
926
+ readonly platforms?: readonly KeyboardPlatform[];
927
+ }
928
+
479
929
  /**
480
930
  * Translates raw browser input (mouse, keyboard, EditContext) into model
481
931
  * mutations. Knows about DOM event types but never reads/writes the DOM
@@ -484,19 +934,41 @@ export declare type EditCommand = (ctx: CursorCommandContext) => {
484
934
  *
485
935
  * Owns the only non-derivable controller state:
486
936
  * - `_desiredColumn` — sticky column for up/down navigation
937
+ * - `_clickCount` / `_lastPointerDown` — multi-click detection for pointer
938
+ * input, since `pointerdown` events (unlike `mousedown`) don't populate
939
+ * `detail` with a click count.
487
940
  */
488
941
  export declare class EditorController extends Disposable {
489
942
  private readonly _model;
490
943
  private readonly _view;
944
+ readonly findController: FindController | undefined;
491
945
  private _desiredColumn;
946
+ private readonly _keyboardPlatform;
947
+ private readonly _keyboardProfile;
948
+ private readonly _forwardedKeyboardProfile;
949
+ private readonly _historyStrategy;
950
+ private readonly _indentation;
951
+ private readonly _tabFocusStatus;
952
+ private _tabMovesFocus;
953
+ /** Running click count for the current multi-click sequence (1, 2, 3, …). */
954
+ private _clickCount;
955
+ /** Timestamp and position of the previous pointer-down, for multi-click detection. */
956
+ private _lastPointerDown;
492
957
  constructor(_model: EditorModel, _view: EditorView, options?: EditorControllerOptions);
493
958
  private readonly _handleTextUpdate;
494
- private readonly _handleMouseDown;
959
+ /** Handle typed, pasted, or command-generated text while a paragraph is pending. */
960
+ private _handlePendingInput;
961
+ private _deletePendingText;
962
+ private readonly _handlePointerDown;
495
963
  private _makeCursorContext;
496
964
  private _makeVisualCursorContext;
497
965
  private _executeCursorCommand;
498
966
  private _executeEditCommand;
967
+ private _runUndoableEdit;
499
968
  private _executeVisualCursorCommand;
969
+ private _cursorDown;
970
+ private _setUserSelection;
971
+ private _applyCursorPosition;
500
972
  /** Move the cursor down one visual line (Arrow Down). */
501
973
  cursorDown(extend?: boolean): void;
502
974
  /** Move the cursor up one visual line (Arrow Up). */
@@ -504,12 +976,34 @@ export declare class EditorController extends Disposable {
504
976
  private _selectedText;
505
977
  private readonly _updateModifierState;
506
978
  private readonly _clearModifierState;
979
+ /**
980
+ * Drop any native DOM selection over the rendered text.
981
+ *
982
+ * The editor paints selection from `model.selection`, so a browser
983
+ * selection there is always spurious: nothing reads it (copy/cut read the
984
+ * model, hit-testing uses the measured layout) and nothing clears it, so it
985
+ * lingers as a second highlight even after the caret moves away.
986
+ * {@link isCaretMotionKey} stops the common source synchronously; this is
987
+ * the backstop for the rest of the browser's editing commands, which are
988
+ * platform- and version-specific and cannot be enumerated (Shift+PageDown
989
+ * and macOS Shift+Ctrl+B both reach one today).
990
+ *
991
+ * Scoped twice so it only ever discards selections the editor owns: the
992
+ * range must touch the rendered text (overlays such as comment widgets sit
993
+ * beside it and stay selectable), and input focus must still be inside this
994
+ * editor (so a host find-in-page, which selects while its own input is
995
+ * focused, is left alone).
996
+ */
997
+ private readonly _discardNativeSelection;
507
998
  private readonly _handleKeyDown;
999
+ executeCommand(command: EditorCommandDefinition): void;
1000
+ private _executeKeyboardAction;
508
1001
  /**
509
1002
  * Context-aware Enter: splits / line-breaks via {@link insertSmartEnter}, or
510
1003
  * arms a transient empty paragraph when at the end of a paragraph.
511
1004
  */
512
1005
  private _smartEnter;
1006
+ private _registerTabFocusAccessibility;
513
1007
  }
514
1008
 
515
1009
  /** Options for an {@link EditorController}. */
@@ -520,10 +1014,79 @@ export declare interface EditorControllerOptions {
520
1014
  * strategy (e.g. `AsyncClipboardStrategy`) in hosts that swallow them.
521
1015
  */
522
1016
  readonly clipboardStrategy?: IClipboardStrategy;
1017
+ /**
1018
+ * Where undo and redo are executed: `LocalHistoryStrategy` for a
1019
+ * self-contained editor, or a strategy that forwards to the host's own
1020
+ * document history. Left unset, the chords are passed on to the host.
1021
+ */
1022
+ readonly historyStrategy?: IHistoryStrategy;
1023
+ readonly keyboardPlatform?: KeyboardPlatform;
1024
+ readonly keyboardProfile?: KeyboardProfile;
1025
+ /**
1026
+ * Bindings owned by the host. Matching events have their browser default
1027
+ * suppressed but continue propagating so the host keybinding service sees them.
1028
+ */
1029
+ readonly forwardedKeyboardProfile?: KeyboardProfile;
1030
+ /** Tab-stop settings used outside semantic list indentation. */
1031
+ readonly indentation?: IndentationConfig;
1032
+ readonly find?: false;
523
1033
  }
524
1034
 
1035
+ /**
1036
+ * The editor overlay's local CSS-pixel coordinate space.
1037
+ *
1038
+ * Browser geometry and pointer APIs expose viewport client coordinates. This
1039
+ * boundary converts them immediately into the coordinate system shared by the
1040
+ * editor content and its overlays. Range rectangles are axis-aligned, so the
1041
+ * current implementation deliberately supports positive axis-aligned scale and
1042
+ * translation only.
1043
+ */
1044
+ export declare class EditorCoordinateSpace {
1045
+ private readonly _getLocalToClientMatrix;
1046
+ static forSvgOverlay(overlay: SVGSVGElement): EditorCoordinateSpace;
1047
+ private constructor();
1048
+ capture(): EditorCoordinateTransform;
1049
+ }
1050
+
1051
+ /** A stable coordinate conversion captured for one measurement operation. */
1052
+ export declare class EditorCoordinateTransform {
1053
+ private readonly _localToClient;
1054
+ private readonly _clientToLocal;
1055
+ constructor(_localToClient: DOMMatrix);
1056
+ toLocalPoint(point: Pick<Point2D, 'x' | 'y'>): Point2D;
1057
+ toClientPoint(point: Pick<Point2D, 'x' | 'y'>): Point2D;
1058
+ toLocalRect(rect: Pick<DOMRectReadOnly, 'left' | 'top' | 'width' | 'height'>): Rect2D;
1059
+ toClientRect(rect: Pick<Rect2D, 'left' | 'top' | 'width' | 'height'>): Rect2D;
1060
+ private _convertRect;
1061
+ }
1062
+
1063
+ export declare type EditorKeyboardAction = {
1064
+ readonly kind: 'cursor';
1065
+ readonly command: CursorKeyboardAction;
1066
+ readonly extend: boolean;
1067
+ } | {
1068
+ readonly kind: 'edit';
1069
+ readonly command: EditKeyboardAction;
1070
+ } | {
1071
+ readonly kind: 'history';
1072
+ readonly command: HistoryKeyboardAction;
1073
+ } | {
1074
+ readonly kind: 'tab';
1075
+ readonly command: TabKeyboardAction;
1076
+ } | {
1077
+ readonly kind: 'toggleTabFocus';
1078
+ } | {
1079
+ readonly kind: 'selectAll';
1080
+ } | {
1081
+ readonly kind: 'enter';
1082
+ readonly command: 'smartEnter' | 'insertParagraph' | 'insertHardLineBreak';
1083
+ };
1084
+
525
1085
  export declare class EditorModel {
526
1086
  private readonly _parser;
1087
+ private readonly _sourceEditListeners;
1088
+ private readonly _sourceTextIds;
1089
+ private _lastSourceTextId;
527
1090
  /**
528
1091
  * The most recent edit applied to {@link sourceText}, used by
529
1092
  * {@link document} to let the parser link incrementally edited code
@@ -532,11 +1095,24 @@ export declare class EditorModel {
532
1095
  */
533
1096
  private _pendingEdit;
534
1097
  readonly sourceText: ISettableObservable<StringValue, void>;
1098
+ readonly wordNavigationConfig: ISettableObservable<WordNavigationConfig, void>;
1099
+ /**
1100
+ * Read-only mode. When `true`, the editor never reveals a block's source
1101
+ * markers (markdown special characters like `**`, `#`, list bullets, code
1102
+ * fences, `$…$`) — every block stays in its clean rendered form regardless of
1103
+ * where the caret/selection is — and text-editing commands are ignored.
1104
+ * Explicit interactions with rendered controls, such as task checkboxes,
1105
+ * remain available. Plain text selection still works everywhere (so the user
1106
+ * can copy). The default (`false`) is the normal editing mode where the active
1107
+ * block reveals its markers.
1108
+ */
1109
+ readonly readonlyMode: ISettableObservable<boolean, void>;
535
1110
  /**
536
1111
  * The current selection, or `undefined` when the editor has no caret
537
1112
  * (e.g. an inactive/unfocused rendering).
538
1113
  */
539
1114
  readonly selection: ISettableObservable<Selection_2 | undefined, void>;
1115
+ readonly selectionSource: ISettableObservable<SelectionSource, void>;
540
1116
  /**
541
1117
  * Whether a Ctrl/Cmd modifier is currently held. Set by the controller from
542
1118
  * live keyboard state; the view reads it to show the link-open affordance
@@ -544,6 +1120,14 @@ export declare class EditorModel {
544
1120
  * whose block is active.
545
1121
  */
546
1122
  readonly ctrlOrMetaDown: ISettableObservable<boolean, void>;
1123
+ /**
1124
+ * Whether a pointer-driven selection drag is currently in progress. Set by
1125
+ * the controller between the pointer-down that starts the drag and the
1126
+ * pointer-up/cancel that ends it. Contributions read it to defer UI that
1127
+ * would otherwise flicker mid-drag (e.g. the comment input box appears only
1128
+ * once the drag ends).
1129
+ */
1130
+ readonly isSelecting: ISettableObservable<boolean, void>;
547
1131
  /**
548
1132
  * Gutter markers (source-control style change indicators) painted in the
549
1133
  * left gutter. Each entry maps a source {@link OffsetRange} to a change kind
@@ -563,16 +1147,17 @@ export declare class EditorModel {
563
1147
  * The transient empty-paragraph editing state, or `undefined` when none is
564
1148
  * armed. See {@link PendingParagraph}. This is *not* document data — it is
565
1149
  * cleared by any source edit and lives only between the Enter that armed it
566
- * and the next keystroke.
1150
+ * and the next content-producing edit.
567
1151
  */
568
1152
  readonly pendingParagraph: ISettableObservable<PendingParagraph | undefined, void>;
569
1153
  readonly cursorOffset: IObservableWithChange<number | undefined, void>;
1154
+ readonly cursorPosition: IObservableWithChange<CursorPosition | undefined, void>;
570
1155
  /**
571
1156
  * The parsed document. Threads the previous document into the parser so
572
1157
  * unchanged blocks keep their object identity across reparses (see
573
1158
  * {@link MarkdownParser.parse}). Writing `previous` inside the compute is
574
- * a safe optimization: `derived` only recomputes when `sourceText`
575
- * changes, and the result is structurally identical to a full reparse.
1159
+ * safe: unchanged source reuses it directly, while changed source produces
1160
+ * a result structurally identical to a full reparse.
576
1161
  */
577
1162
  readonly document: IObservableWithChange<DocumentAstNode, void>;
578
1163
  /**
@@ -589,28 +1174,62 @@ export declare class EditorModel {
589
1174
  * collapsed this is a one-element set holding {@link activeBlock}.
590
1175
  */
591
1176
  readonly activeBlocks: IObservableWithChange<Set<BlockAstNode>, void>;
1177
+ /**
1178
+ * The baseline document to diff against. When set, the editor renders in
1179
+ * diff mode: the modified document ({@link document}) stays editable, while
1180
+ * the baseline's removed/changed blocks are shown as read-only decorations.
1181
+ * `undefined` (the default) renders normally.
1182
+ */
1183
+ readonly baseline: ISettableObservable<StringValue | undefined, void>;
1184
+ private readonly _baselineDocument;
1185
+ /**
1186
+ * The diff of {@link baseline} → {@link document}, or `undefined` when no
1187
+ * baseline is set. The view renders the {@link DiffItem}s as stacked
1188
+ * decorations; `insertedRanges` (modified-side change spans) drive the green
1189
+ * word-level highlight.
1190
+ */
1191
+ readonly diff: IObservableWithChange< {
1192
+ items: DiffItem[];
1193
+ insertedRanges: OffsetRange[];
1194
+ changedBlocks: Set<BlockAstNode>;
1195
+ } | undefined, void>;
1196
+ readonly markerVisibleBlocks: IObservableWithChange<Set<BlockAstNode>, void>;
1197
+ onWillApplySourceEdit(listener: (event: SourceEditEvent) => void): IDisposable;
1198
+ /** Returns a stable per-object identity without retaining the source text. */
1199
+ getSourceTextId(sourceText: StringValue): number;
592
1200
  /**
593
1201
  * Arm a {@link PendingParagraph} at the given gap, minting a fresh synthetic
594
1202
  * AST node for it, and park the caret at the gap start. No source edit is
595
1203
  * applied — the blank line exists only in the view until it is materialized.
596
1204
  */
597
- armPendingParagraph(req: {
598
- anchorBlock: BlockAstNode;
599
- replaceRange: OffsetRange;
600
- atEof: boolean;
601
- }): void;
1205
+ armPendingParagraph(req: Omit<PendingParagraph, 'syntheticAst' | 'cursorLine' | 'text'>): void;
602
1206
  /** Discard the pending paragraph (if any) without touching the source. */
603
1207
  cancelPendingParagraph(): void;
1208
+ /**
1209
+ * Replace the source with an authoritative value from the host, mapping the
1210
+ * selection through the changed span and atomically discarding transient
1211
+ * state anchored to the previous parse.
1212
+ */
1213
+ replaceSourceText(text: StringValue): void;
1214
+ /** Replace the transient horizontal whitespace on the pending line. */
1215
+ setPendingParagraphText(text: string): void;
604
1216
  /**
605
1217
  * 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.
1218
+ * text, including any transient indentation, is separated from its neighbours
1219
+ * by blank lines, and place the caret after it.
608
1220
  */
609
1221
  materializePendingParagraph(text: string): void;
610
- applyEdit(edit: StringEdit): void;
1222
+ /** Sets a rendered task checkbox state in either editing or read-only mode. */
1223
+ setTaskCheckboxChecked(item: ListItemAstNode, checked: boolean): void;
1224
+ applyEdit(edit: StringEdit, selection?: Selection_2): void;
611
1225
  applyEditForSelection(edit: StringEdit): void;
1226
+ private _applySourceEdit;
1227
+ private _identifySourceEdit;
1228
+ private _emitWillApplySourceEdit;
612
1229
  }
613
1230
 
1231
+ export declare type EditorOverlayPosition = 'top-chrome' | 'below-selection' | 'above-decorations';
1232
+
614
1233
  /**
615
1234
  * Pure-render view of an {@link EditorModel}.
616
1235
  *
@@ -640,6 +1259,8 @@ export declare class EditorView extends Disposable {
640
1259
  readonly element: HTMLElement;
641
1260
  readonly editContext: EditContext;
642
1261
  readonly measuredLayout: MeasuredLayoutModel;
1262
+ readonly coordinateSpace: EditorCoordinateSpace;
1263
+ readonly forcedMarkerVisibleBlocks: ISettableObservable<ReadonlySet<BlockAstNode>, void>;
643
1264
  /**
644
1265
  * Inner container that holds the rendered document and the cursor/selection
645
1266
  * overlays. The outer {@link element} spans the full width; this container
@@ -647,9 +1268,14 @@ export declare class EditorView extends Disposable {
647
1268
  * to their parent's box) stay aligned with the content.
648
1269
  */
649
1270
  private readonly _contentContainer;
1271
+ private readonly _resizeObserver;
650
1272
  private readonly _cursorView;
651
1273
  private readonly _selectionView;
652
1274
  private readonly _gutterMarkersView;
1275
+ private readonly _diffHighlightsView;
1276
+ private _readonlyToggleButton;
1277
+ private readonly _editContextSuspensions;
1278
+ private readonly _revealOcclusions;
653
1279
  /**
654
1280
  * The mounted block sequence, in source order. Rebuilt (not mutated) each
655
1281
  * frame by {@link DocumentViewNode.create}; the view just swaps one
@@ -657,8 +1283,11 @@ export declare class EditorView extends Disposable {
657
1283
  * (those go through the measured-layout model).
658
1284
  */
659
1285
  private readonly _document;
1286
+ private readonly _embeddedCodeEditorFactoryVersion;
660
1287
  /** The current view-node tree (AST overlaid with rendered DOM), for debugging. */
661
1288
  get documentViewNode(): IObservable<DocumentViewNode | undefined>;
1289
+ /** Re-resolves embedded code editors while preserving the surrounding editor view. */
1290
+ refreshEmbeddedCodeEditors(): void;
662
1291
  /**
663
1292
  * Last frame's view-data overlay, threaded back into
664
1293
  * {@link buildDocumentViewData} so any subtree whose ast and selection flags
@@ -670,18 +1299,44 @@ export declare class EditorView extends Disposable {
670
1299
  private readonly _viewData;
671
1300
  get viewData(): IObservable<DocumentViewData | undefined>;
672
1301
  /**
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.
1302
+ * Whether the editor is genuinely focused: focus rests somewhere inside the
1303
+ * editor subtree *and* its window is focused. Mirrored onto the root as
1304
+ * `.md-focused`, which gates the painted caret the blinking cursor is only
1305
+ * shown while this is `true`, so it never blinks in an unfocused editor or
1306
+ * after the window loses focus. Only the caret's visibility is affected; the
1307
+ * logical selection and caret geometry ({@link caretRect}) are unchanged.
677
1308
  */
678
- private readonly _pendingCaretRect;
1309
+ private readonly _focused;
1310
+ get focused(): IObservable<boolean>;
679
1311
  /**
680
1312
  * The block cache projected for views (selection painting) that need to
681
1313
  * react to mount/unmount. Derived from {@link _document}, so it stays in
682
1314
  * lock-step without any manual bookkeeping.
683
1315
  */
684
1316
  private readonly _selectionBlocksObs;
1317
+ /**
1318
+ * The caret rect (zero width) at the selection's active end, in
1319
+ * {@link overlayContainer}-local coordinates, or `undefined` when there is no
1320
+ * caret. This is the same geometry the editor paints its cursor from, so
1321
+ * contributions (e.g. comment mode) can anchor an overlay to the active end of
1322
+ * the selection — where the user's cursor is — without re-deriving geometry.
1323
+ */
1324
+ private readonly _caretRect;
1325
+ get caretRect(): IObservable<Rect2D | undefined>;
1326
+ /**
1327
+ * The container that establishes the positioning context for the editor's
1328
+ * overlays (cursor, selection, gutter). Contributions mount their own
1329
+ * absolutely-positioned overlays here so they share the coordinate space of
1330
+ * {@link caretRect}.
1331
+ */
1332
+ get overlayContainer(): HTMLElement;
1333
+ /**
1334
+ * Selection-style rectangles covering `range`, in {@link overlayContainer}-
1335
+ * local coordinates — the same geometry the live selection paints. Exposed so
1336
+ * contributions (e.g. persistent comments) can highlight arbitrary ranges and
1337
+ * anchor overlays to them. Recomputes when the measured layout changes.
1338
+ */
1339
+ rangeRects(range: OffsetRange): IObservable<readonly SelectionRect[]>;
685
1340
  constructor(_model: EditorModel, _options?: EditorViewOptions | undefined);
686
1341
  /**
687
1342
  * Mirrors the model's live Ctrl/Cmd state onto the editor root as
@@ -690,13 +1345,92 @@ export declare class EditorView extends Disposable {
690
1345
  * a plain click, but an active link only opens with the modifier held.
691
1346
  */
692
1347
  private _setupModifierTracking;
1348
+ /**
1349
+ * Tracks whether the editor is genuinely focused and mirrors it onto the
1350
+ * root as `.md-focused` so CSS can gate the painted caret. "Focused" means
1351
+ * focus rests somewhere inside the editor subtree *and* the window itself is
1352
+ * focused; either condition failing (focus moving elsewhere, or the window
1353
+ * losing focus) hides the blinking caret while leaving the logical selection
1354
+ * and caret geometry intact.
1355
+ */
1356
+ private _setupFocusTracking;
1357
+ /**
1358
+ * Renders the edit/read-only mode toggle. It flips the model's
1359
+ * {@link EditorModel.readonlyMode}: when locked (read-only) every block stays
1360
+ * in its clean rendered form (no markdown markers revealed) and edits are
1361
+ * ignored, while text selection still works. The control lives in a
1362
+ * zero-height *sticky* host inside the centered content container, so the
1363
+ * lock follows the content's right edge and remains pinned as the document
1364
+ * scrolls. The current mode is also mirrored onto the root as `.md-readonly`
1365
+ * for any CSS hooks.
1366
+ */
1367
+ private _setupReadonlyToggle;
1368
+ /** Draws attention to the mode toggle after text input is attempted while locked. */
1369
+ showReadonlyEditingAttempt(): void;
693
1370
  focus(): void;
1371
+ mountOverlay(element: HTMLElement | SVGSVGElement, position: EditorOverlayPosition): IDisposable;
1372
+ /** Registers floating editor chrome that should count as covering a range during reveal. */
1373
+ registerRevealOcclusion(element: Element): IDisposable;
1374
+ /**
1375
+ * Temporarily detaches the root {@link EditContext} while focus is inside
1376
+ * nested editor chrome. Chromium otherwise reclaims focus from non-text
1377
+ * controls inside the EditContext host, breaking keyboard access to controls
1378
+ * such as the find actions and read-only toggle.
1379
+ */
1380
+ suspendEditContextWhileFocused(element: HTMLElement): IDisposable;
1381
+ revealRangeInCenterIfOutsideViewport(range: OffsetRange, behavior?: ScrollBehavior): IDisposable;
1382
+ /**
1383
+ * Samples the ambient focus state that decides whether taking focus on open
1384
+ * would steal it from an explicit user target: whether the window is focused
1385
+ * and whether focus is still unclaimed (no active element, or the `<body>`
1386
+ * fallback).
1387
+ */
1388
+ private _sampleAutoFocusEnvironment;
1389
+ /**
1390
+ * One-shot guarded focus attempt: focuses the editor only if doing so will
1391
+ * not steal focus from an explicit user target — the window must already be
1392
+ * focused and no other element may have claimed focus yet. Returns whether
1393
+ * focus was taken. A no-op for a background window or when the user has
1394
+ * already focused something else. {@link autoFocusOnOpen} builds the
1395
+ * open-time behavior on top of this primitive.
1396
+ */
1397
+ tryAutoFocus(): boolean;
1398
+ /**
1399
+ * Focuses the editor when it opens without ever stealing focus from an
1400
+ * explicit user target. Tries once immediately; if the window is not focused
1401
+ * yet — a common open-time race where the editor is mounted before the host
1402
+ * routes focus to its window — the guarded attempt is deferred to the next
1403
+ * time the window gains focus and re-evaluated then. The deferral is
1404
+ * one-shot, so a later, unrelated window refocus never grabs focus, and the
1405
+ * re-check still respects any target the user has claimed in the meantime.
1406
+ */
1407
+ autoFocusOnOpen(): void;
1408
+ /**
1409
+ * Own point→offset resolution. When `true` (the default),
1410
+ * {@link resolveOffsetFromPoint} ignores the platform DOM hit-test
1411
+ * (`caretPositionFromPoint`) and snaps the point to the nearest offset purely
1412
+ * from the rendered {@link VisualLineMap} geometry — picking the nearest
1413
+ * visual line by `y`, then the nearest offset on it by `x`. Because a table
1414
+ * row's cells share one horizontal line band, this makes the whole width of a
1415
+ * row resolve into that row (rather than only the cell boxes), with no visible
1416
+ * layout change. It also lets a drag keep extending toward off-viewport points
1417
+ * (e.g. the pointer leaving the window), which the platform hit-test cannot
1418
+ * resolve. Set to `false` to fall back to the platform DOM hit-test.
1419
+ */
1420
+ readonly geometricHitTest: ISettableObservable<boolean, void>;
694
1421
  /**
695
1422
  * Client coordinates → absolute source offset (any block). Used during
696
1423
  * drag to keep extending the selection even when the pointer leaves the
697
- * original block.
1424
+ * original block. Honours {@link geometricHitTest}.
698
1425
  */
699
1426
  resolveOffsetFromPoint(point: Point2D): SourceOffset | undefined;
1427
+ /**
1428
+ * Resolve table-cell hits that have no measurable text run. Empty cells map
1429
+ * from their own box instead of snapping to a neighboring cell; element-only
1430
+ * content (for example an inactive image) maps through the hit element's view
1431
+ * node. Text-bearing cells keep the normal pixel-precise line-map/DOM path.
1432
+ */
1433
+ private _resolveTableCellOffset;
700
1434
  /**
701
1435
  * Whether a client point falls on the rendered document content, as
702
1436
  * opposed to the surrounding editor padding (the green area). Uses DOM
@@ -706,6 +1440,14 @@ export declare class EditorView extends Disposable {
706
1440
  * have `pointer-events: none`, so the hit-test sees through them.
707
1441
  */
708
1442
  isPointInContent(point: Point2D): boolean;
1443
+ /**
1444
+ * Whether `range` intersects the rendered source text — the region whose
1445
+ * selection this editor paints itself from `model.selection`. This also
1446
+ * catches select-all ranges whose endpoints surround the rendered content.
1447
+ * Overlays anchored beside the text (comment widgets and the like) are *not*
1448
+ * part of it and keep their own native selection behaviour.
1449
+ */
1450
+ intersectsRenderedContent(range: Range): boolean;
709
1451
  private readonly _renderAutorun;
710
1452
  /** Current mounted blocks, or empty before the first render. */
711
1453
  private get _blocks();
@@ -715,6 +1457,18 @@ export declare class EditorView extends Disposable {
715
1457
  * is not read here, so there is no feedback loop into the render autorun.
716
1458
  */
717
1459
  private _publishMeasurements;
1460
+ /**
1461
+ * Paint the diff highlights via the CSS Custom Highlight API: green over the
1462
+ * inserted/changed modified ranges (mapped on the document's own DOM), and
1463
+ * red over each {@link DiffDecorationViewNode}'s deleted ranges (mapped on
1464
+ * the decoration's own subtree). No DOM is mutated, so reconciliation and
1465
+ * editing are unaffected.
1466
+ */
1467
+ private _paintDiff;
1468
+ private _clearDiff;
1469
+ private _syncEditContextAttachment;
1470
+ private _revealRange;
1471
+ private _isRevealOccluded;
718
1472
  }
719
1473
 
720
1474
  export declare interface EditorViewOptions extends BlockViewOptions {
@@ -725,6 +1479,12 @@ export declare interface EditorViewOptions extends BlockViewOptions {
725
1479
  * only) unless a theme class is supplied.
726
1480
  */
727
1481
  readonly classNames?: readonly string[];
1482
+ /**
1483
+ * Whether to render the sticky edit/read-only toggle at the top-right edge
1484
+ * of the content. Defaults to `true`; set to `false` to omit it (e.g. in
1485
+ * fixtures that focus on selection rendering).
1486
+ */
1487
+ readonly showReadonlyToggle?: boolean;
728
1488
  /**
729
1489
  * Controls "limited width mode". The observable yields the maximum content
730
1490
  * width in pixels, or `undefined` to let the content fill the available
@@ -735,6 +1495,14 @@ export declare interface EditorViewOptions extends BlockViewOptions {
735
1495
  * root ({@link element}) always spans the full available width.
736
1496
  */
737
1497
  readonly limitedWidth?: IObservable<number | undefined>;
1498
+ /**
1499
+ * Diff mode only: render every read-only original decoration in active
1500
+ * (source) form, so even whole-block removals expose their markdown markers
1501
+ * as real text. Used by the diff-coverage fixture to verify that every
1502
+ * changed original character is rendered somewhere; off in normal use, where
1503
+ * whole removals show a clean solid band.
1504
+ */
1505
+ readonly diffDecorationsActive?: boolean;
738
1506
  }
739
1507
 
740
1508
  export declare class EmphasisAstNode extends AstNode {
@@ -754,6 +1522,111 @@ declare class EmphasisViewData {
754
1522
  constructor(ast: EmphasisAstNode, content: readonly AnyViewData[]);
755
1523
  }
756
1524
 
1525
+ export declare function escapeFindRegex(value: string): string;
1526
+
1527
+ export declare const FIND_MATCH_LIMIT = 19999;
1528
+
1529
+ export declare function findBlockAtOffset(doc: DocumentAstNode, offset: SourceOffset): BlockAstNode | undefined;
1530
+
1531
+ export declare class FindController extends Disposable {
1532
+ private readonly _editorModel;
1533
+ private readonly _view;
1534
+ private readonly _options;
1535
+ readonly model: FindModel;
1536
+ readonly widget: FindWidget;
1537
+ private readonly _selectionForScope;
1538
+ private _forcedMatch;
1539
+ private _selectedMatch;
1540
+ private _observedSourceTextId;
1541
+ private readonly _sourceEditTracker;
1542
+ private _revealRequest;
1543
+ constructor(_editorModel: EditorModel, _view: EditorView, _options: FindControllerOptions);
1544
+ private _setForcedMarkerVisibleBlocks;
1545
+ openAndFocus(): void;
1546
+ close(): void;
1547
+ private _handleKeyDown;
1548
+ private _cancelRevealRequest;
1549
+ private _findByKeyboard;
1550
+ private _querySeed;
1551
+ private _prepareSeed;
1552
+ private _selectedSingleLineText;
1553
+ private _toggleFindInSelection;
1554
+ }
1555
+
1556
+ export declare interface FindControllerOptions {
1557
+ readonly keyboardPlatform: KeyboardPlatform;
1558
+ }
1559
+
1560
+ export declare type FindDirection = 'next' | 'previous';
1561
+
1562
+ export declare class FindHighlightsView extends Disposable {
1563
+ private readonly _view;
1564
+ private readonly _matchesLayer;
1565
+ private readonly _currentLayer;
1566
+ private readonly _highlightRegistration;
1567
+ private readonly _resizeObserver;
1568
+ private readonly _resizeObservedElements;
1569
+ private _snapshot;
1570
+ private _paintRaf;
1571
+ constructor(_view: EditorView, findModel: FindModel);
1572
+ private _schedulePaint;
1573
+ private _paint;
1574
+ private _observeResizeAncestors;
1575
+ private _paintRanges;
1576
+ }
1577
+
1578
+ export declare interface FindMatchesResult {
1579
+ readonly matches: readonly OffsetRange[];
1580
+ readonly isCapped: boolean;
1581
+ }
1582
+
1583
+ export declare class FindModel extends Disposable {
1584
+ private readonly _editorModel;
1585
+ readonly isRevealed: ISettableObservable<boolean, void>;
1586
+ readonly searchString: ISettableObservable<string, void>;
1587
+ readonly isRegex: ISettableObservable<boolean, void>;
1588
+ readonly matchCase: ISettableObservable<boolean, void>;
1589
+ readonly wholeWord: ISettableObservable<boolean, void>;
1590
+ readonly searchScope: ISettableObservable<OffsetRange | undefined, void>;
1591
+ readonly currentMatch: ISettableObservable<OffsetRange | undefined, void>;
1592
+ readonly loop: ISettableObservable<boolean, void>;
1593
+ readonly searchResult: IObservableWithChange< {
1594
+ kind: "invalid";
1595
+ error: Error;
1596
+ pattern?: undefined;
1597
+ matches?: undefined;
1598
+ isCapped?: undefined;
1599
+ } | {
1600
+ kind: "valid";
1601
+ pattern: FindPattern;
1602
+ matches: readonly OffsetRange[];
1603
+ isCapped: boolean;
1604
+ error?: undefined;
1605
+ }, void>;
1606
+ readonly matchesCount: IObservableWithChange<number, void>;
1607
+ readonly isCapped: IObservableWithChange<boolean, void>;
1608
+ readonly currentMatchPosition: IObservableWithChange<number, void>;
1609
+ private _searchOrigin;
1610
+ private readonly _sourceEditTracker;
1611
+ private _pendingInitialDirection;
1612
+ constructor(_editorModel: EditorModel);
1613
+ reveal(options: {
1614
+ readonly origin: number;
1615
+ readonly searchString?: string;
1616
+ readonly direction?: FindDirection;
1617
+ }): void;
1618
+ hide(): void;
1619
+ setSearchOrigin(offset: number): void;
1620
+ setSearchScope(scope: OffsetRange | undefined): void;
1621
+ moveToNextMatch(): OffsetRange | undefined;
1622
+ moveToPreviousMatch(): OffsetRange | undefined;
1623
+ private _move;
1624
+ private _selectFromOrigin;
1625
+ private _mapStateThroughEdit;
1626
+ private _inputSnapshot;
1627
+ private _readInputSnapshot;
1628
+ }
1629
+
757
1630
  /**
758
1631
  * Source offset (relative to `root`) of the node with `target`'s id, or
759
1632
  * `undefined` when it is not in the tree. Ids are stable across edits, so this
@@ -761,14 +1634,117 @@ declare class EmphasisViewData {
761
1634
  */
762
1635
  export declare function findNodeOffsetById(root: AstNode, target: AstNode): number | undefined;
763
1636
 
764
- export declare function findWordAt(text: string, offset: number): {
1637
+ export declare class FindPattern {
1638
+ private readonly _source;
1639
+ private readonly _flags;
1640
+ private readonly _wholeWord;
1641
+ private readonly _wordSeparators;
1642
+ readonly isEmpty: boolean;
1643
+ private constructor();
1644
+ static create(query: FindQuery): FindQueryResult;
1645
+ findMatches(text: string, scope?: OffsetRange, limit?: number): FindMatchesResult;
1646
+ findNextMatch(text: string, after: number, scope?: OffsetRange, loop?: boolean, skip?: OffsetRange): OffsetRange | undefined;
1647
+ findPreviousMatch(text: string, before: number, scope?: OffsetRange, loop?: boolean, skip?: OffsetRange): OffsetRange | undefined;
1648
+ private _forEachMatch;
1649
+ }
1650
+
1651
+ export declare interface FindQuery {
1652
+ readonly searchString: string;
1653
+ readonly isRegex: boolean;
1654
+ readonly matchCase: boolean;
1655
+ readonly wholeWord: boolean;
1656
+ readonly wordSeparators: string;
1657
+ }
1658
+
1659
+ export declare type FindQueryResult = {
1660
+ readonly kind: 'valid';
1661
+ readonly pattern: FindPattern;
1662
+ } | {
1663
+ readonly kind: 'invalid';
1664
+ readonly error: Error;
1665
+ };
1666
+
1667
+ export declare type FindSearchResult = {
1668
+ readonly kind: 'valid';
1669
+ readonly pattern: FindPattern;
1670
+ readonly matches: readonly OffsetRange[];
1671
+ readonly isCapped: boolean;
1672
+ } | {
1673
+ readonly kind: 'invalid';
1674
+ readonly error: Error;
1675
+ };
1676
+
1677
+ export declare class FindWidget extends Disposable {
1678
+ private readonly _view;
1679
+ private readonly _options;
1680
+ readonly element: HTMLElement;
1681
+ readonly panelElement: HTMLElement;
1682
+ readonly focused: ISettableObservable<boolean, void>;
1683
+ private readonly _inputShell;
1684
+ private readonly _input;
1685
+ private readonly _matchesCount;
1686
+ private readonly _previousButton;
1687
+ private readonly _nextButton;
1688
+ private readonly _selectionButton;
1689
+ private readonly _caseButton;
1690
+ private readonly _wholeWordButton;
1691
+ private readonly _regexButton;
1692
+ private readonly _error;
1693
+ constructor(_view: EditorView, _options: FindWidgetOptions);
1694
+ focusAndSelect(): void;
1695
+ private _registerButton;
1696
+ private _render;
1697
+ }
1698
+
1699
+ export declare interface FindWidgetOptions {
1700
+ readonly findModel: FindModel;
1701
+ readonly canFindInSelection: IObservable<boolean>;
1702
+ readonly onNext: () => void;
1703
+ readonly onPrevious: () => void;
1704
+ readonly onToggleFindInSelection: () => void;
1705
+ readonly onClose: () => void;
1706
+ }
1707
+
1708
+ export declare function findWordAt(text: string, offset: number, config?: WordNavigationConfig): {
765
1709
  start: number;
766
1710
  end: number;
767
1711
  };
768
1712
 
769
- export declare function findWordBoundaryLeft(text: string, offset: number): number;
1713
+ export declare function findWordBoundaryLeft(text: string, offset: number, config?: WordNavigationConfig): number;
1714
+
1715
+ export declare function findWordBoundaryRight(text: string, offset: number, config?: WordNavigationConfig): number;
1716
+
1717
+ export declare function findWordDeleteBoundaryLeft(text: string, offset: number, config?: WordNavigationConfig): number;
770
1718
 
771
- export declare function findWordBoundaryRight(text: string, offset: number): number;
1719
+ export declare function findWordDeleteBoundaryRight(text: string, offset: number, config?: WordNavigationConfig): number;
1720
+
1721
+ /**
1722
+ * A leading YAML front matter block. The YAML value is intentionally opaque:
1723
+ * only the two fences and the exact source between them are modeled.
1724
+ */
1725
+ export declare class FrontMatterAstNode extends BlockAstNodeBase {
1726
+ readonly content: readonly (MarkerAstNode | GlueAstNode)[];
1727
+ readonly leadingTrivia?: GlueAstNode | undefined;
1728
+ readonly kind = "frontMatter";
1729
+ constructor(content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
1730
+ get children(): readonly AstNode[];
1731
+ get openFence(): MarkerAstNode | undefined;
1732
+ get closeFence(): MarkerAstNode | undefined;
1733
+ get value(): MarkerAstNode | undefined;
1734
+ mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
1735
+ withLeadingTrivia(trivia: GlueAstNode | undefined): FrontMatterAstNode;
1736
+ }
1737
+
1738
+ declare class FrontMatterViewData {
1739
+ readonly ast: FrontMatterAstNode;
1740
+ /** Active: render both fences; inactive: render only the opaque YAML value. */
1741
+ readonly showMarkup: boolean;
1742
+ readonly content: readonly AnyViewData[];
1743
+ readonly kind = "frontMatter";
1744
+ constructor(ast: FrontMatterAstNode,
1745
+ /** Active: render both fences; inactive: render only the opaque YAML value. */
1746
+ showMarkup: boolean, content: readonly AnyViewData[]);
1747
+ }
772
1748
 
773
1749
  export declare function getAnnotatedSource(node: AstNode, source: string, offset?: number): string;
774
1750
 
@@ -845,6 +1821,19 @@ declare class HeadingViewData {
845
1821
  constructor(ast: HeadingAstNode, content: readonly AnyViewData[]);
846
1822
  }
847
1823
 
1824
+ export declare function hiddenCursorRanges(doc: DocumentAstNode, markerVisibleBlocks: ReadonlySet<BlockAstNode>, cursor: number): readonly OffsetRange[];
1825
+
1826
+ export declare type HistoryKeyboardAction = 'undo' | 'redo';
1827
+
1828
+ /** A block HTML comment, discriminated by whether its closing delimiter is present. */
1829
+ declare type HtmlCommentSource = OpenHtmlCommentSource | CompleteHtmlCommentSource;
1830
+
1831
+ declare interface HtmlCommentSourceBase {
1832
+ readonly leadingWhitespace: string;
1833
+ readonly opening: '<!--';
1834
+ readonly body: string;
1835
+ }
1836
+
848
1837
  /**
849
1838
  * The editor operations a clipboard strategy drives. The strategy never
850
1839
  * touches the model or the DOM directly — it asks through this seam, so the
@@ -881,6 +1870,9 @@ export declare interface IClipboardStrategy {
881
1870
  connect(context: IClipboardContext): IDisposable;
882
1871
  }
883
1872
 
1873
+ /** A live rendering of a {@link CommentsModel}. Dispose to unmount it. */
1874
+ export declare type ICommentsPresenter = IDisposable;
1875
+
884
1876
  /** The Monarch language definitions the default highlighter wires up. */
885
1877
  export declare interface IDefaultMonarchGrammars {
886
1878
  typescript: unknown;
@@ -890,6 +1882,74 @@ export declare interface IDefaultMonarchGrammars {
890
1882
  python: unknown;
891
1883
  rust: unknown;
892
1884
  shell: unknown;
1885
+ yaml: unknown;
1886
+ }
1887
+
1888
+ /**
1889
+ * A live editor embedded in place of a fenced code block's *rendered* form.
1890
+ *
1891
+ * This is the internal seam between the block view and a concrete embedded
1892
+ * editor (e.g. an `<iframe>` speaking the web-editor protocol). The block view
1893
+ * only speaks string edits: it pushes the block's content down via
1894
+ * {@link setContent} and receives the editor's own changes back through
1895
+ * {@link onEdit} (set by the block view on each (re)construction, so it always
1896
+ * routes to the current AST node). The concrete implementation owns its DOM,
1897
+ * transport, and lifecycle.
1898
+ *
1899
+ * A single instance is adopted across re-renders (like the highlighter session)
1900
+ * so the underlying editor keeps its state across edits — see
1901
+ * {@link CodeBlockViewNode}.
1902
+ */
1903
+ declare interface IEmbeddedCodeEditor {
1904
+ /** The element mounted as the block's rendered form. */
1905
+ readonly element: HTMLElement;
1906
+ /**
1907
+ * Document → editor. The block's content changed (from any source). Must be
1908
+ * idempotent: pushing the content the editor already holds is a no-op, which
1909
+ * is how edits the editor itself originated are prevented from echoing back.
1910
+ */
1911
+ setContent(content: string): void;
1912
+ /** Update whether the embedded editor may change its content. */
1913
+ setReadOnly?(readOnly: boolean): void;
1914
+ /**
1915
+ * Optional synchronous height (px) to reserve for `content` *before* the
1916
+ * editor has laid out. Return `undefined` to let the editor size itself
1917
+ * (the implementation may report its real height later). Lets a registration
1918
+ * avoid a layout jump when it can cheaply estimate the size from content.
1919
+ */
1920
+ estimateHeight?(content: string): number | undefined;
1921
+ /**
1922
+ * Editor → document. Set by the block view on every (re)construction to
1923
+ * route the editor's own edits, expressed in the block's *content*
1924
+ * coordinates, to the current AST node.
1925
+ */
1926
+ onEdit?: (edit: StringEdit) => void;
1927
+ dispose(): void;
1928
+ }
1929
+
1930
+ /** Creates an {@link IEmbeddedCodeEditor} for a fenced block, or opts out. */
1931
+ declare interface IEmbeddedCodeEditorFactory {
1932
+ /**
1933
+ * Return an editor for a fenced block, or `undefined` to fall
1934
+ * back to the default (highlighting / {@link BlockViewOptions.renderCustomCodeBlock}).
1935
+ */
1936
+ create(language: string, infoString: string, initialContent: string): IEmbeddedCodeEditor | undefined;
1937
+ }
1938
+
1939
+ /**
1940
+ * Routes undo and redo to whatever owns the document's history: the editor
1941
+ * itself on a standalone page, or the enclosing document in a host like
1942
+ * VS Code.
1943
+ */
1944
+ export declare interface IHistoryStrategy {
1945
+ undo(): void;
1946
+ redo(): void;
1947
+ /**
1948
+ * Invoked around each source mutation so the strategy can record it.
1949
+ * Implemented only by strategies that build their own history; a host that
1950
+ * forwards edits to a VS Code `TextDocument` lets it record them instead.
1951
+ */
1952
+ record?(operation: () => void, edit?: StringEdit): void;
893
1953
  }
894
1954
 
895
1955
  export declare class ImageAstNode extends AstNode {
@@ -926,6 +1986,14 @@ export declare interface IMonarchApi {
926
1986
  MonarchTokenizer: new (languageService: unknown, standaloneThemeService: unknown, languageId: string, lexer: unknown, configurationService: unknown) => MonarchTokenizer;
927
1987
  }
928
1988
 
1989
+ /** Controls tab-stop insertion and non-list line indentation. */
1990
+ export declare interface IndentationConfig {
1991
+ /** Number of visual columns between tab stops. */
1992
+ readonly tabSize: number;
1993
+ /** Whether indentation uses spaces instead of tab characters. */
1994
+ readonly insertSpaces: boolean;
1995
+ }
1996
+
929
1997
  export declare type InlineAstNode = TextAstNode | StrongAstNode | EmphasisAstNode | StrikethroughAstNode | InlineCodeAstNode | InlineMathAstNode | LinkAstNode | ImageAstNode;
930
1998
 
931
1999
  export declare class InlineCodeAstNode extends AstNode {
@@ -980,16 +2048,25 @@ export declare const insertParagraph: EditCommand;
980
2048
  * - paragraph / heading / thematic break — the "rich text" thing: at the
981
2049
  * block's end arm a transient empty paragraph (see {@link SmartEnterResult});
982
2050
  * 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.
2051
+ * - fenced code / front matter — insert a newline that preserves the current
2052
+ * line's indentation, staying inside the fences.
985
2053
  * - block quote — continue the quote (`\n> `); an empty quote line exits it.
986
2054
  * - list — continue the list with the next marker (incrementing ordered
987
2055
  * numbers, re-emitting task checkboxes); an empty item exits the list.
2056
+ * - complete HTML comment — at the comment's end, leave it by arming a
2057
+ * transient paragraph; inside it (or while the comment is open), insert a
2058
+ * normal source line break.
988
2059
  * A non-collapsed selection, or any other block, falls back to a plain soft line
989
2060
  * break, preserving today's behaviour.
990
2061
  */
991
2062
  export declare const insertSmartEnter: (ctx: CursorCommandContext) => SmartEnterResult;
992
2063
 
2064
+ /**
2065
+ * VS Code-style Tab: insert to the next tab stop for a caret or partial
2066
+ * single-line selection, and indent every selected line for a line selection.
2067
+ */
2068
+ export declare function insertTab(config?: IndentationConfig): EditCommand;
2069
+
993
2070
  export declare function insertText(text: string): EditCommand;
994
2071
 
995
2072
  /**
@@ -1031,6 +2108,29 @@ export declare interface ISyntaxHighlighterDocument extends IDisposable {
1031
2108
  readonly snapshot: IObservableWithChange<ISyntaxHighlightedSnapshot, LengthEdit>;
1032
2109
  }
1033
2110
 
2111
+ export declare interface KeyboardBinding {
2112
+ readonly key: string;
2113
+ readonly modifiers?: KeyboardModifiers;
2114
+ readonly platforms?: readonly KeyboardPlatform[];
2115
+ readonly action: EditorKeyboardAction;
2116
+ }
2117
+
2118
+ export declare interface KeyboardModifiers {
2119
+ readonly shift?: boolean;
2120
+ readonly alt?: boolean;
2121
+ readonly ctrl?: boolean;
2122
+ readonly meta?: boolean;
2123
+ }
2124
+
2125
+ export declare type KeyboardPlatform = 'macos' | 'windows' | 'linux';
2126
+
2127
+ export declare interface KeyboardProfile {
2128
+ /**
2129
+ * Bindings in priority order. The first exact key/modifier/platform match wins.
2130
+ */
2131
+ readonly bindings: readonly KeyboardBinding[];
2132
+ }
2133
+
1034
2134
  declare abstract class LeafAstNode extends AstNode {
1035
2135
  abstract readonly content: string;
1036
2136
  get children(): readonly AstNode[];
@@ -1143,6 +2243,32 @@ declare class ListViewData {
1143
2243
  constructor(ast: ListAstNode, content: readonly AnyViewData[]);
1144
2244
  }
1145
2245
 
2246
+ /**
2247
+ * Compact in-memory history for editors that hold the only copy of the
2248
+ * document, such as a standalone browser page. Where the surrounding host
2249
+ * already records history — a VS Code `TextDocument` — forward to that
2250
+ * instead.
2251
+ */
2252
+ export declare class LocalHistoryStrategy implements IHistoryStrategy {
2253
+ private readonly _model;
2254
+ private readonly _past;
2255
+ private readonly _future;
2256
+ /**
2257
+ * The source text as of the last change this strategy recorded or applied.
2258
+ * Any other value means the document was replaced behind its back, so the
2259
+ * stored edits no longer line up and must be discarded rather than applied.
2260
+ */
2261
+ private _lastKnownText;
2262
+ constructor(_model: EditorModel);
2263
+ record(operation: () => void, edit?: StringEdit): void;
2264
+ undo(): void;
2265
+ redo(): void;
2266
+ /** The entry on top of `stack`, or `undefined` when it cannot be applied. */
2267
+ private _peekApplicable;
2268
+ private _apply;
2269
+ private _clear;
2270
+ }
2271
+
1146
2272
  /**
1147
2273
  * Parses markdown into a {@link DocumentAstNode}.
1148
2274
  *
@@ -1249,8 +2375,8 @@ export declare class MeasuredLayoutDebugRendering {
1249
2375
  * Exposes two DOM nodes the caller can place independently:
1250
2376
  *
1251
2377
  * - {@link overlayElement} — absolutely positioned; the caller mounts it
1252
- * inside the editor element so dashed line-bands and run-boxes line up
1253
- * with the editor's client coordinates.
2378
+ * inside the editor overlay container so dashed line-bands and run-boxes
2379
+ * share the measured editor-local coordinates.
1254
2380
  * - {@link infoElement} — block-flow; the caller mounts it as a sibling
1255
2381
  * *below* the editor. Contains the per-block summary table that used
1256
2382
  * to live on the overlay.
@@ -1261,7 +2387,6 @@ export declare class MeasuredLayoutDebugRendering {
1261
2387
  * the derived subscribed.
1262
2388
  */
1263
2389
  export declare class MeasuredLayoutDebugView extends Disposable {
1264
- private readonly _overlayParent;
1265
2390
  readonly overlayElement: HTMLElement;
1266
2391
  readonly infoElement: HTMLElement;
1267
2392
  readonly rendering: IObservable<MeasuredLayoutDebugRendering>;
@@ -1274,6 +2399,7 @@ export declare class MeasuredLayoutDebugView extends Disposable {
1274
2399
 
1275
2400
  export declare interface MeasuredLayoutDebugViewOptions {
1276
2401
  readonly model: MeasuredLayoutModel;
2402
+ readonly coordinateSpace: EditorCoordinateSpace;
1277
2403
  /**
1278
2404
  * DEBUG ONLY. Maps an absolute source offset to a fill color for that
1279
2405
  * character's glyph rect. The fixture passes the same function to the
@@ -1306,14 +2432,16 @@ export declare interface MeasuredLayoutDebugViewOptions {
1306
2432
  * through this model and never touches view fields directly.
1307
2433
  */
1308
2434
  export declare class MeasuredLayoutModel {
1309
- readonly measurements: ISettableObservable<readonly BlockMeasurement[], void>;
2435
+ private readonly _measurements;
2436
+ readonly measurements: IObservable<readonly BlockMeasurement[]>;
2437
+ private readonly _virtualLines;
1310
2438
  /**
1311
- * Concatenated visual line map across all mounted blocks. Lines are
1312
- * left in DOM (client-coordinate) y order each per-block map already
1313
- * uses absolute client coordinates from `getClientRects()`, so the
1314
- * concatenation is well-formed without re-sorting.
2439
+ * Concatenated visual line map across all mounted blocks. Every per-block
2440
+ * map uses the same editor-local coordinate space, so concatenation is
2441
+ * well-formed without translation or re-sorting.
1315
2442
  */
1316
2443
  readonly visualLineMap: IObservableWithChange<VisualLineMap, void>;
2444
+ setMeasurements(measurements: readonly BlockMeasurement[], virtualLines: readonly VirtualLineMeasurement[]): void;
1317
2445
  }
1318
2446
 
1319
2447
  /**
@@ -1353,14 +2481,25 @@ export declare class NativeClipboardStrategy implements IClipboardStrategy {
1353
2481
  connect(context: IClipboardContext): IDisposable;
1354
2482
  }
1355
2483
 
2484
+ declare interface NestedItem {
2485
+ readonly kind: 'nested';
2486
+ readonly original: AstNode;
2487
+ readonly originalStart: number;
2488
+ readonly modified: AstNode;
2489
+ readonly modifiedStart: number;
2490
+ readonly children: readonly DiffItem[];
2491
+ }
2492
+
1356
2493
  /**
1357
2494
  * Move the cursor one position left or right, skipping over hidden marker
1358
2495
  * ranges in inactive blocks (and inactive items of an active list).
1359
2496
  */
1360
- export declare function nextCursorPosition(doc: DocumentAstNode, activeBlock: BlockAstNode | undefined, cursor: number, direction: 'left' | 'right'): number;
2497
+ export declare function nextCursorPosition(doc: DocumentAstNode, markerVisibleBlocks: ReadonlySet<BlockAstNode>, cursor: number, direction: 'left' | 'right'): number;
1361
2498
 
1362
2499
  declare const NO_ACTIVE_BLOCKS: unique symbol;
1363
2500
 
2501
+ export declare function normalizeCursorPosition(doc: DocumentAstNode, markerVisibleBlocks: ReadonlySet<BlockAstNode>, cursor: number, target: number, direction: 'left' | 'right', includeHiddenRangeBoundary?: boolean): number;
2502
+
1364
2503
  export declare class OffsetRange {
1365
2504
  readonly start: number;
1366
2505
  readonly endExclusive: number;
@@ -1388,6 +2527,14 @@ export declare class OffsetRange {
1388
2527
  toString(): string;
1389
2528
  }
1390
2529
 
2530
+ /** The lossless source slices of a block HTML comment whose closer has not been typed. */
2531
+ declare interface OpenHtmlCommentSource extends HtmlCommentSourceBase {
2532
+ readonly kind: 'open';
2533
+ }
2534
+
2535
+ /** Outdent the current line, or every line touched by the selection. */
2536
+ export declare function outdent(config?: IndentationConfig): EditCommand;
2537
+
1391
2538
  export declare class ParagraphAstNode extends BlockAstNodeBase {
1392
2539
  readonly content: readonly (InlineAstNode | GlueAstNode)[];
1393
2540
  readonly leadingTrivia?: GlueAstNode | undefined;
@@ -1406,23 +2553,32 @@ declare class ParagraphViewData {
1406
2553
  }
1407
2554
 
1408
2555
  /**
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).
2556
+ * A *transient* editing state: an empty paragraph adjacent to a real block.
2557
+ * Markdown has no empty-paragraph node, so this never lives in
2558
+ * {@link EditorModel['sourceText']} or the parsed {@link EditorModel.document}
2559
+ * — it is pure edit intent that the view renders as a synthetic blank line and
2560
+ * that the controller either *materializes* (the user types) or *cancels* (the
2561
+ * user navigates away / backspaces).
1415
2562
  */
1416
2563
  declare interface PendingParagraph {
1417
- /** The paragraph the blank line is rendered directly after. */
2564
+ /** The block the blank line is rendered directly after. */
1418
2565
  readonly anchorBlock: BlockAstNode;
1419
2566
  /**
1420
2567
  * Source region rewritten when the pending paragraph is materialized — the
1421
2568
  * gap between {@link anchorBlock}'s text and whatever follows it.
1422
2569
  */
1423
2570
  readonly replaceRange: OffsetRange;
2571
+ /** Whether materialized text needs a blank-line separator before it. */
2572
+ readonly separateFromPreviousBlock: boolean;
1424
2573
  /** Whether {@link replaceRange} ends at the end of the document. */
1425
2574
  readonly atEof: boolean;
2575
+ /**
2576
+ * Horizontal whitespace typed on the source-less line. It remains transient
2577
+ * until other input materializes the paragraph. Contains only spaces and tabs.
2578
+ */
2579
+ readonly text: string;
2580
+ /** The source-less visual line occupied by the pending caret. */
2581
+ readonly cursorLine: VirtualCursorLine;
1426
2582
  /**
1427
2583
  * A throwaway AST node that exists only to give the synthetic view child a
1428
2584
  * stable identity across render frames (the view pairs nodes by `ast.id`).
@@ -1431,21 +2587,51 @@ declare interface PendingParagraph {
1431
2587
  readonly syntheticAst: ParagraphAstNode;
1432
2588
  }
1433
2589
 
2590
+ declare interface PendingParagraphResult {
2591
+ readonly kind: 'pending';
2592
+ readonly anchorBlock: BlockAstNode;
2593
+ readonly replaceRange: OffsetRange;
2594
+ /** Whether materialized text needs a blank-line separator before it. */
2595
+ readonly separateFromPreviousBlock: boolean;
2596
+ readonly atEof: boolean;
2597
+ }
2598
+
1434
2599
  /**
1435
2600
  * 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.
2601
+ * model). It carries the throwaway {@link ParagraphAstNode} that gives the
2602
+ * rendered line a stable identity across frames, its anchor block, source-less
2603
+ * cursor line, and transient horizontal whitespace. It has no source content or
2604
+ * selection range.
1440
2605
  */
1441
2606
  declare class PendingParagraphViewData {
1442
2607
  readonly ast: ParagraphAstNode;
2608
+ readonly anchorBlock: BlockAstNode;
2609
+ readonly cursorLine: VirtualCursorLine;
2610
+ readonly text: string;
1443
2611
  readonly kind = "pendingParagraph";
1444
- constructor(ast: ParagraphAstNode);
2612
+ constructor(ast: ParagraphAstNode, anchorBlock: BlockAstNode, cursorLine: VirtualCursorLine, text: string);
2613
+ }
2614
+
2615
+ /**
2616
+ * The mounted transient empty paragraph: a `<p class="md-pending-paragraph">`
2617
+ * holding either a `<br>` or decorated transient horizontal whitespace. It is a
2618
+ * leaf view node with no inline source content; the document view publishes its
2619
+ * element geometry as a virtual visual line.
2620
+ */
2621
+ declare class PendingParagraphViewNode extends ViewNode {
2622
+ readonly element: HTMLElement;
2623
+ readonly anchorBlock: BlockAstNode;
2624
+ readonly cursorLine: VirtualCursorLine;
2625
+ private _text;
2626
+ constructor(view: PendingParagraphViewData);
2627
+ update(text: string): void;
2628
+ getCaretClientRect(): DOMRect;
1445
2629
  }
1446
2630
 
1447
2631
  /**
1448
- * Immutable point in 2D space, in CSS-pixel client coordinates.
2632
+ * Immutable point in a caller-defined 2D CSS-pixel coordinate space.
2633
+ * Coordinate-owning APIs must document whether values are viewport-client or
2634
+ * editor-local; values from different spaces must not be mixed.
1449
2635
  */
1450
2636
  export declare class Point2D {
1451
2637
  readonly x: number;
@@ -1456,8 +2642,8 @@ export declare class Point2D {
1456
2642
  }
1457
2643
 
1458
2644
  /**
1459
- * Immutable axis-aligned rectangle in 2D space, in CSS-pixel client
1460
- * coordinates. `x`/`y` is the top-left corner, growing right/down.
2645
+ * Immutable axis-aligned rectangle in a caller-defined 2D CSS-pixel coordinate
2646
+ * space. `x`/`y` is the top-left corner, growing right/down.
1461
2647
  *
1462
2648
  * Half-open in both dimensions: `right` and `bottom` are excluded.
1463
2649
  */
@@ -1483,6 +2669,23 @@ export declare class Rect2D {
1483
2669
  translate(dx: number, dy: number): Rect2D;
1484
2670
  }
1485
2671
 
2672
+ declare interface RemovedItem {
2673
+ readonly kind: 'removed';
2674
+ readonly node: AstNode;
2675
+ readonly originalStart: number;
2676
+ readonly deletedLocal: readonly AnnotatedRange[];
2677
+ }
2678
+
2679
+ declare interface ReplacedItem {
2680
+ readonly kind: 'replaced';
2681
+ readonly original: AstNode;
2682
+ readonly originalStart: number;
2683
+ readonly modified: AstNode;
2684
+ readonly modifiedStart: number;
2685
+ readonly insertedLocal: readonly AnnotatedRange[];
2686
+ readonly deletedLocal: readonly AnnotatedRange[];
2687
+ }
2688
+
1486
2689
  export declare const selectAll: SelectionCommand;
1487
2690
 
1488
2691
  export declare function selectBlock(ctx: CursorCommandContext, blockRange: OffsetRange): Selection_2;
@@ -1508,8 +2711,13 @@ export { Selection_2 as Selection }
1508
2711
  export declare interface SelectionBlock {
1509
2712
  readonly block: BlockAstNode;
1510
2713
  readonly absoluteStart: number;
1511
- readonly viewNode: ViewNode;
1512
- readonly element: HTMLElement;
2714
+ /** Block border box in editor-local coordinates. */
2715
+ readonly rect: Rect2D;
2716
+ /** Visible horizontal padding-box bounds for a scrolling block. */
2717
+ readonly viewportClip: {
2718
+ readonly left: number;
2719
+ readonly right: number;
2720
+ } | undefined;
1513
2721
  }
1514
2722
 
1515
2723
  export declare type SelectionCommand = (ctx: CursorCommandContext, offset: SourceOffset) => Selection_2;
@@ -1521,6 +2729,9 @@ export declare interface SelectionRect {
1521
2729
  readonly height: number;
1522
2730
  }
1523
2731
 
2732
+ /** The interaction that produced the current editor selection. */
2733
+ export declare type SelectionSource = 'user' | 'find';
2734
+
1524
2735
  /**
1525
2736
  * Owns the SVG overlay that paints the selection.
1526
2737
  *
@@ -1541,11 +2752,10 @@ export declare interface SelectionRect {
1541
2752
  * envelope shape used by IDE selection rendering.
1542
2753
  */
1543
2754
  export declare class SelectionView extends Disposable {
1544
- private readonly _parent;
1545
2755
  readonly element: SVGSVGElement;
1546
2756
  readonly rendering: IObservable<SelectionViewRendering>;
1547
2757
  private readonly _path;
1548
- constructor(_parent: HTMLElement, options: SelectionViewOptions);
2758
+ constructor(options: SelectionViewOptions);
1549
2759
  }
1550
2760
 
1551
2761
  export declare interface SelectionViewOptions {
@@ -1573,12 +2783,7 @@ export declare type SmartEnterResult = {
1573
2783
  readonly kind: 'edit';
1574
2784
  readonly edit: StringEdit;
1575
2785
  readonly selection: Selection_2;
1576
- } | {
1577
- readonly kind: 'pending';
1578
- readonly anchorBlock: BlockAstNode;
1579
- readonly replaceRange: OffsetRange;
1580
- readonly atEof: boolean;
1581
- };
2786
+ } | PendingParagraphResult;
1582
2787
 
1583
2788
  /**
1584
2789
  * A run of {@link Token}s together with the exact {@link OffsetRange} they
@@ -1593,8 +2798,39 @@ export declare interface SnapshotTokens {
1593
2798
  readonly tokens: readonly Token[];
1594
2799
  }
1595
2800
 
2801
+ /** Metadata delivered synchronously immediately before a model-owned source edit is applied. */
2802
+ export declare interface SourceEditEvent {
2803
+ readonly baseSourceTextId: number;
2804
+ readonly resultSourceTextId: number;
2805
+ readonly edit: StringEdit;
2806
+ readonly transaction: ITransaction;
2807
+ }
2808
+
1596
2809
  export declare type SourceOffset = number;
1597
2810
 
2811
+ export declare abstract class StackedCommentsPresenter extends Disposable implements ICommentsPresenter {
2812
+ protected readonly model: CommentsModel;
2813
+ protected readonly view: EditorView;
2814
+ protected readonly context?: CommentsPresenterContext | undefined;
2815
+ private readonly _layer;
2816
+ private readonly _entries;
2817
+ private _order;
2818
+ private _pendingRevealCommentId;
2819
+ constructor(model: CommentsModel, view: EditorView, context?: CommentsPresenterContext | undefined);
2820
+ /** Build the card DOM for a comment. Called once per new comment. */
2821
+ protected abstract createWidget(comment: Comment_2): StackWidget;
2822
+ revealComment(id: string): void;
2823
+ private _reconcile;
2824
+ private _relayout;
2825
+ private _revealPendingComment;
2826
+ }
2827
+
2828
+ /** The minimal widget contract a subclass must produce. */
2829
+ export declare interface StackWidget {
2830
+ readonly element: HTMLElement;
2831
+ dispose(): void;
2832
+ }
2833
+
1598
2834
  export declare class StrikethroughAstNode extends AstNode {
1599
2835
  readonly openMarker: MarkerAstNode;
1600
2836
  readonly content: readonly (InlineAstNode | GlueAstNode)[];
@@ -1637,6 +2873,11 @@ export declare class StringReplacement {
1637
2873
  constructor(replaceRange: OffsetRange, newText: string);
1638
2874
  get isEmpty(): boolean;
1639
2875
  equals(other: StringReplacement): boolean;
2876
+ /**
2877
+ * Narrows this replacement to the span that actually changes, by trimming
2878
+ * the prefix and suffix it shares with the text it replaces in `source`.
2879
+ */
2880
+ removeCommonSuffixPrefix(source: string): StringReplacement;
1640
2881
  toString(): string;
1641
2882
  }
1642
2883
 
@@ -1665,6 +2906,8 @@ declare class StrongViewData {
1665
2906
  constructor(ast: StrongAstNode, content: readonly AnyViewData[]);
1666
2907
  }
1667
2908
 
2909
+ export declare type TabKeyboardAction = 'insert' | 'outdent';
2910
+
1668
2911
  export declare class TableAstNode extends BlockAstNodeBase {
1669
2912
  readonly content: readonly (TableRowAstNode | GlueAstNode)[];
1670
2913
  readonly leadingTrivia?: GlueAstNode | undefined;
@@ -1799,6 +3042,55 @@ export declare class Token {
1799
3042
  className: string | undefined);
1800
3043
  }
1801
3044
 
3045
+ declare interface UnchangedItem {
3046
+ readonly kind: 'unchanged';
3047
+ /** The modified-side node (identical in content to the original). */
3048
+ readonly node: AstNode;
3049
+ readonly modifiedStart: number;
3050
+ }
3051
+
3052
+ /**
3053
+ * A block whose token type the parser does not understand (a setext heading or
3054
+ * any future/extension construct). Rather than dropping the
3055
+ * span — which would demote its text to invisible glue — the parser captures the
3056
+ * whole source range verbatim as a single {@link MarkerAstNode} of kind
3057
+ * `content` and records the originating micromark {@link tokenType}, so the view
3058
+ * can render it as raw, editable text with an "unhandled" affordance. Offsets
3059
+ * stay sound: `content` tiles the block's full source span exactly.
3060
+ */
3061
+ declare class UnhandledBlockAstNode extends BlockAstNodeBase {
3062
+ readonly tokenType: string;
3063
+ readonly content: readonly (MarkerAstNode | GlueAstNode)[];
3064
+ readonly leadingTrivia?: GlueAstNode | undefined;
3065
+ readonly kind = "unhandledBlock";
3066
+ constructor(tokenType: string, content: readonly (MarkerAstNode | GlueAstNode)[], leadingTrivia?: GlueAstNode | undefined);
3067
+ get children(): readonly AstNode[];
3068
+ get code(): MarkerAstNode | undefined;
3069
+ /**
3070
+ * Lossless slices when this raw HTML block starts one comment after optional
3071
+ * whitespace. An open comment consumes the remaining source as its body. A
3072
+ * complete comment permits only trailing whitespace after its closer.
3073
+ */
3074
+ get htmlComment(): HtmlCommentSource | undefined;
3075
+ mapChildren(m: ReadonlyMap<AstNode, AstNode>): AstNode;
3076
+ withLeadingTrivia(trivia: GlueAstNode | undefined): UnhandledBlockAstNode;
3077
+ protected _localEquals(o: this): boolean;
3078
+ }
3079
+
3080
+ /**
3081
+ * View-data for an {@link UnhandledBlockAstNode}. The source remains verbatim
3082
+ * in both states. Complete HTML comments use {@link showMarkup} to switch
3083
+ * between their quiet reading treatment and editable source presentation;
3084
+ * other unhandled blocks ignore the flag and keep their warning treatment.
3085
+ */
3086
+ declare class UnhandledBlockViewData {
3087
+ readonly ast: UnhandledBlockAstNode;
3088
+ readonly showMarkup: boolean;
3089
+ readonly content: readonly AnyViewData[];
3090
+ readonly kind = "unhandledBlock";
3091
+ constructor(ast: UnhandledBlockAstNode, showMarkup: boolean, content: readonly AnyViewData[]);
3092
+ }
3093
+
1802
3094
  /**
1803
3095
  * Immutable view of an AST node. Pairs `ast` with its rendered `dom` and a
1804
3096
  * mirror of `ast.children` as ViewNode children. Source offsets are NEVER
@@ -1863,10 +3155,12 @@ export declare class ViewNode extends Disposable {
1863
3155
  /**
1864
3156
  * Map a DOM hit that lands on THIS node's own representation into a source
1865
3157
  * range in this node's local space `[0, ast.length)`. Polymorphic: a text
1866
- * leaf maps the caret offset 1:1; an element-only node (KaTeX math, `<hr>`,
1867
- * an image, a hidden marker) has no internal text mapping and snaps to its
1868
- * start by default subclasses may override (e.g. to snap to the nearer
1869
- * edge by x).
3158
+ * leaf maps the caret offset 1:1. For an element hit — an element-only node
3159
+ * (KaTeX math, `<hr>`, an image, a hidden marker) or a wrapper/container
3160
+ * element the platform reports a child-index offset, not a text caret, so
3161
+ * there is no internal mapping to honour: it snaps to the node's nearer
3162
+ * edge, `offset 0` (the "before" side) → start, any `offset >= 1` (the
3163
+ * "after" side) → end. Subclasses may override for finer control.
1870
3164
  */
1871
3165
  getLocalSourceRange(pos: DomPosition): OffsetRange;
1872
3166
  /**
@@ -1888,6 +3182,24 @@ export declare class ViewNode extends Disposable {
1888
3182
  forEachTextLeaf(nodeOffset: number, visitor: (leaf: ViewNode, leafOffset: number) => void): void;
1889
3183
  }
1890
3184
 
3185
+ /**
3186
+ * A visual cursor line that has no representation in the source text.
3187
+ *
3188
+ * The two source offsets are the positions immediately before and after the
3189
+ * virtual line. The object itself is the stable identity of the line.
3190
+ */
3191
+ export declare class VirtualCursorLine {
3192
+ readonly sourceOffsetBefore: SourceOffset;
3193
+ readonly sourceOffsetAfter: SourceOffset;
3194
+ constructor(sourceOffsetBefore: SourceOffset, sourceOffsetAfter: SourceOffset);
3195
+ }
3196
+
3197
+ /** A measured source-less line inserted directly after a source block. */
3198
+ declare interface VirtualLineMeasurement {
3199
+ readonly afterBlock: BlockAstNode;
3200
+ readonly line: VisualLine;
3201
+ }
3202
+
1891
3203
  export declare type VisualCursorCommand = (ctx: VisualCursorCommandContext) => CursorMoveResult;
1892
3204
 
1893
3205
  export declare interface VisualCursorCommandContext extends CursorCommandContext {
@@ -1905,12 +3217,15 @@ export declare function visualizeAst(root: AstNode, source: string): AstVisualiz
1905
3217
  export declare class VisualLine {
1906
3218
  readonly rect: Rect2D;
1907
3219
  readonly runs: readonly VisualRun[];
1908
- constructor(rect: Rect2D, runs: readonly VisualRun[]);
3220
+ readonly virtualCursorLine?: VirtualCursorLine | undefined;
3221
+ static virtual(cursorLine: VirtualCursorLine, rect: Rect2D): VisualLine;
3222
+ constructor(rect: Rect2D, runs: readonly VisualRun[], virtualCursorLine?: VirtualCursorLine | undefined);
1909
3223
  containsOffset(offset: SourceOffset): boolean;
1910
3224
  /**
1911
3225
  * How `offset` relates to this line's runs:
1912
3226
  * - `'covers'`: a run starts at or strictly contains the offset
1913
- * (`start <= offset < endExclusive`) the caret belongs on this line.
3227
+ * (`start <= offset < endExclusive`), or a zero-length visual-line
3228
+ * anchor sits at the offset — the caret belongs on this line.
1914
3229
  * - `'end'`: the offset is only some run's trailing boundary
1915
3230
  * (`offset === endExclusive`) with no run covering it — a line-break
1916
3231
  * boundary the caret should leave for the next line.
@@ -1923,23 +3238,42 @@ export declare class VisualLine {
1923
3238
  */
1924
3239
  sourceDistanceTo(offset: SourceOffset): number;
1925
3240
  /**
1926
- * x of the caret position before `offset` on this line. When `offset`
1927
- * is past all runs (trailing whitespace / blank line), returns the
1928
- * right edge of the last run; when before all runs, returns the left
1929
- * edge of the first run.
3241
+ * x of the caret position before `offset` on this line.
3242
+ *
3243
+ * The runs tile the source but are stored in paint order, not sorted by
3244
+ * source offset (hidden-marker runs are appended last). So this scans all
3245
+ * runs rather than assuming any ordering:
3246
+ *
3247
+ * - A zero-source visual anchor owns its exact offset, so a marker-only line
3248
+ * wins over the preceding line's inclusive end boundary.
3249
+ * - Otherwise a run starting at `offset` owns that seam. This keeps an
3250
+ * out-of-flow prefix from placing the caret at its trailing edge when the
3251
+ * following body starts at a visually separate x.
3252
+ * - Otherwise, if some run *covers* `offset`, its own geometry places the
3253
+ * caret (exact glyph boundary for text runs). In the active,
3254
+ * markers-visible form every interior offset is covered, so this branch
3255
+ * keeps distinct offsets distinct.
3256
+ * - Otherwise `offset` sits in a gap — a hidden inline marker such as the
3257
+ * `**` of `**bold**`, or before/after the painted text. It snaps to the
3258
+ * seam between the source-nearest runs on either side: the right edge of
3259
+ * the closest run ending at/before `offset`, else the left edge of the
3260
+ * closest run starting at/after it. A hidden marker collapses to zero
3261
+ * width, so both edges coincide at the seam.
1930
3262
  */
1931
3263
  xAtOffset(offset: SourceOffset): number;
1932
3264
  /**
1933
3265
  * Snap `x` to the nearest offset on this line. If `x` falls inside a
1934
- * run, the offset is interpolated by character fraction; otherwise it
1935
- * snaps to the closer edge of the nearest run.
3266
+ * run, the run resolves the offset (exact glyph boundary for text runs,
3267
+ * nearer edge for source-less runs); otherwise it snaps to the closer
3268
+ * edge of the nearest run.
1936
3269
  */
1937
3270
  offsetAtX(x: number): SourceOffset;
1938
3271
  }
1939
3272
 
1940
3273
  /**
1941
3274
  * Geometry of the rendered document, as a map from source offsets to 2D
1942
- * positions and back.
3275
+ * positions and back. All geometry is expressed in the editor overlay's local
3276
+ * CSS-pixel coordinate space.
1943
3277
  *
1944
3278
  * Structure (top to bottom):
1945
3279
  *
@@ -1974,7 +3308,9 @@ export declare class VisualLineMap {
1974
3308
  static measure(blockViews: readonly {
1975
3309
  readonly absoluteStart: number;
1976
3310
  readonly viewNode: ViewNode;
1977
- }[]): VisualLineMap;
3311
+ }[], coordinateSpace: EditorCoordinateSpace, transform?: EditorCoordinateTransform): VisualLineMap;
3312
+ /** Lines backed by source ranges, excluding source-less cursor lines. */
3313
+ readonly sourceLines: readonly VisualLine[];
1978
3314
  constructor(lines: readonly VisualLine[]);
1979
3315
  get lineCount(): number;
1980
3316
  get isEmpty(): boolean;
@@ -1999,6 +3335,12 @@ export declare class VisualLineMap {
1999
3335
  * {@link lineIndexOfOffset}. Returns `0` when the map is empty.
2000
3336
  */
2001
3337
  xAtOffset(offset: SourceOffset): number;
3338
+ /**
3339
+ * Line occupied by a source or virtual cursor position. A virtual position
3340
+ * returns `undefined` until its corresponding DOM line has been measured.
3341
+ */
3342
+ lineIndexOfPosition(position: CursorPosition): number | undefined;
3343
+ xAtPosition(position: CursorPosition): number;
2002
3344
  /**
2003
3345
  * Line whose vertical band contains `y`, clamped to the first/last
2004
3346
  * line when `y` is outside the document.
@@ -2012,6 +3354,9 @@ export declare class VisualLineMap {
2012
3354
  offsetAtPoint(point: Point2D): SourceOffset;
2013
3355
  /** Snap `x` to the nearest offset on a specific line. */
2014
3356
  offsetInLineAtX(lineIndex: number, x: number): SourceOffset;
3357
+ positionInLineAtX(lineIndex: number, x: number): CursorPosition;
3358
+ lineStartOffset(lineIndex: number): SourceOffset | undefined;
3359
+ lineEndOffset(lineIndex: number): SourceOffset | undefined;
2015
3360
  }
2016
3361
 
2017
3362
  /**
@@ -2020,14 +3365,22 @@ export declare class VisualLineMap {
2020
3365
  * When constructed with a {@link VisualRunSource}, `xAtOffset` returns the
2021
3366
  * pixel-exact x of the caret before character `offset` by measuring the
2022
3367
  * prefix `[textNodeStart, textNodeStart + (offset - sourceStart))` with a
2023
- * DOM `Range`. Without a source it falls back to linear interpolation
2024
- * across `rect.width`.
3368
+ * DOM `Range`.
3369
+ *
3370
+ * A source-less run has no per-offset geometry: it either represents an
3371
+ * element-only block (KaTeX math, a mermaid/custom diagram, an image, an
3372
+ * inactive `<hr>`) whose box does not correspond to source offsets, or a
3373
+ * hand-built run in a test. Either way it maps between offsets and x by
3374
+ * snapping to the nearer edge of {@link rect} rather than fabricating
3375
+ * interior positions.
2025
3376
  */
2026
3377
  export declare class VisualRun {
2027
3378
  readonly sourceRange: OffsetRange;
2028
3379
  readonly rect: Rect2D;
2029
3380
  readonly source?: VisualRunSource | undefined;
2030
- constructor(sourceRange: OffsetRange, rect: Rect2D, source?: VisualRunSource | undefined);
3381
+ readonly isVisualLineAnchor: boolean;
3382
+ static visualLineAnchor(sourceOffset: SourceOffset, rect: Rect2D): VisualRun;
3383
+ constructor(sourceRange: OffsetRange, rect: Rect2D, source?: VisualRunSource | undefined, isVisualLineAnchor?: boolean);
2031
3384
  get sourceStart(): SourceOffset;
2032
3385
  get sourceEndExclusive(): SourceOffset;
2033
3386
  get sourceLength(): number;
@@ -2039,19 +3392,40 @@ export declare class VisualRun {
2039
3392
 
2040
3393
  /**
2041
3394
  * The DOM source of a {@link VisualRun}. When set, `xAtOffset` and
2042
- * `offsetAtX` measure exact glyph positions via `Range.getBoundingClientRect`
2043
- * instead of linear interpolation across the run's rect. This matters for
2044
- * proportional fonts where character widths differ a lot (e.g. `m` vs `i`)
2045
- * and a caret placed by interpolation lands several pixels inside the
2046
- * wrong character.
3395
+ * `offsetAtX` measure exact glyph positions via `Range.getBoundingClientRect`.
3396
+ * This matters for proportional fonts where character widths differ a lot
3397
+ * (e.g. `m` vs `i`): a caret placed by anything coarser than real glyph
3398
+ * measurement lands several pixels inside the wrong character.
2047
3399
  *
2048
- * Hand-built runs (tests) omit this; their `xAtOffset` falls back to
2049
- * linear interpolation.
3400
+ * A run without a source has no per-offset geometry, so it maps between
3401
+ * offsets and x by snapping to the nearer run edge. Real text runs always
3402
+ * carry a source; source-less runs are element-only blocks (see
3403
+ * {@link _appendElementBlockRun}) and hand-built runs in tests.
2050
3404
  */
2051
3405
  declare interface VisualRunSource {
2052
3406
  readonly textNode: Text;
2053
3407
  /** Offset within `textNode.data` corresponding to `sourceRange.start`. */
2054
3408
  readonly textNodeStart: number;
3409
+ readonly coordinateSpace: EditorCoordinateSpace;
3410
+ }
3411
+
3412
+ export declare const vscodeHostKeyboardProfile: KeyboardProfile;
3413
+
3414
+ export declare const vscodeKeyboardProfile: KeyboardProfile;
3415
+
3416
+ export declare const vscodeLocalKeyboardProfile: KeyboardProfile;
3417
+
3418
+ export declare class VscodeStackedCommentsView extends StackedCommentsPresenter {
3419
+ protected createWidget(comment: Comment_2): StackWidget;
3420
+ }
3421
+
3422
+ export declare class VsCodeV2CommentsView extends StackedCommentsPresenter {
3423
+ protected createWidget(comment: Comment_2): StackWidget;
3424
+ }
3425
+
3426
+ export declare interface WordNavigationConfig {
3427
+ readonly wordSeparators: string;
3428
+ readonly wordSegmenterLocales: readonly string[];
2055
3429
  }
2056
3430
 
2057
3431
  export { }