viewImpl.ts 36.0 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

A
Alex Dima 已提交
7
import {onUnexpectedError} from 'vs/base/common/errors';
A
Alex Dima 已提交
8
import {EventEmitter, EmitterEvent, IEventEmitter} from 'vs/base/common/eventEmitter';
J
Joao Moreno 已提交
9
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
10 11 12
import * as timer from 'vs/base/common/timer';
import * as browser from 'vs/base/browser/browser';
import * as dom from 'vs/base/browser/dom';
A
Alex Dima 已提交
13
import {StyleMutator} from 'vs/base/browser/styleMutator';
A
Alex Dima 已提交
14
import {IContextKey, IContextKeyService} from 'vs/platform/contextkey/common/contextkey';
15
import {ICommandService} from 'vs/platform/commands/common/commands';
A
Alex Dima 已提交
16 17
import {Range} from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
E
Erich Gamma 已提交
18
import {ViewEventHandler} from 'vs/editor/common/viewModel/viewEventHandler';
A
Alex Dima 已提交
19
import {Configuration} from 'vs/editor/browser/config/configuration';
20
import {KeyboardHandler, IKeyboardHandlerHelper} from 'vs/editor/browser/controller/keyboardHandler';
E
Erich Gamma 已提交
21
import {PointerHandler} from 'vs/editor/browser/controller/pointerHandler';
A
Alex Dima 已提交
22
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
A
Alex Dima 已提交
23
import {ViewController, TriggerCursorHandler} from 'vs/editor/browser/view/viewController';
A
Alex Dima 已提交
24
import {ViewEventDispatcher} from 'vs/editor/browser/view/viewEventDispatcher';
E
Erich Gamma 已提交
25
import {ContentViewOverlays, MarginViewOverlays} from 'vs/editor/browser/view/viewOverlays';
A
Alex Dima 已提交
26
import {LayoutProvider} from 'vs/editor/browser/viewLayout/layoutProvider';
E
Erich Gamma 已提交
27 28 29 30 31
import {ViewContentWidgets} from 'vs/editor/browser/viewParts/contentWidgets/contentWidgets';
import {CurrentLineHighlightOverlay} from 'vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight';
import {DecorationsOverlay} from 'vs/editor/browser/viewParts/decorations/decorations';
import {GlyphMarginOverlay} from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';
import {LineNumbersOverlay} from 'vs/editor/browser/viewParts/lineNumbers/lineNumbers';
32
import {IndentGuidesOverlay} from 'vs/editor/browser/viewParts/indentGuides/indentGuides';
A
Alex Dima 已提交
33 34 35 36 37
import {ViewLines} from 'vs/editor/browser/viewParts/lines/viewLines';
import {LinesDecorationsOverlay} from 'vs/editor/browser/viewParts/linesDecorations/linesDecorations';
import {ViewOverlayWidgets} from 'vs/editor/browser/viewParts/overlayWidgets/overlayWidgets';
import {DecorationsOverviewRuler} from 'vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler';
import {OverviewRuler} from 'vs/editor/browser/viewParts/overviewRuler/overviewRuler';
38
import {Rulers} from 'vs/editor/browser/viewParts/rulers/rulers';
A
Alex Dima 已提交
39 40 41 42
import {ScrollDecorationViewPart} from 'vs/editor/browser/viewParts/scrollDecoration/scrollDecoration';
import {SelectionsOverlay} from 'vs/editor/browser/viewParts/selections/selections';
import {ViewCursors} from 'vs/editor/browser/viewParts/viewCursors/viewCursors';
import {ViewZones} from 'vs/editor/browser/viewParts/viewZones/viewZones';
A
Alex Dima 已提交
43
import {ViewPart} from 'vs/editor/browser/view/viewPart';
A
Alex Dima 已提交
44
import {ViewContext, IViewEventHandler} from 'vs/editor/common/view/viewContext';
45 46 47 48
import {IViewModel} from 'vs/editor/common/viewModel/viewModel';
import {ViewLinesViewportData} from 'vs/editor/common/viewLayout/viewLinesViewportData';
import {IRenderingContext} from 'vs/editor/common/view/renderingContext';
import {IPointerHandlerHelper} from 'vs/editor/browser/controller/mouseHandler';
E
Erich Gamma 已提交
49

A
Alex Dima 已提交
50 51
import EditorContextKeys = editorCommon.EditorContextKeys;

A
Alex Dima 已提交
52
export class View extends ViewEventHandler implements editorBrowser.IView, IDisposable {
E
Erich Gamma 已提交
53 54 55

	private eventDispatcher:ViewEventDispatcher;

A
Alex Dima 已提交
56
	private listenersToRemove:IDisposable[];
A
Alex Dima 已提交
57
	private listenersToDispose:IDisposable[];
E
Erich Gamma 已提交
58 59

	private layoutProvider: LayoutProvider;
60
	public _context: ViewContext;
E
Erich Gamma 已提交
61 62 63 64 65 66 67 68

	// The view lines
	private viewLines: ViewLines;

	// These are parts, but we must do some API related calls on them, so we keep a reference
	private viewZones: ViewZones;
	private contentWidgets: ViewContentWidgets;
	private overlayWidgets: ViewOverlayWidgets;
69
	private viewCursors: ViewCursors;
A
Alex Dima 已提交
70
	private viewParts: ViewPart[];
E
Erich Gamma 已提交
71 72 73 74

	private keyboardHandler: KeyboardHandler;
	private pointerHandler: PointerHandler;

A
Alex Dima 已提交
75
	private outgoingEventBus: EventEmitter;
E
Erich Gamma 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89

	// Dom nodes
	private linesContent: HTMLElement;
	public domNode: HTMLElement;
	public textArea: HTMLTextAreaElement;
	private textAreaCover: HTMLElement;
	private linesContentContainer: HTMLElement;
	private overflowGuardContainer: HTMLElement;

	// Actual mutable state
	private hasFocus:boolean;
	private _isDisposed: boolean;

	private handleAccumulatedModelEventsTimeout:number;
A
Alex Dima 已提交
90
	private accumulatedModelEvents: EmitterEvent[];
A
Alex Dima 已提交
91
	private _renderAnimationFrame: IDisposable;
E
Erich Gamma 已提交
92

A
Alex Dima 已提交
93
	private _editorTextFocusContextKey: IContextKey<boolean>;
E
Erich Gamma 已提交
94

A
Alex Dima 已提交
95
	constructor(
96
		contextKeyService: IContextKeyService,
97
		commandService: ICommandService,
A
Alex Dima 已提交
98 99
		configuration:Configuration,
		model:IViewModel,
100
		private triggerCursorHandler:TriggerCursorHandler
A
Alex Dima 已提交
101
	) {
E
Erich Gamma 已提交
102 103 104
		super();
		this._isDisposed = false;
		this._renderAnimationFrame = null;
A
Alex Dima 已提交
105
		this.outgoingEventBus = new EventEmitter();
E
Erich Gamma 已提交
106

107
		var viewController = new ViewController(model, triggerCursorHandler, this.outgoingEventBus, commandService);
E
Erich Gamma 已提交
108 109 110 111 112 113 114 115 116

		this.listenersToRemove = [];
		this.listenersToDispose = [];

		// The event dispatcher will always go through _renderOnce before dispatching any events
		this.eventDispatcher = new ViewEventDispatcher((callback:()=>void) => this._renderOnce(callback));

		// These two dom nodes must be constructed up front, since references are needed in the layout provider (scrolling & co.)
		this.linesContent = document.createElement('div');
A
Alex Dima 已提交
117
		this.linesContent.className = editorBrowser.ClassNames.LINES_CONTENT + ' monaco-editor-background';
E
Erich Gamma 已提交
118
		this.domNode = document.createElement('div');
119
		this.domNode.className = configuration.editor.viewInfo.editorClassName;
E
Erich Gamma 已提交
120 121

		this.overflowGuardContainer = document.createElement('div');
A
Alex Dima 已提交
122
		this.overflowGuardContainer.className = editorBrowser.ClassNames.OVERFLOW_GUARD;
E
Erich Gamma 已提交
123 124 125 126 127 128 129 130 131

		// The layout provider has such responsibilities as:
		// - scrolling (i.e. viewport / full size) & co.
		// - whitespaces (a.k.a. view zones) management & co.
		// - line heights updating & co.
		this.layoutProvider = new LayoutProvider(configuration, model, this.eventDispatcher, this.linesContent, this.domNode, this.overflowGuardContainer);
		this.eventDispatcher.addEventHandler(this.layoutProvider);

		// The view context is passed on to most classes (basically to reduce param. counts in ctors)
132 133
		this._context = new ViewContext(
				configuration, model, this.eventDispatcher,
A
Alex Dima 已提交
134 135
				(eventHandler:IViewEventHandler) => this.eventDispatcher.addEventHandler(eventHandler),
				(eventHandler:IViewEventHandler) => this.eventDispatcher.removeEventHandler(eventHandler)
E
Erich Gamma 已提交
136 137
		);

138
		this.createTextArea(contextKeyService);
E
Erich Gamma 已提交
139 140 141
		this.createViewParts();

		// Keyboard handler
142
		this.keyboardHandler = new KeyboardHandler(this._context, viewController, this.createKeyboardHandlerHelper());
E
Erich Gamma 已提交
143 144

		// Pointer handler
145
		this.pointerHandler = new PointerHandler(this._context, viewController, this.createPointerHandlerHelper());
E
Erich Gamma 已提交
146 147 148 149 150 151 152 153 154 155

		this.hasFocus = false;
		this.codeEditorHelper = null;

		this.eventDispatcher.addEventHandler(this);

		// The view lines rendering calls model.getLineTokens() that might emit events that its tokens have changed.
		// This delayed processing of incoming model events acts as a guard against undesired/unexpected recursion.
		this.handleAccumulatedModelEventsTimeout = -1;
		this.accumulatedModelEvents = [];
A
Alex Dima 已提交
156
		this.listenersToRemove.push(model.addBulkListener2((events:EmitterEvent[]) => {
E
Erich Gamma 已提交
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
			this.accumulatedModelEvents = this.accumulatedModelEvents.concat(events);
			if (this.handleAccumulatedModelEventsTimeout === -1) {
				this.handleAccumulatedModelEventsTimeout = setTimeout(() => {
					this.handleAccumulatedModelEventsTimeout = -1;
					this._flushAnyAccumulatedEvents();
				});
			}
		}));
	}

	private _flushAnyAccumulatedEvents(): void {
		var toEmit = this.accumulatedModelEvents;
		this.accumulatedModelEvents = [];
		if (toEmit.length > 0) {
			this.eventDispatcher.emitMany(toEmit);
		}
	}

175
	private createTextArea(contextKeyService: IContextKeyService): void {
E
Erich Gamma 已提交
176 177
		// Text Area (The focus will always be in the textarea when the cursor is blinking)
		this.textArea = <HTMLTextAreaElement>document.createElement('textarea');
178
		this._editorTextFocusContextKey = EditorContextKeys.TextFocus.bindTo(contextKeyService);
A
Alex Dima 已提交
179
		this.textArea.className = editorBrowser.ClassNames.TEXTAREA;
E
Erich Gamma 已提交
180 181 182 183
		this.textArea.setAttribute('wrap', 'off');
		this.textArea.setAttribute('autocorrect', 'off');
		this.textArea.setAttribute('autocapitalize', 'off');
		this.textArea.setAttribute('spellcheck', 'false');
184
		this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
E
Erich Gamma 已提交
185 186
		this.textArea.setAttribute('role', 'textbox');
		this.textArea.setAttribute('aria-multiline', 'true');
A
Alex Dima 已提交
187 188 189
		this.textArea.setAttribute('aria-haspopup', 'false');
		this.textArea.setAttribute('aria-autocomplete', 'both');

A
Alex Dima 已提交
190 191
		StyleMutator.setTop(this.textArea, 0);
		StyleMutator.setLeft(this.textArea, 0);
E
Erich Gamma 已提交
192

A
Alex Dima 已提交
193 194
		this.listenersToDispose.push(dom.addDisposableListener(this.textArea, 'focus', () => this._setHasFocus(true)));
		this.listenersToDispose.push(dom.addDisposableListener(this.textArea, 'blur', () => this._setHasFocus(false)));
E
Erich Gamma 已提交
195 196 197 198 199

		// On top of the text area, we position a dom node to cover it up
		// (there have been reports of tiny blinking cursors)
		// (in WebKit the textarea is 1px by 1px because it cannot handle input to a 0x0 textarea)
		this.textAreaCover = document.createElement('div');
200
		if (this._context.configuration.editor.viewInfo.glyphMargin) {
A
Alex Dima 已提交
201
			this.textAreaCover.className = 'monaco-editor-background ' + editorBrowser.ClassNames.GLYPH_MARGIN + ' ' + editorBrowser.ClassNames.TEXTAREA_COVER;
E
Erich Gamma 已提交
202
		} else {
203
			if (this._context.configuration.editor.viewInfo.lineNumbers) {
A
Alex Dima 已提交
204
				this.textAreaCover.className = 'monaco-editor-background ' + editorBrowser.ClassNames.LINE_NUMBERS + ' ' + editorBrowser.ClassNames.TEXTAREA_COVER;
E
Erich Gamma 已提交
205
			} else {
A
Alex Dima 已提交
206
				this.textAreaCover.className = 'monaco-editor-background ' + editorBrowser.ClassNames.TEXTAREA_COVER;
E
Erich Gamma 已提交
207 208 209
			}
		}
		this.textAreaCover.style.position = 'absolute';
A
Alex Dima 已提交
210 211 212 213
		StyleMutator.setWidth(this.textAreaCover, 1);
		StyleMutator.setHeight(this.textAreaCover, 1);
		StyleMutator.setTop(this.textAreaCover, 0);
		StyleMutator.setLeft(this.textAreaCover, 0);
E
Erich Gamma 已提交
214 215 216 217 218 219
	}

	private createViewParts(): void {
		this.viewParts = [];

		// View Lines
220
		this.viewLines = new ViewLines(this._context, this.layoutProvider);
E
Erich Gamma 已提交
221 222

		// View Zones
223
		this.viewZones = new ViewZones(this._context, this.layoutProvider);
E
Erich Gamma 已提交
224 225 226 227
		this.viewParts.push(this.viewZones);

		// Decorations overview ruler
		var decorationsOverviewRuler = new DecorationsOverviewRuler(
228
				this._context, this.layoutProvider.getScrollHeight(),
E
Erich Gamma 已提交
229 230 231 232 233
				(lineNumber:number) => this.layoutProvider.getVerticalOffsetForLineNumber(lineNumber)
		);
		this.viewParts.push(decorationsOverviewRuler);


234
		var scrollDecoration = new ScrollDecorationViewPart(this._context);
E
Erich Gamma 已提交
235 236
		this.viewParts.push(scrollDecoration);

237
		var contentViewOverlays = new ContentViewOverlays(this._context, this.layoutProvider);
E
Erich Gamma 已提交
238
		this.viewParts.push(contentViewOverlays);
239 240 241
		contentViewOverlays.addDynamicOverlay(new CurrentLineHighlightOverlay(this._context, this.layoutProvider));
		contentViewOverlays.addDynamicOverlay(new SelectionsOverlay(this._context));
		contentViewOverlays.addDynamicOverlay(new DecorationsOverlay(this._context));
242
		contentViewOverlays.addDynamicOverlay(new IndentGuidesOverlay(this._context));
E
Erich Gamma 已提交
243

244
		var marginViewOverlays = new MarginViewOverlays(this._context, this.layoutProvider);
E
Erich Gamma 已提交
245
		this.viewParts.push(marginViewOverlays);
246 247 248
		marginViewOverlays.addDynamicOverlay(new GlyphMarginOverlay(this._context));
		marginViewOverlays.addDynamicOverlay(new LinesDecorationsOverlay(this._context));
		marginViewOverlays.addDynamicOverlay(new LineNumbersOverlay(this._context));
E
Erich Gamma 已提交
249 250 251


		// Content widgets
252
		this.contentWidgets = new ViewContentWidgets(this._context, this.domNode);
E
Erich Gamma 已提交
253 254
		this.viewParts.push(this.contentWidgets);

255 256
		this.viewCursors = new ViewCursors(this._context);
		this.viewParts.push(this.viewCursors);
E
Erich Gamma 已提交
257 258

		// Overlay widgets
259
		this.overlayWidgets = new ViewOverlayWidgets(this._context);
E
Erich Gamma 已提交
260 261
		this.viewParts.push(this.overlayWidgets);

262
		var rulers = new Rulers(this._context, this.layoutProvider);
263 264
		this.viewParts.push(rulers);

E
Erich Gamma 已提交
265 266 267 268 269 270 271 272 273 274 275
		// -------------- Wire dom nodes up

		this.linesContentContainer = this.layoutProvider.getScrollbarContainerDomNode();
		this.linesContentContainer.style.position = 'absolute';

		if (decorationsOverviewRuler) {
			var overviewRulerData = this.layoutProvider.getOverviewRulerInsertData();
			overviewRulerData.parent.insertBefore(decorationsOverviewRuler.getDomNode(), overviewRulerData.insertBefore);
		}

		this.linesContent.appendChild(contentViewOverlays.getDomNode());
276
		this.linesContent.appendChild(rulers.domNode);
E
Erich Gamma 已提交
277
		this.linesContent.appendChild(this.viewZones.domNode);
A
Alex Dima 已提交
278
		this.linesContent.appendChild(this.viewLines.getDomNode());
E
Erich Gamma 已提交
279
		this.linesContent.appendChild(this.contentWidgets.domNode);
280
		this.linesContent.appendChild(this.viewCursors.getDomNode());
E
Erich Gamma 已提交
281 282 283 284 285 286 287
		this.overflowGuardContainer.appendChild(marginViewOverlays.getDomNode());
		this.overflowGuardContainer.appendChild(this.linesContentContainer);
		this.overflowGuardContainer.appendChild(scrollDecoration.getDomNode());
		this.overflowGuardContainer.appendChild(this.overlayWidgets.domNode);
		this.overflowGuardContainer.appendChild(this.textArea);
		this.overflowGuardContainer.appendChild(this.textAreaCover);
		this.domNode.appendChild(this.overflowGuardContainer);
288
		this.domNode.appendChild(this.contentWidgets.overflowingContentWidgetsDomNode);
E
Erich Gamma 已提交
289 290 291 292 293 294 295
	}

	private _flushAccumulatedAndRenderNow(): void {
		this._flushAnyAccumulatedEvents();
		this._renderNow();
	}

296
	private createPointerHandlerHelper(): IPointerHandlerHelper {
E
Erich Gamma 已提交
297 298 299 300 301 302 303 304 305 306 307
		return {
			viewDomNode: this.domNode,
			linesContentDomNode: this.linesContent,

			focusTextArea: () => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.focusTextArea: View is disposed');
				}
				this.focus();
			},

308 309 310 311
			isDirty: (): boolean => {
				return (this.accumulatedModelEvents.length > 0);
			},

E
Erich Gamma 已提交
312 313 314 315 316 317
			getScrollLeft: () => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getScrollLeft: View is disposed');
				}
				return this.layoutProvider.getScrollLeft();
			},
318 319 320 321 322 323 324 325
			getScrollTop: () => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getScrollTop: View is disposed');
				}
				return this.layoutProvider.getScrollTop();
			},

			setScrollPosition: (position:editorCommon.INewScrollPosition) => {
E
Erich Gamma 已提交
326
				if (this._isDisposed) {
327
					throw new Error('ViewImpl.pointerHandler.setScrollPosition: View is disposed');
E
Erich Gamma 已提交
328
				}
329
				this.layoutProvider.setScrollPosition(position);
E
Erich Gamma 已提交
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
			},

			isAfterLines: (verticalOffset: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.isAfterLines: View is disposed');
				}
				return this.layoutProvider.isAfterLines(verticalOffset);
			},
			getLineNumberAtVerticalOffset: (verticalOffset: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getLineNumberAtVerticalOffset: View is disposed');
				}
				return this.layoutProvider.getLineNumberAtVerticalOffset(verticalOffset);
			},
			getVerticalOffsetForLineNumber: (lineNumber: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getVerticalOffsetForLineNumber: View is disposed');
				}
				return this.layoutProvider.getVerticalOffsetForLineNumber(lineNumber);
			},
			getWhitespaceAtVerticalOffset: (verticalOffset: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getWhitespaceAtVerticalOffset: View is disposed');
				}
				return this.layoutProvider.getWhitespaceAtVerticalOffset(verticalOffset);
			},
356 357 358 359 360 361
			getLastViewCursorsRenderData: () => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getLastViewCursorsRenderData: View is disposed');
				}
				return this.viewCursors.getLastRenderData() || [];
			},
E
Erich Gamma 已提交
362 363 364 365 366 367
			shouldSuppressMouseDownOnViewZone: (viewZoneId: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.shouldSuppressMouseDownOnViewZone: View is disposed');
				}
				return this.viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId);
			},
368 369 370 371 372 373
			shouldSuppressMouseDownOnWidget: (widgetId: string) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.shouldSuppressMouseDownOnWidget: View is disposed');
				}
				return this.contentWidgets.shouldSuppressMouseDownOnWidget(widgetId);
			},
E
Erich Gamma 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386
			getPositionFromDOMInfo: (spanNode: HTMLElement, offset: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getPositionFromDOMInfo: View is disposed');
				}
				this._flushAccumulatedAndRenderNow();
				return this.viewLines.getPositionFromDOMInfo(spanNode, offset);
			},

			visibleRangeForPosition2: (lineNumber: number, column: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.visibleRangeForPosition2: View is disposed');
				}
				this._flushAccumulatedAndRenderNow();
A
Alex Dima 已提交
387
				var visibleRanges = this.viewLines.visibleRangesForRange2(new Range(lineNumber, column, lineNumber, column), 0);
E
Erich Gamma 已提交
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
				if (!visibleRanges) {
					return null;
				}
				return visibleRanges[0];
			},

			getLineWidth: (lineNumber: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.pointerHandler.getLineWidth: View is disposed');
				}
				this._flushAccumulatedAndRenderNow();
				return this.viewLines.getLineWidth(lineNumber);
			}
		};
	}

404
	private createKeyboardHandlerHelper(): IKeyboardHandlerHelper {
E
Erich Gamma 已提交
405 406 407 408 409 410 411 412 413
		return {
			viewDomNode: this.domNode,
			textArea: this.textArea,
			visibleRangeForPositionRelativeToEditor: (lineNumber: number, column: number) => {
				if (this._isDisposed) {
					throw new Error('ViewImpl.keyboardHandler.visibleRangeForPositionRelativeToEditor: View is disposed');
				}
				this._flushAccumulatedAndRenderNow();
				var linesViewPortData = this.layoutProvider.getLinesViewportData();
A
Alex Dima 已提交
414
				var visibleRanges = this.viewLines.visibleRangesForRange2(new Range(lineNumber, column, lineNumber, column), linesViewPortData.visibleRangesDeltaTop);
E
Erich Gamma 已提交
415 416 417 418
				if (!visibleRanges) {
					return null;
				}
				return visibleRanges[0];
419 420 421
			},
			flushAnyAccumulatedEvents: () => {
				this._flushAnyAccumulatedEvents();
E
Erich Gamma 已提交
422 423 424 425
			}
		};
	}

A
Alex Dima 已提交
426 427 428 429 430 431 432 433 434 435 436 437 438 439
	public setAriaActiveDescendant(id:string): void {
		if (id) {
			this.textArea.setAttribute('role', 'combobox');
			if (this.textArea.getAttribute('aria-activedescendant') !== id) {
				this.textArea.setAttribute('aria-haspopup', 'true');
				this.textArea.setAttribute('aria-activedescendant', id);
			}
		} else {
			this.textArea.setAttribute('role', 'textbox');
			this.textArea.removeAttribute('aria-activedescendant');
			this.textArea.removeAttribute('aria-haspopup');
		}
	}

E
Erich Gamma 已提交
440 441
	// --- begin event handlers

442
	public onLayoutChanged(layoutInfo:editorCommon.EditorLayoutInfo): boolean {
A
Alex Dima 已提交
443
		if (browser.isChrome) {
A
tslint  
Alex Dima 已提交
444
			/* tslint:disable:no-unused-variable */
E
Erich Gamma 已提交
445 446 447
			// Access overflowGuardContainer.clientWidth to prevent relayouting bug in Chrome
			// See Bug 19676: Editor misses a layout event
			var clientWidth = this.overflowGuardContainer.clientWidth + 'px';
A
tslint  
Alex Dima 已提交
448
			/* tslint:enable:no-unused-variable */
E
Erich Gamma 已提交
449
		}
A
Alex Dima 已提交
450 451
		StyleMutator.setWidth(this.domNode, layoutInfo.width);
		StyleMutator.setHeight(this.domNode, layoutInfo.height);
E
Erich Gamma 已提交
452

A
Alex Dima 已提交
453 454
		StyleMutator.setWidth(this.overflowGuardContainer, layoutInfo.width);
		StyleMutator.setHeight(this.overflowGuardContainer, layoutInfo.height);
E
Erich Gamma 已提交
455

A
Alex Dima 已提交
456 457
		StyleMutator.setWidth(this.linesContent, 1000000);
		StyleMutator.setHeight(this.linesContent, 1000000);
E
Erich Gamma 已提交
458

A
Alex Dima 已提交
459 460 461
		StyleMutator.setLeft(this.linesContentContainer, layoutInfo.contentLeft);
		StyleMutator.setWidth(this.linesContentContainer, layoutInfo.contentWidth);
		StyleMutator.setHeight(this.linesContentContainer, layoutInfo.contentHeight);
E
Erich Gamma 已提交
462

A
Alex Dima 已提交
463
		this.outgoingEventBus.emit(editorCommon.EventType.ViewLayoutChanged, layoutInfo);
E
Erich Gamma 已提交
464 465
		return false;
	}
A
Alex Dima 已提交
466
	public onConfigurationChanged(e: editorCommon.IConfigurationChangedEvent): boolean {
467 468
		if (e.viewInfo.editorClassName) {
			this.domNode.className = this._context.configuration.editor.viewInfo.editorClassName;
E
Erich Gamma 已提交
469
		}
470 471
		if (e.viewInfo.ariaLabel) {
			this.textArea.setAttribute('aria-label', this._context.configuration.editor.viewInfo.ariaLabel);
472
		}
E
Erich Gamma 已提交
473 474
		return false;
	}
A
Alex Dima 已提交
475
	public onScrollChanged(e:editorCommon.IScrollEvent): boolean {
A
Alex Dima 已提交
476
		this.outgoingEventBus.emit('scroll', e);
477
		return false;
E
Erich Gamma 已提交
478 479
	}
	public onViewFocusChanged(isFocused:boolean): boolean {
A
Alex Dima 已提交
480
		dom.toggleClass(this.domNode, 'focused', isFocused);
E
Erich Gamma 已提交
481 482
		if (isFocused) {
			this._editorTextFocusContextKey.set(true);
A
Alex Dima 已提交
483
			this.outgoingEventBus.emit(editorCommon.EventType.ViewFocusGained, {});
E
Erich Gamma 已提交
484 485
		} else {
			this._editorTextFocusContextKey.reset();
A
Alex Dima 已提交
486
			this.outgoingEventBus.emit(editorCommon.EventType.ViewFocusLost, {});
E
Erich Gamma 已提交
487 488 489
		}
		return false;
	}
490 491 492 493 494 495 496 497 498 499 500 501 502

	public onCursorRevealRange(e: editorCommon.IViewRevealRangeEvent): boolean {
		return e.revealCursor ? this.revealCursor() : false;
	}

	public onCursorScrollRequest(e: editorCommon.ICursorScrollRequestEvent): boolean {
		return e.revealCursor ? this.revealCursor() : false;
	}

	private revealCursor(): boolean {
		this.triggerCursorHandler('revealCursor', editorCommon.Handler.CursorMove, { to: editorCommon.CursorMovePosition.ViewPortIfOutside });
		return false;
	}
E
Erich Gamma 已提交
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
	// --- end event handlers

	public dispose(): void {
		this._isDisposed = true;
		if (this.handleAccumulatedModelEventsTimeout !== -1) {
			clearTimeout(this.handleAccumulatedModelEventsTimeout);
			this.handleAccumulatedModelEventsTimeout = -1;
		}
		if (this._renderAnimationFrame !== null) {
			this._renderAnimationFrame.dispose();
			this._renderAnimationFrame = null;
		}
		this.accumulatedModelEvents = [];

		this.eventDispatcher.removeEventHandler(this);
		this.outgoingEventBus.dispose();
A
Alex Dima 已提交
519
		this.listenersToRemove = dispose(this.listenersToRemove);
J
Joao Moreno 已提交
520
		this.listenersToDispose = dispose(this.listenersToDispose);
E
Erich Gamma 已提交
521 522 523 524 525 526 527 528 529 530 531 532 533

		this.keyboardHandler.dispose();
		this.pointerHandler.dispose();

		this.viewLines.dispose();

		// Destroy IViewPart second
		for (var i = 0, len = this.viewParts.length; i < len; i++) {
			this.viewParts[i].dispose();
		}
		this.viewParts = [];

		this.layoutProvider.dispose();
534
		this._editorTextFocusContextKey.reset();
E
Erich Gamma 已提交
535 536 537 538
	}

	// --- begin Code Editor APIs

A
Alex Dima 已提交
539 540
	private codeEditorHelper:editorBrowser.ICodeEditorHelper;
	public getCodeEditorHelper(): editorBrowser.ICodeEditorHelper {
E
Erich Gamma 已提交
541 542
		if (!this.codeEditorHelper) {
			this.codeEditorHelper = {
543
				getScrollWidth: () => {
E
Erich Gamma 已提交
544
					if (this._isDisposed) {
545
						throw new Error('ViewImpl.codeEditorHelper.getScrollWidth: View is disposed');
E
Erich Gamma 已提交
546
					}
547
					return this.layoutProvider.getScrollWidth();
E
Erich Gamma 已提交
548 549 550 551 552 553 554
				},
				getScrollLeft: () => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.getScrollLeft: View is disposed');
					}
					return this.layoutProvider.getScrollLeft();
				},
555

E
Erich Gamma 已提交
556 557 558 559 560 561
				getScrollHeight: () => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.getScrollHeight: View is disposed');
					}
					return this.layoutProvider.getScrollHeight();
				},
562
				getScrollTop: () => {
E
Erich Gamma 已提交
563
					if (this._isDisposed) {
564
						throw new Error('ViewImpl.codeEditorHelper.getScrollTop: View is disposed');
E
Erich Gamma 已提交
565
					}
566
					return this.layoutProvider.getScrollTop();
E
Erich Gamma 已提交
567
				},
568 569 570 571 572 573 574 575

				setScrollPosition: (position:editorCommon.INewScrollPosition) => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.setScrollPosition: View is disposed');
					}
					this.layoutProvider.setScrollPosition(position);
				},

E
Erich Gamma 已提交
576 577 578 579
				getVerticalOffsetForPosition: (modelLineNumber:number, modelColumn:number) => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.getVerticalOffsetForPosition: View is disposed');
					}
580
					var modelPosition = this._context.model.validateModelPosition({
E
Erich Gamma 已提交
581 582 583
						lineNumber: modelLineNumber,
						column: modelColumn
					});
584
					var viewPosition = this._context.model.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column);
E
Erich Gamma 已提交
585 586 587 588 589 590 591 592 593 594 595 596
					return this.layoutProvider.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
				},
				delegateVerticalScrollbarMouseDown: (browserEvent: MouseEvent) => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.delegateVerticalScrollbarMouseDown: View is disposed');
					}
					this.layoutProvider.delegateVerticalScrollbarMouseDown(browserEvent);
				},
				getOffsetForColumn: (modelLineNumber: number, modelColumn: number) => {
					if (this._isDisposed) {
						throw new Error('ViewImpl.codeEditorHelper.getOffsetForColumn: View is disposed');
					}
597
					var modelPosition = this._context.model.validateModelPosition({
E
Erich Gamma 已提交
598 599 600
						lineNumber: modelLineNumber,
						column: modelColumn
					});
601
					var viewPosition = this._context.model.convertModelPositionToViewPosition(modelPosition.lineNumber, modelPosition.column);
E
Erich Gamma 已提交
602
					this._flushAccumulatedAndRenderNow();
A
Alex Dima 已提交
603
					var visibleRanges = this.viewLines.visibleRangesForRange2(new Range(viewPosition.lineNumber, viewPosition.column, viewPosition.lineNumber, viewPosition.column), 0);
E
Erich Gamma 已提交
604 605 606 607 608 609 610 611 612 613
					if (!visibleRanges) {
						return -1;
					}
					return visibleRanges[0].left;
				}
			};
		}
		return this.codeEditorHelper;
	}

614
	public getCenteredRangeInViewport(): Range {
E
Erich Gamma 已提交
615 616 617 618
		if (this._isDisposed) {
			throw new Error('ViewImpl.getCenteredRangeInViewport: View is disposed');
		}
		var viewLineNumber = this.layoutProvider.getCenteredViewLineNumberInViewport();
619
		var viewModel = this._context.model;
E
Erich Gamma 已提交
620 621 622 623
		var currentCenteredViewRange = new Range(viewLineNumber, 1, viewLineNumber, viewModel.getLineMaxColumn(viewLineNumber));
		return viewModel.convertViewRangeToModelRange(currentCenteredViewRange);
	}

624
	public getCompletelyVisibleLinesRangeInViewport(): Range {
625
		if (this._isDisposed) {
626
			throw new Error('ViewImpl.getVisibleRangeInViewportExcludingPartialRenderedLines: View is disposed');
627
		}
628 629
		let completelyVisibleLinesRange = this.layoutProvider.getLinesViewportData().completelyVisibleLinesRange;
		return this._context.model.convertViewRangeToModelRange(completelyVisibleLinesRange);
630 631
	}

E
Erich Gamma 已提交
632 633 634 635
//	public getLineInfoProvider():view.ILineInfoProvider {
//		return this.viewLines;
//	}

A
Alex Dima 已提交
636
	public getInternalEventBus(): IEventEmitter {
E
Erich Gamma 已提交
637 638 639 640 641 642
		if (this._isDisposed) {
			throw new Error('ViewImpl.getInternalEventBus: View is disposed');
		}
		return this.outgoingEventBus;
	}

A
Alex Dima 已提交
643
	public saveState(): editorCommon.IViewState {
E
Erich Gamma 已提交
644 645 646 647 648 649
		if (this._isDisposed) {
			throw new Error('ViewImpl.saveState: View is disposed');
		}
		return this.layoutProvider.saveState();
	}

A
Alex Dima 已提交
650
	public restoreState(state: editorCommon.IViewState): void {
E
Erich Gamma 已提交
651 652 653 654 655 656 657 658 659 660 661
		if (this._isDisposed) {
			throw new Error('ViewImpl.restoreState: View is disposed');
		}
		this._flushAnyAccumulatedEvents();
		return this.layoutProvider.restoreState(state);
	}

	public focus(): void {
		if (this._isDisposed) {
			throw new Error('ViewImpl.focus: View is disposed');
		}
662
		this.keyboardHandler.focusTextArea();
E
Erich Gamma 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679

		// IE does not trigger the focus event immediately, so we must help it a little bit
		this._setHasFocus(true);
	}

	public isFocused(): boolean {
		if (this._isDisposed) {
			throw new Error('ViewImpl.isFocused: View is disposed');
		}
		return this.hasFocus;
	}

	public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): OverviewRuler {
		if (this._isDisposed) {
			throw new Error('ViewImpl.createOverviewRuler: View is disposed');
		}
		return new OverviewRuler(
680
				this._context, cssClassName, this.layoutProvider.getScrollHeight(), minimumHeight, maximumHeight,
E
Erich Gamma 已提交
681 682 683 684
				(lineNumber:number) => this.layoutProvider.getVerticalOffsetForLineNumber(lineNumber)
		);
	}

A
Alex Dima 已提交
685
	public change(callback: (changeAccessor: editorBrowser.IViewZoneChangeAccessor) => any): boolean {
E
Erich Gamma 已提交
686 687 688 689 690 691 692
		if (this._isDisposed) {
			throw new Error('ViewImpl.change: View is disposed');
		}
		var zonesHaveChanged = false;
		this._renderOnce(() => {
			// Handle events to avoid "adjusting" newly inserted view zones
			this._flushAnyAccumulatedEvents();
A
Alex Dima 已提交
693 694
			var changeAccessor:editorBrowser.IViewZoneChangeAccessor = {
				addZone: (zone:editorBrowser.IViewZone): number => {
E
Erich Gamma 已提交
695 696 697 698 699 700 701 702 703 704 705
					zonesHaveChanged = true;
					return this.viewZones.addZone(zone);
				},
				removeZone: (id:number): void => {
					zonesHaveChanged = this.viewZones.removeZone(id) || zonesHaveChanged;
				},
				layoutZone: (id: number): void => {
					zonesHaveChanged = this.viewZones.layoutZone(id) || zonesHaveChanged;
				}
			};

A
Alex Dima 已提交
706
			var r: any = safeInvoke1Arg(callback, changeAccessor);
E
Erich Gamma 已提交
707 708 709 710 711 712

			// Invalidate changeAccessor
			changeAccessor.addZone = null;
			changeAccessor.removeZone = null;

			if (zonesHaveChanged) {
713
				this._context.privateViewEventBus.emit(editorCommon.EventType.ViewZonesChanged, null);
E
Erich Gamma 已提交
714 715 716 717 718 719 720
			}

			return r;
		});
		return zonesHaveChanged;
	}

A
Alex Dima 已提交
721
	public getWhitespaces(): editorCommon.IEditorWhitespace[]{
E
Erich Gamma 已提交
722 723 724 725 726 727
		if (this._isDisposed) {
			throw new Error('ViewImpl.getWhitespaces: View is disposed');
		}
		return this.layoutProvider.getWhitespaces();
	}

A
Alex Dima 已提交
728
	public addContentWidget(widgetData: editorBrowser.IContentWidgetData): void {
E
Erich Gamma 已提交
729 730 731 732 733 734 735 736 737
		if (this._isDisposed) {
			throw new Error('ViewImpl.addContentWidget: View is disposed');
		}
		this._renderOnce(() => {
			this.contentWidgets.addWidget(widgetData.widget);
			this.layoutContentWidget(widgetData);
		});
	}

A
Alex Dima 已提交
738
	public layoutContentWidget(widgetData: editorBrowser.IContentWidgetData): void {
E
Erich Gamma 已提交
739 740 741
		if (this._isDisposed) {
			throw new Error('ViewImpl.layoutContentWidget: View is disposed');
		}
742

743 744 745 746 747
		this._renderOnce(() => {
			let newPosition = widgetData.position ? widgetData.position.position : null;
			let newPreference = widgetData.position ? widgetData.position.preference : null;
			this.contentWidgets.setWidgetPosition(widgetData.widget, newPosition, newPreference);
		});
E
Erich Gamma 已提交
748 749
	}

A
Alex Dima 已提交
750
	public removeContentWidget(widgetData: editorBrowser.IContentWidgetData): void {
E
Erich Gamma 已提交
751 752 753 754 755 756 757 758
		if (this._isDisposed) {
			throw new Error('ViewImpl.removeContentWidget: View is disposed');
		}
		this._renderOnce(() => {
			this.contentWidgets.removeWidget(widgetData.widget);
		});
	}

A
Alex Dima 已提交
759
	public addOverlayWidget(widgetData: editorBrowser.IOverlayWidgetData): void {
E
Erich Gamma 已提交
760 761 762 763 764 765 766 767 768
		if (this._isDisposed) {
			throw new Error('ViewImpl.addOverlayWidget: View is disposed');
		}
		this._renderOnce(() => {
			this.overlayWidgets.addWidget(widgetData.widget);
			this.layoutOverlayWidget(widgetData);
		});
	}

A
Alex Dima 已提交
769
	public layoutOverlayWidget(widgetData: editorBrowser.IOverlayWidgetData): void {
E
Erich Gamma 已提交
770 771 772
		if (this._isDisposed) {
			throw new Error('ViewImpl.layoutOverlayWidget: View is disposed');
		}
773 774 775 776 777 778

		let newPreference = widgetData.position ? widgetData.position.preference : null;
		let shouldRender = this.overlayWidgets.setWidgetPosition(widgetData.widget, newPreference);
		if (shouldRender) {
			this._scheduleRender();
		}
E
Erich Gamma 已提交
779 780
	}

A
Alex Dima 已提交
781
	public removeOverlayWidget(widgetData: editorBrowser.IOverlayWidgetData): void {
E
Erich Gamma 已提交
782 783 784 785 786 787 788 789
		if (this._isDisposed) {
			throw new Error('ViewImpl.removeOverlayWidget: View is disposed');
		}
		this._renderOnce(() => {
			this.overlayWidgets.removeWidget(widgetData.widget);
		});
	}

790
	public render(now:boolean, everything:boolean): void {
E
Erich Gamma 已提交
791 792 793
		if (this._isDisposed) {
			throw new Error('ViewImpl.render: View is disposed');
		}
794 795 796 797
		if (everything) {
			// Force a render with a layout event
			this.layoutProvider.emitLayoutChangedEvent();
		}
798 799 800
		if (now) {
			this._flushAccumulatedAndRenderNow();
		}
E
Erich Gamma 已提交
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
	}

	public renderOnce(callback: () => any): any {
		if (this._isDisposed) {
			throw new Error('ViewImpl.renderOnce: View is disposed');
		}
		return this._renderOnce(callback);
	}

	// --- end Code Editor APIs

	private _renderOnce(callback: () => any): any {
		if (this._isDisposed) {
			throw new Error('ViewImpl._renderOnce: View is disposed');
		}
		return this.outgoingEventBus.deferredEmit(() => {
A
Alex Dima 已提交
817 818
			let r = safeInvokeNoArg(callback);
			this._scheduleRender();
E
Erich Gamma 已提交
819 820 821 822 823 824 825 826 827
			return r;
		});
	}

	private _scheduleRender(): void {
		if (this._isDisposed) {
			throw new Error('ViewImpl._scheduleRender: View is disposed');
		}
		if (this._renderAnimationFrame === null) {
A
Alex Dima 已提交
828
			this._renderAnimationFrame = dom.runAtThisOrScheduleAtNextAnimationFrame(this._onRenderScheduled.bind(this), 100);
E
Erich Gamma 已提交
829 830 831 832 833 834 835 836 837
		}
	}

	private _onRenderScheduled(): void {
		this._renderAnimationFrame = null;
		this._flushAccumulatedAndRenderNow();
	}

	private _renderNow(): void {
A
Alex Dima 已提交
838
		safeInvokeNoArg(() => this._actualRender());
E
Erich Gamma 已提交
839 840
	}

841
	private createRenderingContext(linesViewportData:ViewLinesViewportData): IRenderingContext {
E
Erich Gamma 已提交
842 843 844 845 846

		var vInfo = this.layoutProvider.getCurrentViewport();

		var deltaTop = linesViewportData.visibleRangesDeltaTop;

847
		var r:IRenderingContext = {
E
Erich Gamma 已提交
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
			linesViewportData: linesViewportData,
			scrollWidth: this.layoutProvider.getScrollWidth(),
			scrollHeight: this.layoutProvider.getScrollHeight(),

			visibleRange: linesViewportData.visibleRange,
			bigNumbersDelta: linesViewportData.bigNumbersDelta,

			viewportWidth: vInfo.width,
			viewportHeight: vInfo.height,
			viewportLeft: vInfo.left,
			viewportTop: vInfo.top,

			getScrolledTopFromAbsoluteTop: (absoluteTop:number) => {
				return this.layoutProvider.getScrolledTopFromAbsoluteTop(absoluteTop);
			},

			getViewportVerticalOffsetForLineNumber: (lineNumber:number) => {
				var verticalOffset = this.layoutProvider.getVerticalOffsetForLineNumber(lineNumber);
				var scrolledTop = this.layoutProvider.getScrolledTopFromAbsoluteTop(verticalOffset);
				return scrolledTop;
			},

			getDecorationsInViewport: () => linesViewportData.getDecorationsInViewport(),

A
Alex Dima 已提交
872
			linesVisibleRangesForRange: (range:editorCommon.IRange, includeNewLines:boolean) => {
E
Erich Gamma 已提交
873 874 875
				return this.viewLines.linesVisibleRangesForRange(range, includeNewLines);
			},

A
Alex Dima 已提交
876
			visibleRangeForPosition: (position:editorCommon.IPosition) => {
A
Alex Dima 已提交
877
				var visibleRanges = this.viewLines.visibleRangesForRange2(new Range(position.lineNumber, position.column, position.lineNumber, position.column), deltaTop);
E
Erich Gamma 已提交
878 879 880 881 882 883 884 885 886 887 888 889 890
				if (!visibleRanges) {
					return null;
				}
				return visibleRanges[0];
			},

			lineIsVisible: (lineNumber:number) => {
				return linesViewportData.visibleRange.startLineNumber <= lineNumber && lineNumber <= linesViewportData.visibleRange.endLineNumber;
			}
		};
		return r;
	}

891 892 893 894 895 896 897 898 899 900 901
	private _getViewPartsToRender(): ViewPart[] {
		let result:ViewPart[] = [];
		for (let i = 0, len = this.viewParts.length; i < len; i++) {
			let viewPart = this.viewParts[i];
			if (viewPart.shouldRender()) {
				result.push(viewPart);
			}
		}
		return result;
	}

A
Alex Dima 已提交
902
	private _actualRender(): void {
A
Alex Dima 已提交
903
		if (!dom.isInDOM(this.domNode)) {
E
Erich Gamma 已提交
904 905
			return;
		}
A
Alex Dima 已提交
906
		let t = timer.start(timer.Topic.EDITOR, 'View.render');
E
Erich Gamma 已提交
907

908
		let viewPartsToRender = this._getViewPartsToRender();
E
Erich Gamma 已提交
909

A
Alex Dima 已提交
910 911
		if (!this.viewLines.shouldRender() && viewPartsToRender.length === 0) {
			// Nothing to render
912
			this.keyboardHandler.writeToTextArea();
A
Alex Dima 已提交
913 914 915
			t.stop();
			return;
		}
E
Erich Gamma 已提交
916

A
Alex Dima 已提交
917
		let linesViewportData = this.layoutProvider.getLinesViewportData();
E
Erich Gamma 已提交
918

A
Alex Dima 已提交
919
		if (this.viewLines.shouldRender()) {
920 921 922
			this.viewLines.renderText(linesViewportData, () => {
				this.keyboardHandler.writeToTextArea();
			});
A
Alex Dima 已提交
923
			this.viewLines.onDidRender();
924 925 926

			// Rendering of viewLines might cause scroll events to occur, so collect view parts to render again
			viewPartsToRender = this._getViewPartsToRender();
927 928
		} else {
			this.keyboardHandler.writeToTextArea();
A
Alex Dima 已提交
929
		}
E
Erich Gamma 已提交
930

A
Alex Dima 已提交
931
		let renderingContext = this.createRenderingContext(linesViewportData);
A
Alex Dima 已提交
932

A
Alex Dima 已提交
933 934 935 936 937
		// Render the rest of the parts
		for (let i = 0, len = viewPartsToRender.length; i < len; i++) {
			let viewPart = viewPartsToRender[i];
			viewPart.prepareRender(renderingContext);
		}
A
Alex Dima 已提交
938

A
Alex Dima 已提交
939 940 941 942
		for (let i = 0, len = viewPartsToRender.length; i < len; i++) {
			let viewPart = viewPartsToRender[i];
			viewPart.render(renderingContext);
			viewPart.onDidRender();
E
Erich Gamma 已提交
943 944
		}

945 946 947
		// Render the scrollbar
		this.layoutProvider.renderScrollbar();

E
Erich Gamma 已提交
948 949 950 951 952 953
		t.stop();
	}

	private _setHasFocus(newHasFocus:boolean): void {
		if (this.hasFocus !== newHasFocus) {
			this.hasFocus = newHasFocus;
954
			this._context.privateViewEventBus.emit(editorCommon.EventType.ViewFocusChanged, this.hasFocus);
E
Erich Gamma 已提交
955 956 957 958
		}
	}
}

A
Alex Dima 已提交
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
function safeInvokeNoArg(func:Function): any {
	try {
		return func();
	} catch(e) {
		onUnexpectedError(e);
	}
}

function safeInvoke1Arg(func:Function, arg1:any): any {
	try {
		return func(arg1);
	} catch(e) {
		onUnexpectedError(e);
	}
}