Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/viewParts/notebookOverviewRuler.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { getWindow } from '../../../../../base/browser/dom.js';
7
import { createFastDomNode, FastDomNode } from '../../../../../base/browser/fastDomNode.js';
8
import { PixelRatio } from '../../../../../base/browser/pixelRatio.js';
9
import { IThemeService, Themable } from '../../../../../platform/theme/common/themeService.js';
10
import { INotebookEditorDelegate, NotebookOverviewRulerLane } from '../notebookBrowser.js';
11
12
export class NotebookOverviewRuler extends Themable {
13
private readonly _domNode: FastDomNode<HTMLCanvasElement>;
14
private _lanes = 3;
15
16
constructor(readonly notebookEditor: INotebookEditorDelegate, container: HTMLElement, @IThemeService themeService: IThemeService) {
17
super(themeService);
18
this._domNode = createFastDomNode(document.createElement('canvas'));
19
this._domNode.setPosition('relative');
20
this._domNode.setLayerHinting(true);
21
this._domNode.setContain('strict');
22
23
container.appendChild(this._domNode.domNode);
24
25
this._register(notebookEditor.onDidChangeDecorations(() => {
26
this.layout();
27
}));
28
29
this._register(PixelRatio.getInstance(getWindow(this._domNode.domNode)).onDidChange(() => {
30
this.layout();
31
}));
32
}
33
34
layout() {
35
const width = 10;
36
const layoutInfo = this.notebookEditor.getLayoutInfo();
37
const scrollHeight = layoutInfo.scrollHeight;
38
const height = layoutInfo.height;
39
const ratio = PixelRatio.getInstance(getWindow(this._domNode.domNode)).value;
40
this._domNode.setWidth(width);
41
this._domNode.setHeight(height);
42
this._domNode.domNode.width = width * ratio;
43
this._domNode.domNode.height = height * ratio;
44
const ctx = this._domNode.domNode.getContext('2d')!;
45
ctx.clearRect(0, 0, width * ratio, height * ratio);
46
this._render(ctx, width * ratio, height * ratio, scrollHeight * ratio, ratio);
47
}
48
49
private _render(ctx: CanvasRenderingContext2D, width: number, height: number, scrollHeight: number, ratio: number) {
50
const viewModel = this.notebookEditor.getViewModel();
51
const fontInfo = this.notebookEditor.getLayoutInfo().fontInfo;
52
const laneWidth = width / this._lanes;
53
54
let currentFrom = 0;
55
56
if (viewModel) {
57
for (let i = 0; i < viewModel.viewCells.length; i++) {
58
const viewCell = viewModel.viewCells[i];
59
const textBuffer = viewCell.textBuffer;
60
const decorations = viewCell.getCellDecorations();
61
const cellHeight = (viewCell.layoutInfo.totalHeight / scrollHeight) * ratio * height;
62
63
decorations.filter(decoration => decoration.overviewRuler).forEach(decoration => {
64
const overviewRuler = decoration.overviewRuler!;
65
const fillStyle = this.getColor(overviewRuler.color) ?? '#000000';
66
const lineHeight = Math.min(fontInfo.lineHeight, (viewCell.layoutInfo.editorHeight / scrollHeight / textBuffer.getLineCount()) * ratio * height);
67
const lineNumbers = overviewRuler.modelRanges.map(range => range.startLineNumber).reduce((previous: number[], current: number) => {
68
if (previous.length === 0) {
69
previous.push(current);
70
} else {
71
const last = previous[previous.length - 1];
72
if (last !== current) {
73
previous.push(current);
74
}
75
}
76
77
return previous;
78
}, [] as number[]);
79
80
let x = 0;
81
switch (overviewRuler.position) {
82
case NotebookOverviewRulerLane.Left:
83
x = 0;
84
break;
85
case NotebookOverviewRulerLane.Center:
86
x = laneWidth;
87
break;
88
case NotebookOverviewRulerLane.Right:
89
x = laneWidth * 2;
90
break;
91
default:
92
break;
93
}
94
95
const width = overviewRuler.position === NotebookOverviewRulerLane.Full ? laneWidth * 3 : laneWidth;
96
97
for (let i = 0; i < lineNumbers.length; i++) {
98
ctx.fillStyle = fillStyle;
99
const lineNumber = lineNumbers[i];
100
const offset = (lineNumber - 1) * lineHeight;
101
ctx.fillRect(x, currentFrom + offset, width, lineHeight);
102
}
103
104
if (overviewRuler.includeOutput) {
105
ctx.fillStyle = fillStyle;
106
const outputOffset = (viewCell.layoutInfo.editorHeight / scrollHeight) * ratio * height;
107
const decorationHeight = (fontInfo.lineHeight / scrollHeight) * ratio * height;
108
ctx.fillRect(laneWidth, currentFrom + outputOffset, laneWidth, decorationHeight);
109
}
110
});
111
112
currentFrom += cellHeight;
113
}
114
115
const overviewRulerDecorations = viewModel.getOverviewRulerDecorations();
116
117
for (let i = 0; i < overviewRulerDecorations.length; i++) {
118
const decoration = overviewRulerDecorations[i];
119
if (!decoration.options.overviewRuler) {
120
continue;
121
}
122
const viewZoneInfo = this.notebookEditor.getViewZoneLayoutInfo(decoration.viewZoneId);
123
124
if (!viewZoneInfo) {
125
continue;
126
}
127
128
const fillStyle = this.getColor(decoration.options.overviewRuler.color) ?? '#000000';
129
let x = 0;
130
switch (decoration.options.overviewRuler.position) {
131
case NotebookOverviewRulerLane.Left:
132
x = 0;
133
break;
134
case NotebookOverviewRulerLane.Center:
135
x = laneWidth;
136
break;
137
case NotebookOverviewRulerLane.Right:
138
x = laneWidth * 2;
139
break;
140
default:
141
break;
142
}
143
144
const width = decoration.options.overviewRuler.position === NotebookOverviewRulerLane.Full ? laneWidth * 3 : laneWidth;
145
146
ctx.fillStyle = fillStyle;
147
148
const viewZoneHeight = (viewZoneInfo.height / scrollHeight) * ratio * height;
149
const viewZoneTop = (viewZoneInfo.top / scrollHeight) * ratio * height;
150
151
ctx.fillRect(x, viewZoneTop, width, viewZoneHeight);
152
}
153
}
154
}
155
}
156
157