Skip to content

copilot -- Notebook sticky scroll does not show correct element based viewport #251415

@Yoyokrazy

Description

@Yoyokrazy

re: #211122

Issue:

Sometimes when scrolling through a notebook, the sticky scroll lines that appear will render consistently far too late. A header that is in cell 1 of the notebook will not be revealed until far later. I do not know the cause or a consistent set of steps for reproduction.

Information:

All of the code is located in src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts
Here are mermaid diagrams that accurately describe the components and interactions.

Notebook Editor Sticky Scroll Architecture

classDiagram
    class NotebookStickyScroll {
        -domNode: HTMLElement
        -notebookEditor: INotebookEditor
        -notebookCellList: INotebookCellList
        -layoutFn: Function
        -currentStickyLines: Map~OutlineEntry, StickyLineInfo~
        -notebookCellOutlineReference: IReference~NotebookCellOutlineDataSource~
        -_onDidChangeNotebookStickyScroll: Emitter~number~
        +getDomNode(): HTMLElement
        +getCurrentStickyHeight(): number
        +onDidChangeNotebookStickyScroll: Event~number~
        -init(): Promise~void~
        -updateConfig(e: NotebookOptionsChangeEvent): void
        -updateContent(newMap: Map): void
        -onContextMenu(e: MouseEvent): void
        +dispose(): void
    }

    class NotebookStickyLine {
        +element: HTMLElement
        +foldingIcon: StickyFoldingIcon
        +header: HTMLElement
        +entry: OutlineEntry
        +notebookEditor: INotebookEditor
        -toggleFoldRange(currentState: CellFoldingState): void
        -focusCell(): void
        +getParentCount(entry: OutlineEntry): number
    }

    class StickyFoldingIcon {
        +domNode: HTMLElement
        +isCollapsed: boolean
        +dimension: number
        +setVisible(visible: boolean): void
    }

    class OutlineEntry {
        +cell: ICellViewModel
        +index: number
        +level: number
        +label: string
        +parent: OutlineEntry
        +asFlatList(flatList: OutlineEntry[]): void
    }

    class NotebookCellOutlineDataSource {
        +entries: OutlineEntry[]
        +onDidChange: Event~void~
        +computeFullSymbols(token: CancellationToken): Promise~void~
    }

    class INotebookEditor {
        +notebookOptions: NotebookOptions
        +scrollTop: number
        +visibleRanges: VisibleRange[]
        +onDidScroll(): Event~void~
        +onDidAttachViewModel(): Event~void~
        +focusNotebookCell(cell, focus): void
        +getAbsoluteTopOfElement(cell): number
        +setScrollTop(top: number): void
        +cellAt(index: number): ICellViewModel
        +getLayoutInfo(): LayoutInfo
    }

    class INotebookCellList {
        +triggerScrollFromMouseWheelEvent(event: IMouseWheelEvent): void
        +getCellViewScrollTop(cell): number
    }

    %% Relationships
    NotebookStickyScroll --> NotebookStickyLine : creates/manages
    NotebookStickyScroll --> NotebookCellOutlineDataSource : uses
    NotebookStickyScroll --> INotebookEditor : interacts with
    NotebookStickyScroll --> INotebookCellList : uses

    NotebookStickyLine --> StickyFoldingIcon : contains
    NotebookStickyLine --> OutlineEntry : represents
    NotebookStickyLine --> INotebookEditor : controls

    NotebookCellOutlineDataSource --> OutlineEntry : produces

    %% Composition relationships
    NotebookStickyScroll *-- NotebookStickyLine
    NotebookStickyLine *-- StickyFoldingIcon
Loading

Flow Diagram

flowchart TD
    A[NotebookStickyScroll Init] --> B[Get Outline Data Source]
    B --> C[Compute Full Symbols]
    C --> D[Initial Content Update]
    D --> E[Setup Event Listeners]

    E --> F[Scroll Event]
    E --> G[Outline Change Event]
    E --> H[View Model Change Event]
    E --> I[Options Change Event]

    F --> J[Compute Content]
    G --> J
    H --> J
    I --> K[Update Config]

    J --> L[Compare with Current Sticky Lines]
    L --> M{Lines Changed?}
    M -->|Yes| N[Update Content]
    M -->|No| O[Dispose Computed Lines]

    N --> P[Clear DOM]
    P --> Q[Dispose Current Lines]
    Q --> R[Render New Lines]
    R --> S[Update Height]
    S --> T[Fire Change Event]
    T --> U[Layout Update]

    K --> V{Sticky Enabled?}
    V -->|Yes| A
    V -->|No| W[Clear & Dispose]
Loading

Content Computation Flow

flowchart TD
    A[computeContent Function] --> B[Get Editor Scroll Top]
    B --> C[Get Visible Range]
    C --> D{Visible Range Exists?}
    D -->|No| E[Return Empty Map]
    D -->|Yes| F{First Cell is Header?}

    F -->|Yes| G[Check if Should Show First Cell Sticky]
    F -->|No| H[Iterate Visible Cells]

    G --> I{Scroll > 22px?}
    I -->|Yes| J[Create Sticky Lines for First Cell]
    I -->|No| H

    H --> K[Get Current Cell & Entry]
    K --> L[Get Next Cell & Entry]
    L --> M{Next Cell is Header?}

    M -->|Yes| N[Calculate Section Bottom]
    M -->|No| O[Continue to Next Cell]

    N --> P[Calculate Sticky Heights]
    P --> Q{Can Render All Lines?}
    Q -->|Yes| R[Render All Lines for Section]
    Q -->|No| S{Next Section >= Current?}

    S -->|Yes| T[Render Next Section Lines]
    S -->|No| U{Available Space >= Next Height?}

    U -->|Yes| V[Render Limited Lines]
    U -->|No| T

    O --> W{More Cells?}
    W -->|Yes| K
    W -->|No| X[Render Lines for Last Section]

    J --> Y[Return Sticky Lines Map]
    R --> Y
    T --> Y
    V --> Y
    X --> Y
    E --> Y
Loading

Key Components Interaction

sequenceDiagram
    participant User
    participant StickyScroll as NotebookStickyScroll
    participant Editor as INotebookEditor
    participant Outline as NotebookCellOutlineDataSource
    participant StickyLine as NotebookStickyLine

    User->>Editor: Scrolls notebook
    Editor->>StickyScroll: onDidScroll event
    StickyScroll->>Outline: Get current entries
    StickyScroll->>StickyScroll: computeContent()
    StickyScroll->>StickyLine: Create new sticky lines
    StickyScroll->>StickyScroll: updateContent()
    StickyScroll->>Editor: Fire height change event
    Editor->>StickyScroll: layoutFn callback

    User->>StickyLine: Click header
    StickyLine->>Editor: focusNotebookCell()
    StickyLine->>Editor: setScrollTop()

    User->>StickyLine: Click folding icon
    StickyLine->>StickyLine: toggleFoldRange()
    StickyLine->>Editor: Update folding state

    User->>StickyScroll: Right-click (context menu)
    StickyScroll->>StickyScroll: onContextMenu()
    StickyScroll->>Editor: Show context menu
Loading

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions