Skip to content

Commit

Permalink
Add support for basic scaling of horizontal gaps
Browse files Browse the repository at this point in the history
FIX: Improve the way enormously long (non-wrapped) lines are displayed by making sure they
stay shorter than the maximal pixel size the browser's CSS engine can handle.

Closes codemirror/dev#1448
  • Loading branch information
marijnh committed Sep 27, 2024
1 parent 86d355a commit a5424ff
Showing 1 changed file with 18 additions and 8 deletions.
26 changes: 18 additions & 8 deletions src/viewstate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ const enum VP {
MaxCoverMargin = VP.Margin / 4,
// Beyond this size, DOM layout starts to break down in browsers
// because they use fixed-precision numbers to store dimensions.
MaxDOMHeight = 7e6
MaxDOMHeight = 7e6,
MaxHorizGap = 2e6
}

// Line gaps are placeholder widgets used to hide pieces of overlong
// lines within the viewport, as a kludge to keep the editor
// responsive when a ridiculously long line is loaded into it.
export class LineGap {
constructor(readonly from: number, readonly to: number, readonly size: number) {}
constructor(readonly from: number, readonly to: number, readonly size: number, readonly displaySize: number) {}

static same(a: readonly LineGap[], b: readonly LineGap[]) {
if (a.length != b.length) return false
Expand All @@ -71,7 +72,7 @@ export class LineGap {

draw(viewState: ViewState, wrapping: boolean) {
return Decoration.replace({
widget: new LineGapWidget(this.size * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
widget: new LineGapWidget(this.displaySize * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
}).range(this.from, this.to)
}
}
Expand Down Expand Up @@ -420,7 +421,7 @@ export class ViewState {
if (!gaps.length || changes.empty) return gaps
let mapped = []
for (let gap of gaps) if (!changes.touchesRange(gap.from, gap.to))
mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size))
mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size, gap.displaySize))
return mapped
}

Expand Down Expand Up @@ -458,7 +459,9 @@ export class ViewState {
let lineStart = mayMeasure.moveToLineBoundary(EditorSelection.cursor(to), false, true).head
if (lineStart > from) to = lineStart
}
gap = new LineGap(from, to, this.gapSize(line, from, to, structure))
let size = this.gapSize(line, from, to, structure)
let displaySize = wrapping || size < VP.MaxHorizGap ? size : VP.MaxHorizGap
gap = new LineGap(from, to, size, displaySize)
}
gaps.push(gap)
}
Expand Down Expand Up @@ -486,15 +489,22 @@ export class ViewState {
} else {
let totalWidth = structure.total * this.heightOracle.charWidth
let marginWidth = margin * this.heightOracle.charWidth
let horizOffset = 0
if (totalWidth > VP.MaxHorizGap) for (let old of current) {
if (old.from >= line.from && old.from < line.to && old.size != old.displaySize &&
old.from * this.heightOracle.charWidth + horizOffset < this.pixelViewport.left)
horizOffset = old.size - old.displaySize
}
let pxLeft = this.pixelViewport.left + horizOffset, pxRight = this.pixelViewport.right + horizOffset
let left, right
if (target != null) {
let targetFrac = findFraction(structure, target)
let spaceFrac = ((this.pixelViewport.right - this.pixelViewport.left) / 2 + marginWidth) / totalWidth
let spaceFrac = ((pxRight - pxLeft) / 2 + marginWidth) / totalWidth
left = targetFrac - spaceFrac
right = targetFrac + spaceFrac
} else {
left = (this.pixelViewport.left - marginWidth) / totalWidth
right = (this.pixelViewport.right + marginWidth) / totalWidth
left = (pxLeft - marginWidth) / totalWidth
right = (pxRight + marginWidth) / totalWidth
}
viewFrom = findPosition(structure, left)
viewTo = findPosition(structure, right)
Expand Down

0 comments on commit a5424ff

Please sign in to comment.