Initial VS Code 1.19 source merge (#571)

* Initial 1.19 xcopy

* Fix yarn build

* Fix numerous build breaks

* Next batch of build break fixes

* More build break fixes

* Runtime breaks

* Additional post merge fixes

* Fix windows setup file

* Fix test failures.

* Update license header blocks to refer to source eula
This commit is contained in:
Karl Burtram
2018-01-28 23:37:17 -08:00
committed by GitHub
parent 9a1ac20710
commit 251ae01c3e
8009 changed files with 93378 additions and 35634 deletions

View File

@@ -20,21 +20,19 @@ import { Selection, ISelection } from 'vs/editor/common/core/selection';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl';
import { hash } from 'vs/base/common/hash';
import { EditorModeContext } from 'vs/editor/common/modes/editorModeContext';
import {
IModelContentChangedEvent, IModelDecorationsChangedEvent,
IModelLanguageChangedEvent, IModelOptionsChangedEvent, TextModelEventType, IModelLanguageConfigurationChangedEvent
} from 'vs/editor/common/model/textModelEvents';
import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents';
import * as editorOptions from 'vs/editor/common/config/editorOptions';
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer';
import * as modes from 'vs/editor/common/modes';
import { Schemas } from 'vs/base/common/network';
let EDITOR_ID = 0;
export abstract class CommonCodeEditor extends Disposable implements editorCommon.ICommonCodeEditor {
export abstract class CommonCodeEditor extends Disposable {
private readonly _onDidDispose: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidDispose: Event<void> = this._onDidDispose.event;
@@ -160,10 +158,6 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
return editorCommon.EditorType.ICodeEditor;
}
public destroy(): void {
this.dispose();
}
public dispose(): void {
let keys = Object.keys(this._contributions);
for (let i = 0, len = keys.length; i < len; i++) {
@@ -261,6 +255,42 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
return this.viewModel.getCenteredRangeInViewport();
}
public getWhitespaces(): IEditorWhitespace[] {
if (!this.hasView) {
return [];
}
return this.viewModel.viewLayout.getWhitespaces();
}
protected _getVerticalOffsetForPosition(modelLineNumber: number, modelColumn: number): number {
let modelPosition = this.model.validatePosition({
lineNumber: modelLineNumber,
column: modelColumn
});
let viewPosition = this.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);
}
public getTopForLineNumber(lineNumber: number): number {
if (!this.hasView) {
return -1;
}
return this._getVerticalOffsetForPosition(lineNumber, 1);
}
public getTopForPosition(lineNumber: number, column: number): number {
if (!this.hasView) {
return -1;
}
return this._getVerticalOffsetForPosition(lineNumber, column);
}
public setHiddenAreas(ranges: IRange[]): void {
if (this.viewModel) {
this.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)));
}
}
public getVisibleColumnFromPosition(rawPosition: IPosition): number {
if (!this.model) {
return rawPosition.column;
@@ -713,7 +743,7 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
const action = this.getAction(handlerId);
if (action) {
TPromise.as(action.run()).done(null, onUnexpectedError);
TPromise.as(action.run()).then(null, onUnexpectedError);
return;
}
@@ -721,17 +751,15 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
return;
}
const command = CommonEditorRegistry.getEditorCommand(handlerId);
if (command) {
payload = payload || {};
payload.source = source;
TPromise.as(command.runEditorCommand(null, this, payload)).done(null, onUnexpectedError);
if (this._triggerEditorCommand(source, handlerId, payload)) {
return;
}
this.cursor.trigger(source, handlerId, payload);
}
protected abstract _triggerEditorCommand(source: string, handlerId: string, payload: any): boolean;
public _getCursors(): ICursors {
return this.cursor;
}
@@ -910,43 +938,16 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
this.viewModel = new ViewModel(this.id, this._configuration, this.model, (callback) => this._scheduleAtNextAnimationFrame(callback));
this.listenersToRemove.push(this.model.addBulkListener((events) => {
for (let i = 0, len = events.length; i < len; i++) {
let eventType = events[i].type;
let e = events[i].data;
switch (eventType) {
case TextModelEventType.ModelDecorationsChanged:
this._onDidChangeModelDecorations.fire(e);
break;
case TextModelEventType.ModelLanguageChanged:
this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language);
this._onDidChangeModelLanguage.fire(e);
break;
case TextModelEventType.ModelLanguageConfigurationChanged:
this._onDidChangeModelLanguageConfiguration.fire(e);
break;
case TextModelEventType.ModelContentChanged:
this._onDidChangeModelContent.fire(e);
break;
case TextModelEventType.ModelOptionsChanged:
this._onDidChangeModelOptions.fire(e);
break;
case TextModelEventType.ModelDispose:
// Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model
this.setModel(null);
break;
default:
// console.warn("Unhandled model event: ", e);
}
}
this.listenersToRemove.push(this.model.onDidChangeDecorations((e) => this._onDidChangeModelDecorations.fire(e)));
this.listenersToRemove.push(this.model.onDidChangeLanguage((e) => {
this.domElement.setAttribute('data-mode-id', this.model.getLanguageIdentifier().language);
this._onDidChangeModelLanguage.fire(e);
}));
this.listenersToRemove.push(this.model.onDidChangeLanguageConfiguration((e) => this._onDidChangeModelLanguageConfiguration.fire(e)));
this.listenersToRemove.push(this.model.onDidChangeContent((e) => this._onDidChangeModelContent.fire(e)));
this.listenersToRemove.push(this.model.onDidChangeOptions((e) => this._onDidChangeModelOptions.fire(e)));
// Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model
this.listenersToRemove.push(this.model.onWillDispose(() => this.setModel(null)));
this.cursor = new Cursor(
this._configuration,
@@ -1036,8 +1037,6 @@ export abstract class CommonCodeEditor extends Disposable implements editorCommo
class EditorContextKeysManager extends Disposable {
private _editor: CommonCodeEditor;
private _editorId: IContextKey<string>;
private _editorFocus: IContextKey<boolean>;
private _editorTextFocus: IContextKey<boolean>;
private _editorTabMovesFocus: IContextKey<boolean>;
@@ -1053,7 +1052,7 @@ class EditorContextKeysManager extends Disposable {
this._editor = editor;
this._editorId = contextKeyService.createKey('editorId', editor.getId());
contextKeyService.createKey('editorId', editor.getId());
this._editorFocus = EditorContextKeys.focus.bindTo(contextKeyService);
this._editorTextFocus = EditorContextKeys.textFocus.bindTo(contextKeyService);
this._editorTabMovesFocus = EditorContextKeys.tabMovesFocus.bindTo(contextKeyService);
@@ -1096,3 +1095,121 @@ class EditorContextKeysManager extends Disposable {
this._editorTextFocus.set(this._editor.isFocused());
}
}
export class EditorModeContext extends Disposable {
private _editor: CommonCodeEditor;
private _langId: IContextKey<string>;
private _hasCompletionItemProvider: IContextKey<boolean>;
private _hasCodeActionsProvider: IContextKey<boolean>;
private _hasCodeLensProvider: IContextKey<boolean>;
private _hasDefinitionProvider: IContextKey<boolean>;
private _hasImplementationProvider: IContextKey<boolean>;
private _hasTypeDefinitionProvider: IContextKey<boolean>;
private _hasHoverProvider: IContextKey<boolean>;
private _hasDocumentHighlightProvider: IContextKey<boolean>;
private _hasDocumentSymbolProvider: IContextKey<boolean>;
private _hasReferenceProvider: IContextKey<boolean>;
private _hasRenameProvider: IContextKey<boolean>;
private _hasDocumentFormattingProvider: IContextKey<boolean>;
private _hasDocumentSelectionFormattingProvider: IContextKey<boolean>;
private _hasSignatureHelpProvider: IContextKey<boolean>;
private _isInWalkThrough: IContextKey<boolean>;
constructor(
editor: CommonCodeEditor,
contextKeyService: IContextKeyService
) {
super();
this._editor = editor;
this._langId = EditorContextKeys.languageId.bindTo(contextKeyService);
this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService);
this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService);
this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService);
this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(contextKeyService);
this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(contextKeyService);
this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService);
this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(contextKeyService);
this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService);
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService);
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService);
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService);
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService);
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService);
const update = () => this._update();
// update when model/mode changes
this._register(editor.onDidChangeModel(update));
this._register(editor.onDidChangeModelLanguage(update));
// update when registries change
this._register(modes.SuggestRegistry.onDidChange(update));
this._register(modes.CodeActionProviderRegistry.onDidChange(update));
this._register(modes.CodeLensProviderRegistry.onDidChange(update));
this._register(modes.DefinitionProviderRegistry.onDidChange(update));
this._register(modes.ImplementationProviderRegistry.onDidChange(update));
this._register(modes.TypeDefinitionProviderRegistry.onDidChange(update));
this._register(modes.HoverProviderRegistry.onDidChange(update));
this._register(modes.DocumentHighlightProviderRegistry.onDidChange(update));
this._register(modes.DocumentSymbolProviderRegistry.onDidChange(update));
this._register(modes.ReferenceProviderRegistry.onDidChange(update));
this._register(modes.RenameProviderRegistry.onDidChange(update));
this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update));
this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update));
this._register(modes.SignatureHelpProviderRegistry.onDidChange(update));
update();
}
dispose() {
super.dispose();
}
reset() {
this._langId.reset();
this._hasCompletionItemProvider.reset();
this._hasCodeActionsProvider.reset();
this._hasCodeLensProvider.reset();
this._hasDefinitionProvider.reset();
this._hasImplementationProvider.reset();
this._hasTypeDefinitionProvider.reset();
this._hasHoverProvider.reset();
this._hasDocumentHighlightProvider.reset();
this._hasDocumentSymbolProvider.reset();
this._hasReferenceProvider.reset();
this._hasRenameProvider.reset();
this._hasDocumentFormattingProvider.reset();
this._hasDocumentSelectionFormattingProvider.reset();
this._hasSignatureHelpProvider.reset();
this._isInWalkThrough.reset();
}
private _update() {
const model = this._editor.getModel();
if (!model) {
this.reset();
return;
}
this._langId.set(model.getLanguageIdentifier().language);
this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model));
this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));
this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));
this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));
this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model));
this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));
this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));
this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));
this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));
this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));
this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
}
}

View File

@@ -31,7 +31,7 @@ export interface ITabFocus {
setTabFocusMode(tabFocusMode: boolean): void;
}
export const TabFocus: ITabFocus = new class {
export const TabFocus: ITabFocus = new class implements ITabFocus {
private _tabFocus: boolean = false;
private _onDidChangeTabFocus: Emitter<boolean> = new Emitter<boolean>();
@@ -203,9 +203,15 @@ const editorConfiguration: IConfigurationNode = {
},
'editor.lineNumbers': {
'type': 'string',
'enum': ['off', 'on', 'relative'],
'enum': ['off', 'on', 'relative', 'interval'],
'enumDescriptions': [
nls.localize('lineNumbers.off', "Line numbers are not rendered."),
nls.localize('lineNumbers.on', "Line numbers are rendered as absolute number."),
nls.localize('lineNumbers.relative', "Line numbers are rendered as distance in lines to cursor position."),
nls.localize('lineNumbers.interval', "Line numbers are rendered every 10 lines.")
],
'default': 'on',
'description': nls.localize('lineNumbers', "Controls the display of line numbers. Possible values are 'on', 'off', and 'relative'. 'relative' shows the line count from the current cursor position.")
'description': nls.localize('lineNumbers', "Controls the display of line numbers. Possible values are 'on', 'off', and 'relative'.")
},
'editor.rulers': {
'type': 'array',
@@ -224,13 +230,13 @@ const editorConfiguration: IConfigurationNode = {
'type': 'number',
'default': EDITOR_MODEL_DEFAULTS.tabSize,
'minimum': 1,
'description': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overriden based on the file contents when `editor.detectIndentation` is on."),
'description': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `editor.detectIndentation` is on."),
'errorMessage': nls.localize('tabSize.errorMessage', "Expected 'number'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
},
'editor.insertSpaces': {
'type': 'boolean',
'default': EDITOR_MODEL_DEFAULTS.insertSpaces,
'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overriden based on the file contents when `editor.detectIndentation` is on."),
'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overridden based on the file contents when `editor.detectIndentation` is on."),
'errorMessage': nls.localize('insertSpaces.errorMessage', "Expected 'boolean'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
},
'editor.detectIndentation': {
@@ -284,6 +290,11 @@ const editorConfiguration: IConfigurationNode = {
'default': EDITOR_DEFAULTS.contribInfo.find.autoFindInSelection,
'description': nls.localize('find.autoFindInSelection', "Controls if Find in Selection flag is turned on when multiple characters or lines of text are selected in the editor")
},
'editor.find.globalFindClipboard': {
'type': 'boolean',
'default': EDITOR_DEFAULTS.contribInfo.find.globalFindClipboard,
'description': nls.localize('find.globalFindClipboard', "Controls if the Find Widget should read or modify the shared find clipboard on macOS")
},
'editor.wordWrap': {
'type': 'string',
'enum': ['off', 'on', 'wordWrapColumn', 'bounded'],
@@ -603,6 +614,12 @@ const editorConfiguration: IConfigurationNode = {
'default': EDITOR_DEFAULTS.contribInfo.lightbulbEnabled,
'description': nls.localize('codeActions', "Enables the code action lightbulb")
},
'editor.selectionClipboard': {
'type': 'boolean',
'default': EDITOR_DEFAULTS.contribInfo.selectionClipboard,
'description': nls.localize('selectionClipboard', "Controls if the Linux primary clipboard should be supported."),
'included': platform.isLinux
},
'diffEditor.renderSideBySide': {
'type': 'boolean',
'default': true,
@@ -621,12 +638,4 @@ const editorConfiguration: IConfigurationNode = {
}
};
if (platform.isLinux) {
editorConfiguration['properties']['editor.selectionClipboard'] = {
'type': 'boolean',
'default': EDITOR_DEFAULTS.contribInfo.selectionClipboard,
'description': nls.localize('selectionClipboard', "Controls if the Linux primary clipboard should be supported.")
};
}
configurationRegistry.registerConfiguration(editorConfiguration);

View File

@@ -86,6 +86,11 @@ export interface IEditorFindOptions {
* Controls if Find in Selection flag is turned on when multiple lines of text are selected in the editor.
*/
autoFindInSelection: boolean;
/**
* @internal
* Controls if the Find Widget should read or modify the shared find clipboard on macOS
*/
globalFindClipboard: boolean;
}
/**
@@ -160,7 +165,7 @@ export interface IEditorOptions {
* Otherwise, line numbers will not be rendered.
* Defaults to true.
*/
lineNumbers?: 'on' | 'off' | 'relative' | ((lineNumber: number) => string);
lineNumbers?: 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);
/**
* Should the corresponding line be selected when clicking on the line number?
* Defaults to true.
@@ -739,6 +744,10 @@ export interface InternalEditorMinimapOptions {
export interface InternalEditorFindOptions {
readonly seedSearchStringFromSelection: boolean;
readonly autoFindInSelection: boolean;
/**
* @internal
*/
readonly globalFindClipboard: boolean;
}
export interface EditorWrappingInfo {
@@ -753,14 +762,21 @@ export interface EditorWrappingInfo {
readonly wordWrapBreakObtrusiveCharacters: string;
}
export const enum RenderLineNumbersType {
Off = 0,
On = 1,
Relative = 2,
Interval = 3,
Custom = 4
}
export interface InternalEditorViewOptions {
readonly extraEditorClassName: string;
readonly disableMonospaceOptimizations: boolean;
readonly rulers: number[];
readonly ariaLabel: string;
readonly renderLineNumbers: boolean;
readonly renderLineNumbers: RenderLineNumbersType;
readonly renderCustomLineNumbers: (lineNumber: number) => string;
readonly renderRelativeLineNumbers: boolean;
readonly selectOnLineNumbers: boolean;
readonly glyphMargin: boolean;
readonly revealHorizontalRightPadding: number;
@@ -1029,7 +1045,6 @@ export class InternalEditorOptions {
&& a.ariaLabel === b.ariaLabel
&& a.renderLineNumbers === b.renderLineNumbers
&& a.renderCustomLineNumbers === b.renderCustomLineNumbers
&& a.renderRelativeLineNumbers === b.renderRelativeLineNumbers
&& a.selectOnLineNumbers === b.selectOnLineNumbers
&& a.glyphMargin === b.glyphMargin
&& a.revealHorizontalRightPadding === b.revealHorizontalRightPadding
@@ -1106,6 +1121,7 @@ export class InternalEditorOptions {
return (
a.seedSearchStringFromSelection === b.seedSearchStringFromSelection
&& a.autoFindInSelection === b.autoFindInSelection
&& a.globalFindClipboard === b.globalFindClipboard
);
}
@@ -1544,7 +1560,8 @@ export class EditorOptionsValidator {
return {
seedSearchStringFromSelection: _boolean(opts.seedSearchStringFromSelection, defaults.seedSearchStringFromSelection),
autoFindInSelection: _boolean(opts.autoFindInSelection, defaults.autoFindInSelection)
autoFindInSelection: _boolean(opts.autoFindInSelection, defaults.autoFindInSelection),
globalFindClipboard: _boolean(opts.globalFindClipboard, defaults.globalFindClipboard)
};
}
@@ -1558,9 +1575,8 @@ export class EditorOptionsValidator {
rulers.sort();
}
let renderLineNumbers: boolean = defaults.renderLineNumbers;
let renderLineNumbers: RenderLineNumbersType = defaults.renderLineNumbers;
let renderCustomLineNumbers: (lineNumber: number) => string = defaults.renderCustomLineNumbers;
let renderRelativeLineNumbers: boolean = defaults.renderRelativeLineNumbers;
if (typeof opts.lineNumbers !== 'undefined') {
let lineNumbers = opts.lineNumbers;
@@ -1573,21 +1589,16 @@ export class EditorOptionsValidator {
}
if (typeof lineNumbers === 'function') {
renderLineNumbers = true;
renderLineNumbers = RenderLineNumbersType.Custom;
renderCustomLineNumbers = lineNumbers;
renderRelativeLineNumbers = false;
} else if (lineNumbers === 'interval') {
renderLineNumbers = RenderLineNumbersType.Interval;
} else if (lineNumbers === 'relative') {
renderLineNumbers = true;
renderCustomLineNumbers = null;
renderRelativeLineNumbers = true;
renderLineNumbers = RenderLineNumbersType.Relative;
} else if (lineNumbers === 'on') {
renderLineNumbers = true;
renderCustomLineNumbers = null;
renderRelativeLineNumbers = false;
renderLineNumbers = RenderLineNumbersType.On;
} else {
renderLineNumbers = false;
renderCustomLineNumbers = null;
renderRelativeLineNumbers = false;
renderLineNumbers = RenderLineNumbersType.Off;
}
}
@@ -1627,7 +1638,6 @@ export class EditorOptionsValidator {
ariaLabel: _string(opts.ariaLabel, defaults.ariaLabel),
renderLineNumbers: renderLineNumbers,
renderCustomLineNumbers: renderCustomLineNumbers,
renderRelativeLineNumbers: renderRelativeLineNumbers,
selectOnLineNumbers: _boolean(opts.selectOnLineNumbers, defaults.selectOnLineNumbers),
glyphMargin: _boolean(opts.glyphMargin, defaults.glyphMargin),
revealHorizontalRightPadding: _clampedInt(opts.revealHorizontalRightPadding, defaults.revealHorizontalRightPadding, 0, 1000),
@@ -1730,7 +1740,6 @@ export class InternalEditorOptionsFactory {
ariaLabel: (accessibilityIsOff ? nls.localize('accessibilityOffAriaLabel', "The editor is not accessible at this time. Press Alt+F1 for options.") : opts.viewInfo.ariaLabel),
renderLineNumbers: opts.viewInfo.renderLineNumbers,
renderCustomLineNumbers: opts.viewInfo.renderCustomLineNumbers,
renderRelativeLineNumbers: opts.viewInfo.renderRelativeLineNumbers,
selectOnLineNumbers: opts.viewInfo.selectOnLineNumbers,
glyphMargin: opts.viewInfo.glyphMargin,
revealHorizontalRightPadding: opts.viewInfo.revealHorizontalRightPadding,
@@ -1822,7 +1831,7 @@ export class InternalEditorOptionsFactory {
outerHeight: env.outerHeight,
showGlyphMargin: opts.viewInfo.glyphMargin,
lineHeight: env.fontInfo.lineHeight,
showLineNumbers: opts.viewInfo.renderLineNumbers,
showLineNumbers: (opts.viewInfo.renderLineNumbers !== RenderLineNumbersType.Off),
lineNumbersMinChars: opts.lineNumbersMinChars,
lineNumbersDigitCount: env.lineNumbersDigitCount,
lineDecorationsWidth: lineDecorationsWidth,
@@ -2152,9 +2161,8 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
disableMonospaceOptimizations: false,
rulers: [],
ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"),
renderLineNumbers: true,
renderLineNumbers: RenderLineNumbersType.On,
renderCustomLineNumbers: null,
renderRelativeLineNumbers: false,
selectOnLineNumbers: true,
glyphMargin: true,
revealHorizontalRightPadding: 30,
@@ -2223,7 +2231,8 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = {
matchBrackets: true,
find: {
seedSearchStringFromSelection: true,
autoFindInSelection: false
autoFindInSelection: false,
globalFindClipboard: true
},
colorDecorators: true,
lightbulbEnabled: true

View File

@@ -12,7 +12,7 @@ export interface IEditorZoom {
setZoomLevel(zoomLevel: number): void;
}
export const EditorZoom: IEditorZoom = new class {
export const EditorZoom: IEditorZoom = new class implements IEditorZoom {
private _zoomLevel: number = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
import { CursorColumns, CursorConfiguration, EditOperationResult, CursorContext, CursorState, RevealTarget, IColumnSelectData, ICursors, EditOperationType } from 'vs/editor/common/controller/cursorCommon';
import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations';
import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations';
import { TextModelEventType, ModelRawContentChangedEvent, RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents';
import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents';
import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
import * as viewEvents from 'vs/editor/common/view/viewEvents';
@@ -113,28 +113,12 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this._columnSelectData = null;
this._prevEditOperationType = EditOperationType.Other;
this._register(this._model.addBulkListener((events) => {
this._register(this._model.onDidChangeRawContent((e) => {
if (this._isHandling) {
return;
}
let hadContentChange = false;
let hadFlushEvent = false;
for (let i = 0, len = events.length; i < len; i++) {
const event = events[i];
const eventType = event.type;
if (eventType === TextModelEventType.ModelRawContentChanged2) {
hadContentChange = true;
const rawChangeEvent = <ModelRawContentChangedEvent>event.data;
hadFlushEvent = hadFlushEvent || rawChangeEvent.containsEvent(RawContentChangedType.Flush);
}
}
if (!hadContentChange) {
return;
}
let hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);
this._onModelContentChanged(hadFlushEvent);
}));

View File

@@ -82,7 +82,9 @@ export class CursorConfiguration {
public readonly autoClosingPairsOpen: CharacterMap;
public readonly autoClosingPairsClose: CharacterMap;
public readonly surroundingPairs: CharacterMap;
public readonly electricChars: { [key: string]: boolean; };
private readonly _languageIdentifier: LanguageIdentifier;
private _electricChars: { [key: string]: boolean; };
public static shouldRecreate(e: IConfigurationChangedEvent): boolean {
return (
@@ -102,6 +104,8 @@ export class CursorConfiguration {
modelOptions: TextModelResolvedOptions,
configuration: IConfiguration
) {
this._languageIdentifier = languageIdentifier;
let c = configuration.editor;
this.readOnly = c.readOnly;
@@ -119,14 +123,7 @@ export class CursorConfiguration {
this.autoClosingPairsOpen = {};
this.autoClosingPairsClose = {};
this.surroundingPairs = {};
this.electricChars = {};
let electricChars = CursorConfiguration._getElectricCharacters(languageIdentifier);
if (electricChars) {
for (let i = 0; i < electricChars.length; i++) {
this.electricChars[electricChars[i]] = true;
}
}
this._electricChars = null;
let autoClosingPairs = CursorConfiguration._getAutoClosingPairs(languageIdentifier);
if (autoClosingPairs) {
@@ -144,6 +141,19 @@ export class CursorConfiguration {
}
}
public get electricChars() {
if (!this._electricChars) {
this._electricChars = {};
let electricChars = CursorConfiguration._getElectricCharacters(this._languageIdentifier);
if (electricChars) {
for (let i = 0; i < electricChars.length; i++) {
this._electricChars[electricChars[i]] = true;
}
}
}
return this._electricChars;
}
public normalizeIndentation(str: string): string {
return TextModel.normalizeIndentation(str, this.tabSize, this.insertSpaces);
}
@@ -335,11 +345,6 @@ export class CursorContext {
return this.viewModel.getCompletelyVisibleViewRangeAtScrollTop(scrollTop);
}
public getCompletelyVisibleModelRangeAtScrollTop(scrollTop: number): Range {
const viewRange = this.viewModel.getCompletelyVisibleViewRangeAtScrollTop(scrollTop);
return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
}
public getVerticalOffsetForViewLine(viewLineNumber: number): number {
return this.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewLineNumber);
}

View File

@@ -670,7 +670,7 @@ export namespace CursorMove {
select?: boolean;
by?: string;
value?: number;
};
}
export function parse(args: RawArguments): ParsedArguments {
if (!args.to) {
@@ -753,7 +753,7 @@ export namespace CursorMove {
unit: Unit;
select: boolean;
value: number;
};
}
export const enum Direction {
Left,
@@ -772,7 +772,7 @@ export namespace CursorMove {
ViewPortBottom,
ViewPortIfOutside,
};
}
export const enum Unit {
None,
@@ -780,6 +780,6 @@ export namespace CursorMove {
WrappedLine,
Character,
HalfLine,
};
}
}

View File

@@ -13,7 +13,7 @@ import * as strings from 'vs/base/common/strings';
import { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';
import { Selection } from 'vs/editor/common/core/selection';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { IndentAction } from 'vs/editor/common/modes/languageConfiguration';
import { IndentAction, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand';
import { IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter';
import { getMapForWordSeparators, WordCharacterClass } from 'vs/editor/common/controller/wordCharacterClassifier';
@@ -144,10 +144,10 @@ export class TypeOperations {
}
private static _goodIndentForLine(config: CursorConfiguration, model: ITokenizedModel, lineNumber: number): string {
let action;
let indentation;
let expectedIndentAction = LanguageConfigurationRegistry.getInheritIndentForLine(model, lineNumber, false);
let action: IndentAction | EnterAction;
let indentation: string;
let expectedIndentAction = config.autoIndent ? LanguageConfigurationRegistry.getInheritIndentForLine(model, lineNumber, false) : null;
if (expectedIndentAction) {
action = expectedIndentAction.action;
indentation = expectedIndentAction.indentation;

View File

@@ -1,73 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as strings from 'vs/base/common/strings';
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
export const enum CodeEditorStateFlag {
Value = 1,
Selection = 2,
Position = 4,
Scroll = 8
}
export class EditorState {
private readonly flags: number;
private readonly position: Position;
private readonly selection: Range;
private readonly modelVersionId: string;
private readonly scrollLeft: number;
private readonly scrollTop: number;
constructor(editor: ICommonCodeEditor, flags: number) {
this.flags = flags;
if ((this.flags & CodeEditorStateFlag.Value) !== 0) {
var model = editor.getModel();
this.modelVersionId = model ? strings.format('{0}#{1}', model.uri.toString(), model.getVersionId()) : null;
}
if ((this.flags & CodeEditorStateFlag.Position) !== 0) {
this.position = editor.getPosition();
}
if ((this.flags & CodeEditorStateFlag.Selection) !== 0) {
this.selection = editor.getSelection();
}
if ((this.flags & CodeEditorStateFlag.Scroll) !== 0) {
this.scrollLeft = editor.getScrollLeft();
this.scrollTop = editor.getScrollTop();
}
}
private _equals(other: any): boolean {
if (!(other instanceof EditorState)) {
return false;
}
var state = <EditorState>other;
if (this.modelVersionId !== state.modelVersionId) {
return false;
}
if (this.scrollLeft !== state.scrollLeft || this.scrollTop !== state.scrollTop) {
return false;
}
if (!this.position && state.position || this.position && !state.position || this.position && state.position && !this.position.equals(state.position)) {
return false;
}
if (!this.selection && state.selection || this.selection && !state.selection || this.selection && state.selection && !this.selection.equalsRange(state.selection)) {
return false;
}
return true;
}
public validate(editor: ICommonCodeEditor): boolean {
return this._equals(new EditorState(editor, this.flags));
}
}

View File

@@ -12,61 +12,72 @@ export class LineToken {
_lineTokenBrand: void;
private readonly _source: LineTokens;
private readonly _tokenIndex: number;
private readonly _metadata: number;
private readonly _tokenCount: number;
public readonly startOffset: number;
public readonly endOffset: number;
public readonly hasPrev: boolean;
public readonly hasNext: boolean;
private _tokenIndex: number;
private _metadata: number;
private _startOffset: number;
private _endOffset: number;
public get startOffset(): number {
return this._startOffset;
}
public get endOffset(): number {
return this._endOffset;
}
public get hasPrev(): boolean {
return (this._tokenIndex > 0);
}
public get hasNext(): boolean {
return (this._tokenIndex + 1 < this._tokenCount);
}
public get languageId(): LanguageId {
return TokenMetadata.getLanguageId(this._metadata);
}
public get tokenType(): StandardTokenType {
return TokenMetadata.getTokenType(this._metadata);
}
public get fontStyle(): FontStyle {
return TokenMetadata.getFontStyle(this._metadata);
}
public get foregroundId(): ColorId {
return TokenMetadata.getForeground(this._metadata);
}
public get backgroundId(): ColorId {
return TokenMetadata.getBackground(this._metadata);
}
constructor(source: LineTokens, tokenIndex: number, tokenCount: number, startOffset: number, endOffset: number, metadata: number) {
this._source = source;
this._tokenCount = tokenCount;
this._set(tokenIndex, startOffset, endOffset, metadata);
}
public clone(): LineToken {
return new LineToken(this._source, this._tokenIndex, this._tokenCount, this._startOffset, this._endOffset, this._metadata);
}
_set(tokenIndex: number, startOffset: number, endOffset: number, metadata: number): void {
this._tokenIndex = tokenIndex;
this._metadata = metadata;
this.startOffset = startOffset;
this.endOffset = endOffset;
this.hasPrev = (this._tokenIndex > 0);
this.hasNext = (this._tokenIndex + 1 < tokenCount);
this._startOffset = startOffset;
this._endOffset = endOffset;
}
public prev(): LineToken {
if (!this.hasPrev) {
return null;
}
return this._source.tokenAt(this._tokenIndex - 1);
this._source.tokenAt(this._tokenIndex - 1, this);
return this;
}
public next(): LineToken {
if (!this.hasNext) {
return null;
}
return this._source.tokenAt(this._tokenIndex + 1);
this._source.tokenAt(this._tokenIndex + 1, this);
return this;
}
}
@@ -93,10 +104,6 @@ export class LineTokens {
return this._text;
}
public getLineLength(): number {
return this._textLength;
}
public getTokenStartOffset(tokenIndex: number): number {
return this._tokens[(tokenIndex << 1)];
}
@@ -138,7 +145,7 @@ export class LineTokens {
return this.tokenAt(tokenIndex);
}
public tokenAt(tokenIndex: number): LineToken {
public tokenAt(tokenIndex: number, dest?: LineToken): LineToken {
let startOffset = this._tokens[(tokenIndex << 1)];
let endOffset: number;
if (tokenIndex + 1 < this._tokensCount) {
@@ -147,6 +154,11 @@ export class LineTokens {
endOffset = this._textLength;
}
let metadata = this._tokens[(tokenIndex << 1) + 1];
if (dest) {
dest._set(tokenIndex, startOffset, endOffset, metadata);
return dest;
}
return new LineToken(this, tokenIndex, this._tokensCount, startOffset, endOffset, metadata);
}

View File

@@ -246,13 +246,6 @@ export class Range {
return new Position(this.startLineNumber, this.startColumn);
}
/**
* Clone this range.
*/
public cloneRange(): Range {
return new Range(this.startLineNumber, this.startColumn, this.endLineNumber, this.endColumn);
}
/**
* Transform to a user presentable string representation.
*/
@@ -387,4 +380,3 @@ export class Range {
return range.endLineNumber > range.startLineNumber;
}
}

View File

@@ -30,22 +30,13 @@ export class RGBA8 {
public readonly a: number;
constructor(r: number, g: number, b: number, a: number) {
this.r = RGBA8._clampInt_0_255(r);
this.g = RGBA8._clampInt_0_255(g);
this.b = RGBA8._clampInt_0_255(b);
this.a = RGBA8._clampInt_0_255(a);
this.r = RGBA8._clamp(r);
this.g = RGBA8._clamp(g);
this.b = RGBA8._clamp(b);
this.a = RGBA8._clamp(a);
}
public static equals(a: RGBA8, b: RGBA8): boolean {
return (
a.r === b.r
&& a.g === b.g
&& a.b === b.b
&& a.a === b.a
);
}
private static _clampInt_0_255(c: number): number {
private static _clamp(c: number): number {
if (c < 0) {
return 0;
}

View File

@@ -7,8 +7,8 @@
export class Uint8Matrix {
private _data: Uint8Array;
private _rows: number;
private _cols: number;
public readonly rows: number;
public readonly cols: number;
constructor(rows: number, cols: number, defaultValue: number) {
let data = new Uint8Array(rows * cols);
@@ -17,16 +17,16 @@ export class Uint8Matrix {
}
this._data = data;
this._rows = rows;
this._cols = cols;
this.rows = rows;
this.cols = cols;
}
public get(row: number, col: number): number {
return this._data[row * this._cols + col];
return this._data[row * this.cols + col];
}
public set(row: number, col: number, value: number): void {
this._data[row * this._cols + col] = value;
this._data[row * this.cols + col] = value;
}
}

View File

@@ -1,17 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ILineChange } from 'vs/editor/common/editorCommon';
export class DiffComputer {
constructor(originalLines: string[], modifiedLines: string[], shouldPostProcessCharChanges: boolean, shouldIgnoreTrimWhitespace: boolean) {
}
public computeDiff(): ILineChange[] {
return [];
}
}

View File

@@ -4,26 +4,21 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { BulkListenerCallback } from 'vs/base/common/eventEmitter';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
import { IndentRanges } from 'vs/editor/common/model/indentRanges';
import { ITextSource } from 'vs/editor/common/model/textSource';
import {
ModelRawContentChangedEvent, IModelContentChangedEvent, IModelDecorationsChangedEvent,
IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent
IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelLanguageConfigurationChangedEvent, IModelTokensChangedEvent
} from 'vs/editor/common/model/textModelEvents';
import * as editorOptions from 'vs/editor/common/config/editorOptions';
import { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { ICursors, CursorConfiguration } from 'vs/editor/common/controller/cursorCommon';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
/**
@@ -895,11 +890,6 @@ export interface ITokenizedModel extends ITextModel {
*/
matchBracket(position: IPosition): [Range, Range];
/**
* @internal
*/
getIndentRanges(): IndentRanges;
/**
* @internal
*/
@@ -1137,29 +1127,23 @@ export interface IModel extends IReadOnlyModel, IEditableTextModel, ITokenizedMo
* @event
*/
onDidChangeLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable;
/**
* An event emitted when the tokens associated with the model have changed.
* @event
* @internal
*/
onDidChangeTokens(listener: (e: IModelTokensChangedEvent) => void): IDisposable;
/**
* An event emitted right before disposing the model.
* @event
*/
onWillDispose(listener: () => void): IDisposable;
/**
* @internal
*/
addBulkListener(listener: BulkListenerCallback): IDisposable;
/**
* A unique identifier associated with this model.
*/
readonly id: string;
/**
* Destroy this model. This will unbind the model from the mode
* and make all necessary clean-up to release this object to the GC.
* @internal
*/
destroy(): void;
/**
* Destroy this model. This will unbind the model from the mode
* and make all necessary clean-up to release this object to the GC.
@@ -1240,12 +1224,6 @@ export interface ICharChange extends IChange {
export interface ILineChange extends IChange {
readonly charChanges: ICharChange[];
}
/**
* Information about a line in the diff editor
*/
export interface IDiffLineInformation {
readonly equivalentLineNumber: number;
}
/**
* @internal
@@ -1277,51 +1255,6 @@ export interface INewScrollPosition {
scrollTop?: number;
}
/**
* Description of an action contribution
*/
export interface IActionDescriptor {
/**
* An unique identifier of the contributed action.
*/
id: string;
/**
* A label of the action that will be presented to the user.
*/
label: string;
/**
* Precondition rule.
*/
precondition?: string;
/**
* An array of keybindings for the action.
*/
keybindings?: number[];
/**
* The keybinding rule (condition on top of precondition).
*/
keybindingContext?: string;
/**
* Control if the action should show up in the context menu and where.
* The context menu of the editor has these default:
* navigation - The navigation group comes first in all cases.
* 1_modification - This group comes next and contains commands that modify your code.
* 9_cutcopypaste - The last default group with the basic editing commands.
* You can also create your own group.
* Defaults to null (don't show in context menu).
*/
contextMenuGroupId?: string;
/**
* Control the order in the context menu group.
*/
contextMenuOrder?: number;
/**
* Method that will be executed when the action is triggered.
* @param editor The editor instance is passed in as a convinience
*/
run(editor: ICommonCodeEditor): void | TPromise<void>;
}
export interface IEditorAction {
readonly id: string;
readonly label: string;
@@ -1399,12 +1332,6 @@ export interface IEditor {
*/
getEditorType(): string;
/**
* Destroy the editor.
* @internal
*/
destroy(): void;
/**
* Update the editor's options after the editor has been created.
*/
@@ -1438,11 +1365,6 @@ export interface IEditor {
*/
isFocused(): boolean;
/**
* Returns all actions associated with this editor.
*/
getActions(): IEditorAction[];
/**
* Returns all actions associated with this editor.
*/
@@ -1725,333 +1647,6 @@ export interface IDecorationOptions {
renderOptions?: IDecorationInstanceRenderOptions;
}
export interface ICommonCodeEditor extends IEditor {
/**
* An event emitted when the content of the current model has changed.
* @event
*/
onDidChangeModelContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;
/**
* An event emitted when the language of the current model has changed.
* @event
*/
onDidChangeModelLanguage(listener: (e: IModelLanguageChangedEvent) => void): IDisposable;
/**
* An event emitted when the language configuration of the current model has changed.
* @event
*/
onDidChangeModelLanguageConfiguration(listener: (e: IModelLanguageConfigurationChangedEvent) => void): IDisposable;
/**
* An event emitted when the options of the current model has changed.
* @event
*/
onDidChangeModelOptions(listener: (e: IModelOptionsChangedEvent) => void): IDisposable;
/**
* An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`)
* @event
*/
onDidChangeConfiguration(listener: (e: editorOptions.IConfigurationChangedEvent) => void): IDisposable;
/**
* An event emitted when the cursor position has changed.
* @event
*/
onDidChangeCursorPosition(listener: (e: ICursorPositionChangedEvent) => void): IDisposable;
/**
* An event emitted when the cursor selection has changed.
* @event
*/
onDidChangeCursorSelection(listener: (e: ICursorSelectionChangedEvent) => void): IDisposable;
/**
* An event emitted when the model of this editor has changed (e.g. `editor.setModel()`).
* @event
*/
onDidChangeModel(listener: (e: IModelChangedEvent) => void): IDisposable;
/**
* An event emitted when the decorations of the current model have changed.
* @event
*/
onDidChangeModelDecorations(listener: (e: IModelDecorationsChangedEvent) => void): IDisposable;
/**
* An event emitted when the text inside this editor gained focus (i.e. cursor blinking).
* @event
*/
onDidFocusEditorText(listener: () => void): IDisposable;
/**
* An event emitted when the text inside this editor lost focus.
* @event
*/
onDidBlurEditorText(listener: () => void): IDisposable;
/**
* An event emitted when the text inside this editor or an editor widget gained focus.
* @event
*/
onDidFocusEditor(listener: () => void): IDisposable;
/**
* An event emitted when the text inside this editor or an editor widget lost focus.
* @event
*/
onDidBlurEditor(listener: () => void): IDisposable;
/**
* An event emitted before interpreting typed characters (on the keyboard).
* @event
* @internal
*/
onWillType(listener: (text: string) => void): IDisposable;
/**
* An event emitted before interpreting typed characters (on the keyboard).
* @event
* @internal
*/
onDidType(listener: (text: string) => void): IDisposable;
/**
* An event emitted when users paste text in the editor.
* @event
* @internal
*/
onDidPaste(listener: (range: Range) => void): IDisposable;
/**
* Saves current view state of the editor in a serializable object.
*/
saveViewState(): ICodeEditorViewState;
/**
* Restores the view state of the editor from a serializable object generated by `saveViewState`.
*/
restoreViewState(state: ICodeEditorViewState): void;
/**
* Returns true if this editor or one of its widgets has keyboard focus.
*/
hasWidgetFocus(): boolean;
/**
* Get a contribution of this editor.
* @id Unique identifier of the contribution.
* @return The contribution or null if contribution not found.
*/
getContribution<T extends IEditorContribution>(id: string): T;
/**
* Execute `fn` with the editor's services.
* @internal
*/
invokeWithinContext<T>(fn: (accessor: ServicesAccessor) => T): T;
/**
* Type the getModel() of IEditor.
*/
getModel(): IModel;
/**
* Returns the current editor's configuration
*/
getConfiguration(): editorOptions.InternalEditorOptions;
/**
* Returns the 'raw' editor's configuration (without any validation or defaults).
* @internal
*/
getRawConfiguration(): editorOptions.IEditorOptions;
/**
* Get value of the current model attached to this editor.
* @see IModel.getValue
*/
getValue(options?: { preserveBOM: boolean; lineEnding: string; }): string;
/**
* Set the value of the current model attached to this editor.
* @see IModel.setValue
*/
setValue(newValue: string): void;
/**
* Get the scrollWidth of the editor's viewport.
*/
getScrollWidth(): number;
/**
* Get the scrollLeft of the editor's viewport.
*/
getScrollLeft(): number;
/**
* Get the scrollHeight of the editor's viewport.
*/
getScrollHeight(): number;
/**
* Get the scrollTop of the editor's viewport.
*/
getScrollTop(): number;
/**
* Change the scrollLeft of the editor's viewport.
*/
setScrollLeft(newScrollLeft: number): void;
/**
* Change the scrollTop of the editor's viewport.
*/
setScrollTop(newScrollTop: number): void;
/**
* Change the scroll position of the editor's viewport.
*/
setScrollPosition(position: INewScrollPosition): void;
/**
* Get an action that is a contribution to this editor.
* @id Unique identifier of the contribution.
* @return The action or null if action not found.
*/
getAction(id: string): IEditorAction;
/**
* Execute a command on the editor.
* The edits will land on the undo-redo stack, but no "undo stop" will be pushed.
* @param source The source of the call.
* @param command The command to execute
*/
executeCommand(source: string, command: ICommand): void;
/**
* Push an "undo stop" in the undo-redo stack.
*/
pushUndoStop(): boolean;
/**
* Execute edits on the editor.
* The edits will land on the undo-redo stack, but no "undo stop" will be pushed.
* @param source The source of the call.
* @param edits The edits to execute.
* @param endCursoState Cursor state after the edits were applied.
*/
executeEdits(source: string, edits: IIdentifiedSingleEditOperation[], endCursoState?: Selection[]): boolean;
/**
* Execute multiple (concommitent) commands on the editor.
* @param source The source of the call.
* @param command The commands to execute
*/
executeCommands(source: string, commands: ICommand[]): void;
/**
* @internal
*/
_getCursors(): ICursors;
/**
* @internal
*/
_getCursorConfiguration(): CursorConfiguration;
/**
* Get all the decorations on a line (filtering out decorations from other editors).
*/
getLineDecorations(lineNumber: number): IModelDecoration[];
/**
* All decorations added through this call will get the ownerId of this editor.
* @see IModel.deltaDecorations
*/
deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];
/**
* @internal
*/
setDecorations(decorationTypeKey: string, ranges: IDecorationOptions[]): void;
/**
* @internal
*/
setDecorationsFast(decorationTypeKey: string, ranges: IRange[]): void;
/**
* @internal
*/
removeDecorations(decorationTypeKey: string): void;
/**
* Get the layout info for the editor.
*/
getLayoutInfo(): editorOptions.EditorLayoutInfo;
/**
* @internal
*/
getTelemetryData(): { [key: string]: any; };
}
export interface ICommonDiffEditor extends IEditor {
/**
* An event emitted when the diff information computed by this diff editor has been updated.
* @event
*/
onDidUpdateDiff(listener: () => void): IDisposable;
/**
* Saves current view state of the editor in a serializable object.
*/
saveViewState(): IDiffEditorViewState;
/**
* Restores the view state of the editor from a serializable object generated by `saveViewState`.
*/
restoreViewState(state: IDiffEditorViewState): void;
/**
* Type the getModel() of IEditor.
*/
getModel(): IDiffEditorModel;
/**
* Get the `original` editor.
*/
getOriginalEditor(): ICommonCodeEditor;
/**
* Get the `modified` editor.
*/
getModifiedEditor(): ICommonCodeEditor;
/**
* Get the computed diff information.
*/
getLineChanges(): ILineChange[];
/**
* Get information based on computed diff about a line number from the original model.
* If the diff computation is not finished or the model is missing, will return null.
*/
getDiffLineInformationForOriginal(lineNumber: number): IDiffLineInformation;
/**
* Get information based on computed diff about a line number from the modified model.
* If the diff computation is not finished or the model is missing, will return null.
*/
getDiffLineInformationForModified(lineNumber: number): IDiffLineInformation;
/**
* @see ICodeEditor.getValue
*/
getValue(options?: { preserveBOM: boolean; lineEnding: string; }): string;
/**
* Returns whether the diff editor is ignoring trim whitespace or not.
* @internal
*/
readonly ignoreTrimWhitespace: boolean;
/**
* Returns whether the diff editor is rendering side by side or not.
* @internal
*/
readonly renderSideBySide: boolean;
/**
* Returns whether the diff editor is rendering +/- indicators or not.
* @internal
*/
readonly renderIndicators: boolean;
}
/**
* The type of the `IEditor`.
*/
@@ -2060,28 +1655,6 @@ export var EditorType = {
IDiffEditor: 'vs.editor.IDiffEditor'
};
/**
*@internal
*/
export function isCommonCodeEditor(thing: any): thing is ICommonCodeEditor {
if (thing && typeof (<ICommonCodeEditor>thing).getEditorType === 'function') {
return (<ICommonCodeEditor>thing).getEditorType() === EditorType.ICodeEditor;
} else {
return false;
}
}
/**
*@internal
*/
export function isCommonDiffEditor(thing: any): thing is ICommonDiffEditor {
if (thing && typeof (<ICommonDiffEditor>thing).getEditorType === 'function') {
return (<ICommonDiffEditor>thing).getEditorType() === EditorType.IDiffEditor;
} else {
return false;
}
}
/**
* Built-in commands.
* @internal

View File

@@ -1,342 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { illegalArgument } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ServicesAccessor, IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation';
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { KeybindingsRegistry, ICommandAndKeybindingRule, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Position } from 'vs/editor/common/core/position';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { IModelService } from 'vs/editor/common/services/modelService';
import { MenuId, MenuRegistry, IMenuItem } from 'vs/platform/actions/common/actions';
import { IEditorService } from 'vs/platform/editor/common/editor';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ICodeEditorService, getCodeEditor } from 'vs/editor/common/services/codeEditorService';
export type ServicesAccessor = ServicesAccessor;
export type ICommonEditorContributionCtor = IConstructorSignature1<editorCommon.ICommonCodeEditor, editorCommon.IEditorContribution>;
// ----- Generic Command
export interface ICommandKeybindingsOptions extends IKeybindings {
kbExpr?: ContextKeyExpr;
weight?: number;
}
export interface ICommandOptions {
id: string;
precondition: ContextKeyExpr;
kbOpts?: ICommandKeybindingsOptions;
description?: ICommandHandlerDescription;
}
export abstract class Command {
public readonly id: string;
public readonly precondition: ContextKeyExpr;
private readonly _kbOpts: ICommandKeybindingsOptions;
private readonly _description: ICommandHandlerDescription;
constructor(opts: ICommandOptions) {
this.id = opts.id;
this.precondition = opts.precondition;
this._kbOpts = opts.kbOpts;
this._description = opts.description;
}
public toCommandAndKeybindingRule(defaultWeight: number): ICommandAndKeybindingRule {
const kbOpts = this._kbOpts || { primary: 0 };
let kbWhen = kbOpts.kbExpr;
if (this.precondition) {
if (kbWhen) {
kbWhen = ContextKeyExpr.and(kbWhen, this.precondition);
} else {
kbWhen = this.precondition;
}
}
const weight = (typeof kbOpts.weight === 'number' ? kbOpts.weight : defaultWeight);
return {
id: this.id,
handler: (accessor, args) => this.runCommand(accessor, args),
weight: weight,
when: kbWhen,
primary: kbOpts.primary,
secondary: kbOpts.secondary,
win: kbOpts.win,
linux: kbOpts.linux,
mac: kbOpts.mac,
description: this._description
};
}
public abstract runCommand(accessor: ServicesAccessor, args: any): void | TPromise<void>;
}
// ----- Editor Command & Editor Contribution Command
function findFocusedEditor(accessor: ServicesAccessor): editorCommon.ICommonCodeEditor {
return accessor.get(ICodeEditorService).getFocusedCodeEditor();
}
function getWorkbenchActiveEditor(accessor: ServicesAccessor): editorCommon.ICommonCodeEditor {
const editorService = accessor.get(IEditorService);
let activeEditor = (<any>editorService).getActiveEditor && (<any>editorService).getActiveEditor();
return getCodeEditor(activeEditor);
}
export interface IContributionCommandOptions<T> extends ICommandOptions {
handler: (controller: T) => void;
}
export interface EditorControllerCommand<T extends editorCommon.IEditorContribution> {
new(opts: IContributionCommandOptions<T>): EditorCommand;
}
export abstract class EditorCommand extends Command {
/**
* Create a command class that is bound to a certain editor contribution.
*/
public static bindToContribution<T extends editorCommon.IEditorContribution>(controllerGetter: (editor: editorCommon.ICommonCodeEditor) => T): EditorControllerCommand<T> {
return class EditorControllerCommandImpl extends EditorCommand {
private _callback: (controller: T) => void;
constructor(opts: IContributionCommandOptions<T>) {
super(opts);
this._callback = opts.handler;
}
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void {
let controller = controllerGetter(editor);
if (controller) {
this._callback(controllerGetter(editor));
}
}
};
}
public runCommand(accessor: ServicesAccessor, args: any): void | TPromise<void> {
// Find the editor with text focus
let editor = findFocusedEditor(accessor);
if (!editor) {
// Fallback to use what the workbench considers the active editor
editor = getWorkbenchActiveEditor(accessor);
}
if (!editor) {
// well, at least we tried...
return;
}
return editor.invokeWithinContext((editorAccessor) => {
const kbService = editorAccessor.get(IContextKeyService);
if (!kbService.contextMatchesRules(this.precondition)) {
// precondition does not hold
return;
}
return this.runEditorCommand(editorAccessor, editor, args);
});
}
public abstract runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void>;
}
// ----- Editor Action
export interface IEditorCommandMenuOptions {
group?: string;
order?: number;
when?: ContextKeyExpr;
}
export interface IActionOptions extends ICommandOptions {
label: string;
alias: string;
menuOpts?: IEditorCommandMenuOptions;
}
export abstract class EditorAction extends EditorCommand {
public label: string;
public alias: string;
private menuOpts: IEditorCommandMenuOptions;
constructor(opts: IActionOptions) {
super(opts);
this.label = opts.label;
this.alias = opts.alias;
this.menuOpts = opts.menuOpts;
}
public toMenuItem(): IMenuItem {
if (!this.menuOpts) {
return null;
}
return {
command: {
id: this.id,
title: this.label
},
when: ContextKeyExpr.and(this.precondition, this.menuOpts.when),
group: this.menuOpts.group,
order: this.menuOpts.order
};
}
public runEditorCommand(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void> {
this.reportTelemetry(accessor, editor);
return this.run(accessor, editor, args || {});
}
protected reportTelemetry(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor) {
/* __GDPR__
"editorActionInvoked" : {
"name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"${include}": [
"${EditorTelemetryData}"
]
}
*/
accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() });
}
public abstract run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor, args: any): void | TPromise<void>;
}
// --- Registration of commands and actions
export function editorAction(ctor: { new(): EditorAction; }): void {
CommonEditorRegistry.registerEditorAction(new ctor());
}
export function editorCommand(ctor: { new(): EditorCommand }): void {
registerEditorCommand(new ctor());
}
export function registerEditorCommand<T extends EditorCommand>(editorCommand: T): T {
CommonEditorRegistry.registerEditorCommand(editorCommand);
return editorCommand;
}
export function commonEditorContribution(ctor: ICommonEditorContributionCtor): void {
EditorContributionRegistry.INSTANCE.registerEditorContribution(ctor);
}
export module CommonEditorRegistry {
// --- Editor Actions
export function registerEditorAction(editorAction: EditorAction) {
EditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);
}
export function getEditorActions(): EditorAction[] {
return EditorContributionRegistry.INSTANCE.getEditorActions();
}
export function getEditorCommand(commandId: string): EditorCommand {
return EditorContributionRegistry.INSTANCE.getEditorCommand(commandId);
}
// --- Editor Contributions
export function getEditorContributions(): ICommonEditorContributionCtor[] {
return EditorContributionRegistry.INSTANCE.getEditorContributions();
}
// --- Editor Commands
export function commandWeight(importance: number = 0): number {
return KeybindingsRegistry.WEIGHT.editorContrib(importance);
}
export function registerEditorCommand(editorCommand: EditorCommand): void {
EditorContributionRegistry.INSTANCE.registerEditorCommand(editorCommand);
}
export function registerLanguageCommand(id: string, handler: (accessor: ServicesAccessor, args: { [n: string]: any }) => any) {
CommandsRegistry.registerCommand(id, (accessor, args) => handler(accessor, args || {}));
}
export function registerDefaultLanguageCommand(id: string, handler: (model: editorCommon.IModel, position: Position, args: { [n: string]: any }) => any) {
registerLanguageCommand(id, function (accessor, args) {
const { resource, position } = args;
if (!(resource instanceof URI)) {
throw illegalArgument('resource');
}
if (!Position.isIPosition(position)) {
throw illegalArgument('position');
}
const model = accessor.get(IModelService).getModel(resource);
if (!model) {
throw illegalArgument('Can not find open model for ' + resource);
}
const editorPosition = Position.lift(position);
return handler(model, editorPosition, args);
});
}
}
// Editor extension points
const Extensions = {
EditorCommonContributions: 'editor.commonContributions'
};
class EditorContributionRegistry {
public static INSTANCE = new EditorContributionRegistry();
private editorContributions: ICommonEditorContributionCtor[];
private editorActions: EditorAction[];
private editorCommands: { [commandId: string]: EditorCommand; };
constructor() {
this.editorContributions = [];
this.editorActions = [];
this.editorCommands = Object.create(null);
}
public registerEditorContribution(ctor: ICommonEditorContributionCtor): void {
this.editorContributions.push(ctor);
}
public registerEditorAction(action: EditorAction) {
let menuItem = action.toMenuItem();
if (menuItem) {
MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem);
}
KeybindingsRegistry.registerCommandAndKeybindingRule(action.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
this.editorActions.push(action);
}
public getEditorContributions(): ICommonEditorContributionCtor[] {
return this.editorContributions.slice(0);
}
public getEditorActions(): EditorAction[] {
return this.editorActions.slice(0);
}
public registerEditorCommand(editorCommand: EditorCommand) {
KeybindingsRegistry.registerCommandAndKeybindingRule(editorCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
this.editorCommands[editorCommand.id] = editorCommand;
}
public getEditorCommand(commandId: string): EditorCommand {
return (this.editorCommands[commandId] || null);
}
}
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);

View File

@@ -42,4 +42,4 @@ export namespace EditorContextKeys {
export const hasDocumentFormattingProvider = new RawContextKey<boolean>('editorHasDocumentFormattingProvider', undefined);
export const hasDocumentSelectionFormattingProvider = new RawContextKey<boolean>('editorHasDocumentSelectionFormattingProvider', undefined);
export const hasSignatureHelpProvider = new RawContextKey<boolean>('editorHasSignatureHelpProvider', undefined);
};
}

View File

@@ -12,11 +12,9 @@ import { TextModelWithDecorations, ModelDecorationOptions } from 'vs/editor/comm
import * as strings from 'vs/base/common/strings';
import * as arrays from 'vs/base/common/arrays';
import { Selection } from 'vs/editor/common/core/selection';
import { IDisposable } from 'vs/base/common/lifecycle';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { ITextSource, IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource';
import { TextModel } from 'vs/editor/common/model/textModel';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource';
import { ModelRawContentChangedEvent, ModelRawChange, IModelContentChange, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from 'vs/editor/common/model/textModelEvents';
export interface IValidatedEditOperation {
sortIndex: number;
@@ -35,17 +33,6 @@ interface IIdentifiedLineEdit extends ILineEdit {
export class EditableTextModel extends TextModelWithDecorations implements editorCommon.IEditableTextModel {
public static createFromString(text: string, options: editorCommon.ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier = null): EditableTextModel {
return new EditableTextModel(RawTextSource.fromString(text), options, languageIdentifier);
}
public onDidChangeRawContent(listener: (e: textModelEvents.ModelRawContentChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelRawContentChanged2, listener);
}
public onDidChangeContent(listener: (e: textModelEvents.IModelContentChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelContentChanged, listener);
}
private _commandManager: EditStack;
// for extra details about change events:
@@ -93,8 +80,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
public pushEditOperations(beforeCursorState: Selection[], editOperations: editorCommon.IIdentifiedSingleEditOperation[], cursorStateComputer: editorCommon.ICursorStateComputer): Selection[] {
try {
this._eventEmitter.beginDeferredEmit();
this._onDidChangeDecorations.beginDeferredEmit();
return this._pushEditOperations(beforeCursorState, editOperations, cursorStateComputer);
} finally {
this._onDidChangeDecorations.endDeferredEmit();
this._eventEmitter.endDeferredEmit();
}
}
@@ -276,10 +265,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
public applyEdits(rawOperations: editorCommon.IIdentifiedSingleEditOperation[]): editorCommon.IIdentifiedSingleEditOperation[] {
try {
this._eventEmitter.beginDeferredEmit();
this._acquireDecorationsTracker();
this._onDidChangeDecorations.beginDeferredEmit();
return this._applyEdits(rawOperations);
} finally {
this._releaseDecorationsTracker();
this._onDidChangeDecorations.endDeferredEmit();
this._eventEmitter.endDeferredEmit();
}
}
@@ -472,8 +461,8 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
// Sort operations descending
operations.sort(EditableTextModel._sortOpsDescending);
let rawContentChanges: textModelEvents.ModelRawChange[] = [];
let contentChanges: textModelEvents.IModelContentChange[] = [];
let rawContentChanges: ModelRawChange[] = [];
let contentChanges: IModelContentChange[] = [];
let lineEditsQueue: IIdentifiedLineEdit[] = [];
const queueLineEdit = (lineEdit: IIdentifiedLineEdit) => {
@@ -506,7 +495,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, i));
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
new ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
);
currentLineNumber = lineNumber;
@@ -517,7 +506,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lines[currentLineNumber - 1].applyEdits(lineEditsQueue.slice(currentLineNumberStart, lineEditsQueue.length));
this._lineStarts.changeValue(currentLineNumber - 1, this._lines[currentLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
new ModelRawLineChanged(currentLineNumber, this._lines[currentLineNumber - 1].text)
);
lineEditsQueue = [];
@@ -580,11 +569,11 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lineStarts.changeValue(spliceStartLineNumber - 1, this._lines[spliceStartLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(spliceStartLineNumber, this._lines[spliceStartLineNumber - 1].text)
new ModelRawLineChanged(spliceStartLineNumber, this._lines[spliceStartLineNumber - 1].text)
);
rawContentChanges.push(
new textModelEvents.ModelRawLinesDeleted(spliceStartLineNumber + 1, spliceStartLineNumber + spliceCnt)
new ModelRawLinesDeleted(spliceStartLineNumber + 1, spliceStartLineNumber + spliceCnt)
);
}
@@ -604,7 +593,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
let leftoverLine = this._lines[spliceLineNumber - 1].split(spliceColumn);
this._lineStarts.changeValue(spliceLineNumber - 1, this._lines[spliceLineNumber - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLineChanged(spliceLineNumber, this._lines[spliceLineNumber - 1].text)
new ModelRawLineChanged(spliceLineNumber, this._lines[spliceLineNumber - 1].text)
);
this._invalidateLine(spliceLineNumber - 1);
@@ -625,7 +614,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
this._lines[startLineNumber + insertingLinesCnt - 1].append(leftoverLine);
this._lineStarts.changeValue(startLineNumber + insertingLinesCnt - 1, this._lines[startLineNumber + insertingLinesCnt - 1].text.length + this._EOL.length);
rawContentChanges.push(
new textModelEvents.ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n'))
new ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n'))
);
}
@@ -647,25 +636,23 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
if (rawContentChanges.length !== 0 || contentChanges.length !== 0) {
this._increaseVersionId();
this._emitModelRawContentChangedEvent(new textModelEvents.ModelRawContentChangedEvent(
rawContentChanges,
this.getVersionId(),
this._isUndoing,
this._isRedoing
));
const e: textModelEvents.IModelContentChangedEvent = {
changes: contentChanges,
eol: this._EOL,
versionId: this.getVersionId(),
isUndoing: this._isUndoing,
isRedoing: this._isRedoing,
isFlush: false
};
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelContentChanged, e);
this._emitContentChangedEvent(
new ModelRawContentChangedEvent(
rawContentChanges,
this.getVersionId(),
this._isUndoing,
this._isRedoing
),
{
changes: contentChanges,
eol: this._EOL,
versionId: this.getVersionId(),
isUndoing: this._isUndoing,
isRedoing: this._isRedoing,
isFlush: false
}
);
}
this._resetIndentRanges();
}
private _undo(): Selection[] {
@@ -685,10 +672,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
public undo(): Selection[] {
try {
this._eventEmitter.beginDeferredEmit();
this._acquireDecorationsTracker();
this._onDidChangeDecorations.beginDeferredEmit();
return this._undo();
} finally {
this._releaseDecorationsTracker();
this._onDidChangeDecorations.endDeferredEmit();
this._eventEmitter.endDeferredEmit();
}
}
@@ -710,10 +697,10 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
public redo(): Selection[] {
try {
this._eventEmitter.beginDeferredEmit();
this._acquireDecorationsTracker();
this._onDidChangeDecorations.beginDeferredEmit();
return this._redo();
} finally {
this._releaseDecorationsTracker();
this._onDidChangeDecorations.endDeferredEmit();
this._eventEmitter.endDeferredEmit();
}
}
@@ -740,7 +727,7 @@ export class EditableTextModel extends TextModelWithDecorations implements edito
});
}
private static _DECORATION_OPTION = ModelDecorationOptions.register({
private static readonly _DECORATION_OPTION = ModelDecorationOptions.register({
stickiness: editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges
});

View File

@@ -1,267 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ITextModel } from 'vs/editor/common/editorCommon';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
import { computeIndentLevel } from 'vs/editor/common/model/modelLine';
export const MAX_FOLDING_REGIONS = 0xFFFF;
const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000;
const MASK_LINE_NUMBER = 0xFFFFFF;
const MASK_INDENT = 0xFF000000;
export class IndentRanges {
private _startIndexes: Uint32Array;
private _endIndexes: Uint32Array;
private _model: ITextModel;
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, model: ITextModel) {
if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {
throw new Error('invalid startIndexes or endIndexes size');
}
this._startIndexes = startIndexes;
this._endIndexes = endIndexes;
this._model = model;
this._computeParentIndices();
}
private _computeParentIndices() {
let parentIndexes = [];
let isInsideLast = (startLineNumber: number, endLineNumber: number) => {
let index = parentIndexes[parentIndexes.length - 1];
return this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber;
};
for (let i = 0, len = this._startIndexes.length; i < len; i++) {
let startLineNumber = this._startIndexes[i];
let endLineNumber = this._endIndexes[i];
if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) {
throw new Error('startLineNumber or endLineNumber must not exceed ' + MASK_LINE_NUMBER);
}
while (parentIndexes.length > 0 && !isInsideLast(startLineNumber, endLineNumber)) {
parentIndexes.pop();
}
let parentIndex = parentIndexes.length > 0 ? parentIndexes[parentIndexes.length - 1] : -1;
parentIndexes.push(i);
this._startIndexes[i] = startLineNumber + ((parentIndex & 0xFF) << 24);
this._endIndexes[i] = endLineNumber + ((parentIndex & 0xFF00) << 16);
}
}
public get length(): number {
return this._startIndexes.length;
}
public getStartLineNumber(index: number): number {
return this._startIndexes[index] & MASK_LINE_NUMBER;
}
public getEndLineNumber(index: number): number {
return this._endIndexes[index] & MASK_LINE_NUMBER;
}
public getParentIndex(index: number) {
let parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16);
if (parent === MAX_FOLDING_REGIONS) {
return -1;
}
return parent;
}
public getIndent(index: number) {
const lineNumber = this.getStartLineNumber(index);
const tabSize = this._model.getOptions().tabSize;
const lineContent = this._model.getLineContent(lineNumber);
return computeIndentLevel(lineContent, tabSize);
}
public contains(index: number, line: number) {
return this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line;
}
private findIndex(line: number) {
let low = 0, high = this._startIndexes.length;
if (high === 0) {
return -1; // no children
}
while (low < high) {
let mid = Math.floor((low + high) / 2);
if (line < this.getStartLineNumber(mid)) {
high = mid;
} else {
low = mid + 1;
}
}
return low - 1;
}
public findRange(line: number): number {
let index = this.findIndex(line);
if (index >= 0) {
let endLineNumber = this.getEndLineNumber(index);
if (endLineNumber >= line) {
return index;
}
index = this.getParentIndex(index);
while (index !== -1) {
if (this.contains(index, line)) {
return index;
}
index = this.getParentIndex(index);
}
}
return -1;
}
}
// public only for testing
export class RangesCollector {
private _startIndexes: number[];
private _endIndexes: number[];
private _indentOccurrences: number[];
private _length: number;
private _foldingRegionsLimit: number;
constructor(foldingRegionsLimit: number) {
this._startIndexes = [];
this._endIndexes = [];
this._indentOccurrences = [];
this._length = 0;
this._foldingRegionsLimit = foldingRegionsLimit;
}
public insertFirst(startLineNumber: number, endLineNumber: number, indent: number) {
if (startLineNumber > MASK_LINE_NUMBER || endLineNumber > MASK_LINE_NUMBER) {
return;
}
let index = this._length;
this._startIndexes[index] = startLineNumber;
this._endIndexes[index] = endLineNumber;
this._length++;
if (indent < 1000) {
this._indentOccurrences[indent] = (this._indentOccurrences[indent] || 0) + 1;
}
}
public toIndentRanges(model: ITextModel) {
if (this._length <= this._foldingRegionsLimit) {
// reverse and create arrays of the exact length
let startIndexes = new Uint32Array(this._length);
let endIndexes = new Uint32Array(this._length);
for (let i = this._length - 1, k = 0; i >= 0; i-- , k++) {
startIndexes[k] = this._startIndexes[i];
endIndexes[k] = this._endIndexes[i];
}
return new IndentRanges(startIndexes, endIndexes, model);
} else {
let entries = 0;
let maxIndent = this._indentOccurrences.length;
for (let i = 0; i < this._indentOccurrences.length; i++) {
let n = this._indentOccurrences[i];
if (n) {
if (n + entries > this._foldingRegionsLimit) {
maxIndent = i;
break;
}
entries += n;
}
}
const tabSize = model.getOptions().tabSize;
// reverse and create arrays of the exact length
let startIndexes = new Uint32Array(entries);
let endIndexes = new Uint32Array(entries);
for (let i = this._length - 1, k = 0; i >= 0; i--) {
let startIndex = this._startIndexes[i];
let lineContent = model.getLineContent(startIndex);
let indent = computeIndentLevel(lineContent, tabSize);
if (indent < maxIndent) {
startIndexes[k] = startIndex;
endIndexes[k] = this._endIndexes[i];
k++;
}
}
return new IndentRanges(startIndexes, endIndexes, model);
}
}
}
interface PreviousRegion { indent: number; line: number; marker: boolean; };
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRegionsLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): IndentRanges {
const tabSize = model.getOptions().tabSize;
let result = new RangesCollector(foldingRegionsLimit);
let pattern = void 0;
if (markers) {
pattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`);
}
let previousRegions: PreviousRegion[] = [];
previousRegions.push({ indent: -1, line: model.getLineCount() + 1, marker: false }); // sentinel, to make sure there's at least one entry
for (let line = model.getLineCount(); line > 0; line--) {
let lineContent = model.getLineContent(line);
let indent = computeIndentLevel(lineContent, tabSize);
let previous = previousRegions[previousRegions.length - 1];
if (indent === -1) {
if (offSide && !previous.marker) {
// for offSide languages, empty lines are associated to the next block
previous.line = line;
}
continue; // only whitespace
}
let m;
if (pattern && (m = lineContent.match(pattern))) {
// folding pattern match
if (m[1]) { // start pattern match
// discard all regions until the folding pattern
let i = previousRegions.length - 1;
while (i > 0 && !previousRegions[i].marker) {
i--;
}
if (i > 0) {
previousRegions.length = i + 1;
previous = previousRegions[i];
// new folding range from pattern, includes the end line
result.insertFirst(line, previous.line, indent);
previous.marker = false;
previous.indent = indent;
previous.line = line;
continue;
} else {
// no end marker found, treat line as a regular line
}
} else { // end pattern match
previousRegions.push({ indent: -2, line, marker: true });
continue;
}
}
if (previous.indent > indent) {
// discard all regions with larger indent
do {
previousRegions.pop();
previous = previousRegions[previousRegions.length - 1];
} while (previous.indent > indent);
// new folding range
let endLineNumber = previous.line - 1;
if (endLineNumber - line >= 1) { // needs at east size 1
result.insertFirst(line, endLineNumber, indent);
}
}
if (previous.indent === indent) {
previous.line = line;
} else { // previous.indent < indent
// new region with a bigger indent
previousRegions.push({ indent, line, marker: false });
}
}
return result.toIndentRanges(model);
}

View File

@@ -12,10 +12,13 @@ import { IModelDecoration } from 'vs/editor/common/editorCommon';
// The red-black tree is based on the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
//
/**
* The class name sort order must match the severity order. Highest severity last.
*/
export const ClassName = {
EditorInfoDecoration: 'infosquiggly',
EditorWarningDecoration: 'warningsquiggly',
EditorErrorDecoration: 'errorsquiggly'
EditorInfoDecoration: 'squiggly-a-info',
EditorWarningDecoration: 'squiggly-b-warning',
EditorErrorDecoration: 'squiggly-c-error'
};
/**
@@ -29,7 +32,7 @@ export const enum TrackedRangeStickiness {
GrowsOnlyWhenTypingAfter = 3,
}
const enum NodeColor {
export const enum NodeColor {
Black = 0,
Red = 1,
}
@@ -78,7 +81,7 @@ const enum Constants {
MAX_SAFE_DELTA = 1 << 30,
}
function getNodeColor(node: IntervalNode): NodeColor {
export function getNodeColor(node: IntervalNode): NodeColor {
return ((node.metadata & Constants.ColorMask) >>> Constants.ColorOffset);
}
function setNodeColor(node: IntervalNode, color: NodeColor): void {
@@ -185,9 +188,11 @@ export class IntervalNode implements IModelDecoration {
public setOptions(options: ModelDecorationOptions) {
this.options = options;
let className = this.options.className;
setNodeIsForValidation(this, (
this.options.className === ClassName.EditorErrorDecoration
|| this.options.className === ClassName.EditorWarningDecoration
className === ClassName.EditorErrorDecoration
|| className === ClassName.EditorWarningDecoration
|| className === ClassName.EditorInfoDecoration
));
setNodeStickiness(this, <number>this.options.stickiness);
setNodeIsInOverviewRuler(this, this.options.overviewRuler.color ? true : false);
@@ -209,7 +214,7 @@ export class IntervalNode implements IModelDecoration {
}
}
const SENTINEL: IntervalNode = new IntervalNode(null, 0, 0);
export const SENTINEL: IntervalNode = new IntervalNode(null, 0, 0);
SENTINEL.parent = SENTINEL;
SENTINEL.left = SENTINEL;
SENTINEL.right = SENTINEL;
@@ -239,13 +244,6 @@ export class IntervalTree {
return search(this, filterOwnerId, filterOutValidation, cachedVersionId);
}
public count(): number {
if (this.root === SENTINEL) {
return 0;
}
return nodeCount(this);
}
/**
* Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!
*/
@@ -314,46 +312,10 @@ export class IntervalTree {
this._normalizeDeltaIfNecessary();
}
public assertInvariants(): void {
assert(getNodeColor(SENTINEL) === NodeColor.Black);
assert(SENTINEL.parent === SENTINEL);
assert(SENTINEL.left === SENTINEL);
assert(SENTINEL.right === SENTINEL);
assert(SENTINEL.start === 0);
assert(SENTINEL.end === 0);
assert(SENTINEL.delta === 0);
assert(this.root.parent === SENTINEL);
assertValidTree(this);
}
public getAllInOrder(): IntervalNode[] {
return search(this, 0, false, 0);
}
public print(): void {
if (this.root === SENTINEL) {
console.log(`~~ empty`);
return;
}
let out: string[] = [];
this._print(this.root, '', 0, out);
console.log(out.join(''));
}
private _print(n: IntervalNode, indent: string, delta: number, out: string[]): void {
out.push(`${indent}[${getNodeColor(n) === NodeColor.Red ? 'R' : 'B'},${n.delta}, ${n.start}->${n.end}, ${n.maxEnd}] : {${delta + n.start}->${delta + n.end}}, maxEnd: ${n.maxEnd + delta}\n`);
if (n.left !== SENTINEL) {
this._print(n.left, indent + ' ', delta, out);
} else {
out.push(`${indent} NIL\n`);
}
if (n.right !== SENTINEL) {
this._print(n.right, indent + ' ', delta + n.delta, out);
} else {
out.push(`${indent} NIL\n`);
}
}
private _normalizeDeltaIfNecessary(): void {
if (!this.requestNormalizeDelta) {
return;
@@ -425,7 +387,7 @@ function adjustMarkerBeforeColumn(markerOffset: number, markerStickToPreviousCha
return true;
}
return markerStickToPreviousCharacter;
};
}
/**
* This is a lot more complicated than strictly necessary to maintain the same behaviour
@@ -646,40 +608,6 @@ function noOverlapReplace(T: IntervalTree, start: number, end: number, textLengt
//#region Searching
function nodeCount(T: IntervalTree): number {
let node = T.root;
let count = 0;
while (node !== SENTINEL) {
if (getNodeIsVisited(node)) {
// going up from this node
setNodeIsVisited(node.left, false);
setNodeIsVisited(node.right, false);
node = node.parent;
continue;
}
if (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {
// go left
node = node.left;
continue;
}
// handle current node
count++;
setNodeIsVisited(node, true);
if (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {
// go right
node = node.right;
continue;
}
}
setNodeIsVisited(T.root, false);
return count;
}
function collectNodesFromOwner(T: IntervalTree, ownerId: number): IntervalNode[] {
let node = T.root;
let result: IntervalNode[] = [];
@@ -1304,66 +1232,10 @@ function recomputeMaxEndWalkToRoot(node: IntervalNode): void {
//#endregion
//#region utils
function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number {
export function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number {
if (aStart === bStart) {
return aEnd - bEnd;
}
return aStart - bStart;
}
//#endregion
//#region Assertion
function depth(n: IntervalNode): number {
if (n === SENTINEL) {
// The leafs are black
return 1;
}
assert(depth(n.left) === depth(n.right));
return (getNodeColor(n) === NodeColor.Black ? 1 : 0) + depth(n.left);
}
function assertValidNode(n: IntervalNode, delta): void {
if (n === SENTINEL) {
return;
}
let l = n.left;
let r = n.right;
if (getNodeColor(n) === NodeColor.Red) {
assert(getNodeColor(l) === NodeColor.Black);
assert(getNodeColor(r) === NodeColor.Black);
}
let expectedMaxEnd = n.end;
if (l !== SENTINEL) {
assert(intervalCompare(l.start + delta, l.end + delta, n.start + delta, n.end + delta) <= 0);
expectedMaxEnd = Math.max(expectedMaxEnd, l.maxEnd);
}
if (r !== SENTINEL) {
assert(intervalCompare(n.start + delta, n.end + delta, r.start + delta + n.delta, r.end + delta + n.delta) <= 0);
expectedMaxEnd = Math.max(expectedMaxEnd, r.maxEnd + n.delta);
}
assert(n.maxEnd === expectedMaxEnd);
assertValidNode(l, delta);
assertValidNode(r, delta + n.delta);
}
function assertValidTree(tree: IntervalTree): void {
if (tree.root === SENTINEL) {
return;
}
assert(getNodeColor(tree.root) === NodeColor.Black);
assert(depth(tree.root.left) === depth(tree.root.right));
assertValidNode(tree.root, 0);
}
function assert(condition: boolean): void {
if (!condition) {
throw new Error('Assertion violation');
}
}
//#endregion

View File

@@ -5,15 +5,12 @@
'use strict';
import URI from 'vs/base/common/uri';
import {
IModel, ITextModelCreationOptions
} from 'vs/editor/common/editorCommon';
import Event, { Emitter } from 'vs/base/common/event';
import { IModel, ITextModelCreationOptions } from 'vs/editor/common/editorCommon';
import { EditableTextModel } from 'vs/editor/common/model/editableTextModel';
import { TextModel } from 'vs/editor/common/model/textModel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
// The hierarchy is:
// Model -> EditableTextModel -> TextModelWithDecorations -> TextModelWithTokens -> TextModel
@@ -22,21 +19,9 @@ var MODEL_ID = 0;
export class Model extends EditableTextModel implements IModel {
public onDidChangeDecorations(listener: (e: textModelEvents.IModelDecorationsChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelDecorationsChanged, listener);
}
public onDidChangeOptions(listener: (e: textModelEvents.IModelOptionsChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelOptionsChanged, listener);
}
public onWillDispose(listener: () => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelDispose, listener);
}
public onDidChangeLanguage(listener: (e: textModelEvents.IModelLanguageChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageChanged, listener);
}
public onDidChangeLanguageConfiguration(listener: (e: textModelEvents.IModelLanguageConfigurationChangedEvent) => void): IDisposable {
return this._eventEmitter.addListener(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, listener);
}
private readonly _onWillDispose: Emitter<void> = this._register(new Emitter<void>());
public readonly onWillDispose: Event<void> = this._onWillDispose.event;
public static createFromString(text: string, options: ITextModelCreationOptions = TextModel.DEFAULT_CREATION_OPTIONS, languageIdentifier: LanguageIdentifier = null, uri: URI = null): Model {
return new Model(RawTextSource.fromString(text), options, languageIdentifier, uri);
}
@@ -62,13 +47,9 @@ export class Model extends EditableTextModel implements IModel {
this._attachedEditorCount = 0;
}
public destroy(): void {
this.dispose();
}
public dispose(): void {
this._isDisposing = true;
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelDispose);
this._onWillDispose.fire();
super.dispose();
this._isDisposing = false;
}

View File

@@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { OrderGuaranteeEventEmitter, BulkListenerCallback } from 'vs/base/common/eventEmitter';
import * as strings from 'vs/base/common/strings';
import Event, { Emitter } from 'vs/base/common/event';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
@@ -16,8 +16,8 @@ import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { TextModelSearch, SearchParams } from 'vs/editor/common/model/textModelSearch';
import { TextSource, ITextSource, IRawTextSource, RawTextSource } from 'vs/editor/common/model/textSource';
import { IDisposable } from 'vs/base/common/lifecycle';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { IModelContentChangedEvent, ModelRawContentChangedEvent, ModelRawFlush, ModelRawEOLChanged, IModelOptionsChangedEvent, InternalModelContentChangeEvent } from 'vs/editor/common/model/textModelEvents';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
const LIMIT_FIND_COUNT = 999;
export const LONG_LINE_BOUNDARY = 10000;
@@ -27,10 +27,10 @@ export interface ITextModelCreationData {
readonly options: editorCommon.TextModelResolvedOptions;
}
export class TextModel implements editorCommon.ITextModel {
private static MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
private static MODEL_TOKENIZATION_LIMIT = 20 * 1024 * 1024; // 20 MB
private static MANY_MANY_LINES = 300 * 1000; // 300K lines
export class TextModel extends Disposable implements editorCommon.ITextModel {
private static readonly MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
private static readonly MODEL_TOKENIZATION_LIMIT = 20 * 1024 * 1024; // 20 MB
private static readonly MANY_MANY_LINES = 300 * 1000; // 300K lines
public static DEFAULT_CREATION_OPTIONS: editorCommon.ITextModelCreationOptions = {
tabSize: EDITOR_MODEL_DEFAULTS.tabSize,
@@ -71,11 +71,17 @@ export class TextModel implements editorCommon.ITextModel {
};
}
public addBulkListener(listener: BulkListenerCallback): IDisposable {
return this._eventEmitter.addBulkListener(listener);
}
private readonly _onDidChangeOptions: Emitter<IModelOptionsChangedEvent> = this._register(new Emitter<IModelOptionsChangedEvent>());
public readonly onDidChangeOptions: Event<IModelOptionsChangedEvent> = this._onDidChangeOptions.event;
protected readonly _eventEmitter: OrderGuaranteeEventEmitter;
protected readonly _eventEmitter: DidChangeContentEmitter = this._register(new DidChangeContentEmitter());
public onDidChangeRawContent(listener: (e: ModelRawContentChangedEvent) => void): IDisposable {
return this._eventEmitter.event((e: InternalModelContentChangeEvent) => listener(e.rawContentChangedEvent));
}
public onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable {
return this._eventEmitter.event((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent));
}
/*protected*/ _lines: IModelLine[];
protected _EOL: string;
@@ -97,7 +103,7 @@ export class TextModel implements editorCommon.ITextModel {
protected readonly _isTooLargeForTokenization: boolean;
constructor(rawTextSource: IRawTextSource, creationOptions: editorCommon.ITextModelCreationOptions) {
this._eventEmitter = new OrderGuaranteeEventEmitter();
super();
const textModelData = TextModel.resolveCreationData(rawTextSource, creationOptions);
@@ -167,7 +173,7 @@ export class TextModel implements editorCommon.ITextModel {
let e = this._options.createChangeEvent(newOpts);
this._options = newOpts;
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelOptionsChanged, e);
this._onDidChangeOptions.fire(e);
}
public detectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void {
@@ -296,11 +302,11 @@ export class TextModel implements editorCommon.ITextModel {
this._EOL = null;
this._BOM = null;
this._eventEmitter.dispose();
super.dispose();
}
private _emitContentChanged2(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string, isUndoing: boolean, isRedoing: boolean, isFlush: boolean): void {
const e: textModelEvents.IModelContentChangedEvent = {
private _createContentChanged2(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, rangeLength: number, text: string, isUndoing: boolean, isRedoing: boolean, isFlush: boolean): IModelContentChangedEvent {
return {
changes: [{
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
rangeLength: rangeLength,
@@ -312,9 +318,6 @@ export class TextModel implements editorCommon.ITextModel {
isRedoing: isRedoing,
isFlush: isFlush
};
if (!this._isDisposing) {
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelContentChanged, e);
}
}
protected _resetValue(newValue: ITextSource): void {
@@ -364,18 +367,17 @@ export class TextModel implements editorCommon.ITextModel {
this._resetValue(newValue);
this._emitModelRawContentChangedEvent(
new textModelEvents.ModelRawContentChangedEvent(
this._emitContentChangedEvent(
new ModelRawContentChangedEvent(
[
new textModelEvents.ModelRawFlush()
new ModelRawFlush()
],
this._versionId,
false,
false
)
),
this._createContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false, true)
);
this._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false, true);
}
public getValue(eol?: editorCommon.EndOfLinePreference, preserveBOM: boolean = false): string {
@@ -519,18 +521,17 @@ export class TextModel implements editorCommon.ITextModel {
this._increaseVersionId();
this._onAfterEOLChange();
this._emitModelRawContentChangedEvent(
new textModelEvents.ModelRawContentChangedEvent(
this._emitContentChangedEvent(
new ModelRawContentChangedEvent(
[
new textModelEvents.ModelRawEOLChanged()
new ModelRawEOLChanged()
],
this._versionId,
false,
false
)
),
this._createContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false, false)
);
this._emitContentChanged2(1, 1, endLineNumber, endColumn, oldModelValueLength, this.getValue(), false, false, false);
}
public getLineMinColumn(lineNumber: number): number {
@@ -573,17 +574,6 @@ export class TextModel implements editorCommon.ITextModel {
return result + 2;
}
public validateLineNumber(lineNumber: number): number {
this._assertNotDisposed();
if (lineNumber < 1) {
lineNumber = 1;
}
if (lineNumber > this._lines.length) {
lineNumber = this._lines.length;
}
return lineNumber;
}
/**
* Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.
* Will try to not allocate if possible.
@@ -750,12 +740,12 @@ export class TextModel implements editorCommon.ITextModel {
return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
}
protected _emitModelRawContentChangedEvent(e: textModelEvents.ModelRawContentChangedEvent): void {
protected _emitContentChangedEvent(rawChange: ModelRawContentChangedEvent, change: IModelContentChangedEvent): void {
if (this._isDisposing) {
// Do not confuse listeners by emitting any event after disposing
return;
}
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelRawContentChanged2, e);
this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));
}
private _constructLines(textSource: ITextSource): void {
@@ -820,3 +810,39 @@ export class TextModel implements editorCommon.ITextModel {
return TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
}
}
export class DidChangeContentEmitter extends Disposable {
private readonly _actual: Emitter<InternalModelContentChangeEvent> = this._register(new Emitter<InternalModelContentChangeEvent>());
public readonly event: Event<InternalModelContentChangeEvent> = this._actual.event;
private _deferredCnt: number;
private _deferredEvents: InternalModelContentChangeEvent[];
constructor() {
super();
this._deferredCnt = 0;
this._deferredEvents = [];
}
public beginDeferredEmit(): void {
this._deferredCnt++;
}
public endDeferredEmit(): void {
this._deferredCnt--;
if (this._deferredCnt === 0) {
while (this._deferredEvents.length > 0) {
this._actual.fire(this._deferredEvents.shift());
}
}
}
public fire(e: InternalModelContentChangeEvent): void {
if (this._deferredCnt > 0) {
this._deferredEvents.push(e);
return;
}
this._actual.fire(e);
}
}

View File

@@ -7,20 +7,6 @@
import { IRange } from 'vs/editor/common/core/range';
/**
* @internal
*/
export const TextModelEventType = {
ModelDispose: 'modelDispose',
ModelTokensChanged: 'modelTokensChanged',
ModelLanguageChanged: 'modelLanguageChanged',
ModelOptionsChanged: 'modelOptionsChanged',
ModelContentChanged: 'contentChanged',
ModelRawContentChanged2: 'rawContentChanged2',
ModelDecorationsChanged: 'decorationsChanged',
ModelLanguageConfigurationChanged: 'modelLanguageConfigurationChanged'
};
/**
* An event describing that the current mode associated with a model has changed.
*/
@@ -249,3 +235,13 @@ export class ModelRawContentChangedEvent {
return false;
}
}
/**
* @internal
*/
export class InternalModelContentChangeEvent {
constructor(
public readonly rawContentChangedEvent: ModelRawContentChangedEvent,
public readonly contentChangedEvent: IModelContentChangedEvent,
) { }
}

View File

@@ -5,17 +5,19 @@
'use strict';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import * as strings from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
import Event, { Emitter } from 'vs/base/common/event';
import { Range, IRange } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { TextModelWithTokens } from 'vs/editor/common/model/textModelWithTokens';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { IModelDecorationsChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { IntervalNode, IntervalTree, recomputeMaxEnd, getNodeIsInOverviewRuler } from 'vs/editor/common/model/intervalTree';
import { Disposable } from 'vs/base/common/lifecycle';
let _INSTANCE_COUNT = 0;
/**
@@ -36,14 +38,15 @@ function nextInstanceId(): string {
export class TextModelWithDecorations extends TextModelWithTokens implements editorCommon.ITextModelWithDecorations {
protected readonly _onDidChangeDecorations: DidChangeDecorationsEmitter = this._register(new DidChangeDecorationsEmitter());
public readonly onDidChangeDecorations: Event<IModelDecorationsChangedEvent> = this._onDidChangeDecorations.event;
/**
* Used to workaround broken clients that might attempt using a decoration id generated by a different model.
* It is not globally unique in order to limit it to one character.
*/
private readonly _instanceId: string;
private _lastDecorationId: number;
private _currentDecorationsTrackerCnt: number;
private _currentDecorationsTrackerDidChange: boolean;
private _decorations: { [decorationId: string]: IntervalNode; };
private _decorationsTree: DecorationsTrees;
@@ -52,8 +55,6 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
this._instanceId = nextInstanceId();
this._lastDecorationId = 0;
this._currentDecorationsTrackerCnt = 0;
this._currentDecorationsTrackerDidChange = false;
this._decorations = Object.create(null);
this._decorationsTree = new DecorationsTrees();
}
@@ -73,30 +74,10 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
this._decorationsTree = new DecorationsTrees();
}
_getTrackedRangesCount(): number {
return this._decorationsTree.count();
}
// --- END TrackedRanges
protected _acquireDecorationsTracker(): void {
if (this._currentDecorationsTrackerCnt === 0) {
this._currentDecorationsTrackerDidChange = false;
}
this._currentDecorationsTrackerCnt++;
}
protected _releaseDecorationsTracker(): void {
this._currentDecorationsTrackerCnt--;
if (this._currentDecorationsTrackerCnt === 0) {
if (this._currentDecorationsTrackerDidChange) {
this._emitModelDecorationsChangedEvent();
}
}
}
protected _adjustDecorationsForEdit(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
this._decorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
}
@@ -138,31 +119,29 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
this._assertNotDisposed();
try {
this._eventEmitter.beginDeferredEmit();
this._acquireDecorationsTracker();
this._onDidChangeDecorations.beginDeferredEmit();
return this._changeDecorations(ownerId, callback);
} finally {
this._releaseDecorationsTracker();
this._eventEmitter.endDeferredEmit();
this._onDidChangeDecorations.endDeferredEmit();
}
}
private _changeDecorations<T>(ownerId: number, callback: (changeAccessor: editorCommon.IModelDecorationsChangeAccessor) => T): T {
let changeAccessor: editorCommon.IModelDecorationsChangeAccessor = {
addDecoration: (range: IRange, options: editorCommon.IModelDecorationOptions): string => {
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
return this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0];
},
changeDecoration: (id: string, newRange: IRange): void => {
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
this._changeDecorationImpl(id, newRange);
},
changeDecorationOptions: (id: string, options: editorCommon.IModelDecorationOptions) => {
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
this._changeDecorationOptionsImpl(id, _normalizeOptions(options));
},
removeDecoration: (id: string): void => {
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
this._deltaDecorationsImpl(ownerId, [id], []);
},
deltaDecorations: (oldDecorations: string[], newDecorations: editorCommon.IModelDeltaDecoration[]): string[] => {
@@ -170,7 +149,7 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
// nothing to do
return [];
}
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.fire();
return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
}
};
@@ -199,13 +178,11 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
}
try {
this._eventEmitter.beginDeferredEmit();
this._acquireDecorationsTracker();
this._currentDecorationsTrackerDidChange = true;
this._onDidChangeDecorations.beginDeferredEmit();
this._onDidChangeDecorations.fire();
return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
} finally {
this._releaseDecorationsTracker();
this._eventEmitter.endDeferredEmit();
this._onDidChangeDecorations.endDeferredEmit();
}
}
@@ -312,13 +289,6 @@ export class TextModelWithDecorations extends TextModelWithTokens implements edi
return this._ensureNodesHaveRanges(result);
}
private _emitModelDecorationsChangedEvent(): void {
if (!this._isDisposing) {
let e: textModelEvents.IModelDecorationsChangedEvent = {};
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelDecorationsChanged, e);
}
}
private _getDecorationsInRange(filterRange: Range, filterOwnerId: number, filterOutValidation: boolean): IntervalNode[] {
const startOffset = this._lineStarts.getAccumulatedValue(filterRange.startLineNumber - 2) + filterRange.startColumn - 1;
const endOffset = this._lineStarts.getAccumulatedValue(filterRange.endLineNumber - 2) + filterRange.endColumn - 1;
@@ -479,12 +449,6 @@ class DecorationsTrees {
}
}
public count(): number {
const c0 = this._decorationsTree0.count();
const c1 = this._decorationsTree1.count();
return c0 + c1;
}
public collectNodesFromOwner(ownerId: number): IntervalNode[] {
const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);
const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);
@@ -559,15 +523,6 @@ export class ModelDecorationOverviewRulerOptions implements editorCommon.IModelD
this.position = options.position;
}
}
public equals(other: ModelDecorationOverviewRulerOptions): boolean {
return (
this.color === other.color
&& this.darkColor === other.darkColor
&& this.hcColor === other.hcColor
&& this.position === other.position
);
}
}
let lastStaticId = 0;
@@ -615,28 +570,6 @@ export class ModelDecorationOptions implements editorCommon.IModelDecorationOpti
this.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : strings.empty;
this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : strings.empty;
}
public equals(other: ModelDecorationOptions): boolean {
if (this.staticId > 0 || other.staticId > 0) {
return this.staticId === other.staticId;
}
return (
this.stickiness === other.stickiness
&& this.className === other.className
&& this.isWholeLine === other.isWholeLine
&& this.showIfCollapsed === other.showIfCollapsed
&& this.glyphMarginClassName === other.glyphMarginClassName
&& this.linesDecorationsClassName === other.linesDecorationsClassName
&& this.marginClassName === other.marginClassName
&& this.inlineClassName === other.inlineClassName
&& this.beforeContentClassName === other.beforeContentClassName
&& this.afterContentClassName === other.afterContentClassName
&& markedStringsEquals(this.hoverMessage, other.hoverMessage)
&& markedStringsEquals(this.glyphMarginHoverMessage, other.glyphMarginHoverMessage)
&& this.overviewRuler.equals(other.overviewRuler)
);
}
}
ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({});
@@ -656,3 +589,36 @@ function _normalizeOptions(options: editorCommon.IModelDecorationOptions): Model
}
return ModelDecorationOptions.createDynamic(options);
}
export class DidChangeDecorationsEmitter extends Disposable {
private readonly _actual: Emitter<IModelDecorationsChangedEvent> = this._register(new Emitter<IModelDecorationsChangedEvent>());
public readonly event: Event<IModelDecorationsChangedEvent> = this._actual.event;
private _deferredCnt: number;
private _shouldFire: boolean;
constructor() {
super();
this._deferredCnt = 0;
this._shouldFire = false;
}
public beginDeferredEmit(): void {
this._deferredCnt++;
}
public endDeferredEmit(): void {
this._deferredCnt--;
if (this._deferredCnt === 0) {
if (this._shouldFire) {
this._shouldFire = false;
this._actual.fire({});
}
}
}
public fire(): void {
this._shouldFire = true;
}
}

View File

@@ -8,6 +8,7 @@ import * as nls from 'vs/nls';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IDisposable } from 'vs/base/common/lifecycle';
import { StopWatch } from 'vs/base/common/stopwatch';
import Event, { Emitter } from 'vs/base/common/event';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { TextModel } from 'vs/editor/common/model/textModel';
@@ -21,8 +22,7 @@ import { LineTokens, LineToken } from 'vs/editor/common/core/lineTokens';
import { getWordAtText } from 'vs/editor/common/model/wordHelper';
import { TokenizationResult2 } from 'vs/editor/common/core/token';
import { ITextSource, IRawTextSource } from 'vs/editor/common/model/textSource';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { IndentRanges, computeRanges } from 'vs/editor/common/model/indentRanges';
import { IModelTokensChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { computeIndentLevel } from 'vs/editor/common/model/modelLine';
class ModelTokensChangedEventBuilder {
@@ -50,7 +50,7 @@ class ModelTokensChangedEventBuilder {
}
}
public build(): textModelEvents.IModelTokensChangedEvent {
public build(): IModelTokensChangedEvent {
if (this._ranges.length === 0) {
return null;
}
@@ -62,7 +62,16 @@ class ModelTokensChangedEventBuilder {
export class TextModelWithTokens extends TextModel implements editorCommon.ITokenizedModel {
private static MODE_TOKENIZATION_FAILED_MSG = nls.localize('mode.tokenizationSupportFailed', "The mode has failed while tokenizing the input.");
private static readonly MODE_TOKENIZATION_FAILED_MSG = nls.localize('mode.tokenizationSupportFailed', "The mode has failed while tokenizing the input.");
private readonly _onDidChangeLanguage: Emitter<IModelLanguageChangedEvent> = this._register(new Emitter<IModelLanguageChangedEvent>());
public readonly onDidChangeLanguage: Event<IModelLanguageChangedEvent> = this._onDidChangeLanguage.event;
private readonly _onDidChangeLanguageConfiguration: Emitter<IModelLanguageConfigurationChangedEvent> = this._register(new Emitter<IModelLanguageConfigurationChangedEvent>());
public readonly onDidChangeLanguageConfiguration: Event<IModelLanguageConfigurationChangedEvent> = this._onDidChangeLanguageConfiguration.event;
private readonly _onDidChangeTokens: Emitter<IModelTokensChangedEvent> = this._register(new Emitter<IModelTokensChangedEvent>());
public readonly onDidChangeTokens: Event<IModelTokensChangedEvent> = this._onDidChangeTokens.event;
private _languageIdentifier: LanguageIdentifier;
private _tokenizationListener: IDisposable;
@@ -71,7 +80,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
private _invalidLineStartIndex: number;
private _lastState: IState;
private _indentRanges: IndentRanges;
private _languageRegistryListener: IDisposable;
private _revalidateTokensTimeout: number;
@@ -102,13 +110,11 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
this._languageRegistryListener = LanguageConfigurationRegistry.onDidChange((e) => {
if (e.languageIdentifier.id === this._languageIdentifier.id) {
this._resetIndentRanges();
this._emitModelLanguageConfigurationEvent({});
this._onDidChangeLanguageConfiguration.fire({});
}
});
this._resetTokenizationState();
this._resetIndentRanges();
}
public dispose(): void {
@@ -128,7 +134,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
super._resetValue(newValue);
// Cancel tokenization, clear all tokens and begin tokenizing
this._resetTokenizationState();
this._resetIndentRanges();
}
protected _resetTokenizationState(): void {
@@ -169,29 +174,19 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
}
}
private _withModelTokensChangedEventBuilder<T>(callback: (eventBuilder: ModelTokensChangedEventBuilder) => T): T {
let eventBuilder = new ModelTokensChangedEventBuilder();
let result = callback(eventBuilder);
if (!this._isDisposing) {
let e = eventBuilder.build();
if (e) {
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelTokensChanged, e);
}
}
return result;
}
public forceTokenization(lineNumber: number): void {
if (lineNumber < 1 || lineNumber > this.getLineCount()) {
throw new Error('Illegal value ' + lineNumber + ' for `lineNumber`');
}
this._withModelTokensChangedEventBuilder((eventBuilder) => {
this._updateTokensUntilLine(eventBuilder, lineNumber);
});
const eventBuilder = new ModelTokensChangedEventBuilder();
this._updateTokensUntilLine(eventBuilder, lineNumber);
const e = eventBuilder.build();
if (e) {
this._onDidChangeTokens.fire(e);
}
}
public isCheapToTokenize(lineNumber: number): boolean {
@@ -231,7 +226,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
return;
}
let e: textModelEvents.IModelLanguageChangedEvent = {
let e: IModelLanguageChangedEvent = {
oldLanguage: this._languageIdentifier.language,
newLanguage: languageIdentifier.language
};
@@ -240,7 +235,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
// Cancel tokenization, clear all tokens and begin tokenizing
this._resetTokenizationState();
this._resetIndentRanges();
this.emitModelTokensChangedEvent({
ranges: [{
@@ -248,8 +242,8 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
toLineNumber: this.getLineCount()
}]
});
this._emitModelModeChangedEvent(e);
this._emitModelLanguageConfigurationEvent({});
this._onDidChangeLanguage.fire(e);
this._onDidChangeLanguageConfiguration.fire({});
}
public getLanguageIdAtPosition(_lineNumber: number, _column: number): LanguageId {
@@ -295,56 +289,60 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
private _revalidateTokensNow(toLineNumber: number = this._invalidLineStartIndex + 1000000): void {
this._withModelTokensChangedEventBuilder((eventBuilder) => {
const eventBuilder = new ModelTokensChangedEventBuilder();
toLineNumber = Math.min(this._lines.length, toLineNumber);
toLineNumber = Math.min(this._lines.length, toLineNumber);
var MAX_ALLOWED_TIME = 20,
fromLineNumber = this._invalidLineStartIndex + 1,
tokenizedChars = 0,
currentCharsToTokenize = 0,
currentEstimatedTimeToTokenize = 0,
sw = StopWatch.create(false),
elapsedTime: number;
var MAX_ALLOWED_TIME = 20,
fromLineNumber = this._invalidLineStartIndex + 1,
tokenizedChars = 0,
currentCharsToTokenize = 0,
currentEstimatedTimeToTokenize = 0,
sw = StopWatch.create(false),
elapsedTime: number;
// Tokenize at most 1000 lines. Estimate the tokenization speed per character and stop when:
// - MAX_ALLOWED_TIME is reached
// - tokenizing the next line would go above MAX_ALLOWED_TIME
// Tokenize at most 1000 lines. Estimate the tokenization speed per character and stop when:
// - MAX_ALLOWED_TIME is reached
// - tokenizing the next line would go above MAX_ALLOWED_TIME
for (var lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {
elapsedTime = sw.elapsed();
if (elapsedTime > MAX_ALLOWED_TIME) {
// Stop if MAX_ALLOWED_TIME is reached
for (var lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {
elapsedTime = sw.elapsed();
if (elapsedTime > MAX_ALLOWED_TIME) {
// Stop if MAX_ALLOWED_TIME is reached
toLineNumber = lineNumber - 1;
break;
}
// Compute how many characters will be tokenized for this line
currentCharsToTokenize = this._lines[lineNumber - 1].text.length;
if (tokenizedChars > 0) {
// If we have enough history, estimate how long tokenizing this line would take
currentEstimatedTimeToTokenize = (elapsedTime / tokenizedChars) * currentCharsToTokenize;
if (elapsedTime + currentEstimatedTimeToTokenize > MAX_ALLOWED_TIME) {
// Tokenizing this line will go above MAX_ALLOWED_TIME
toLineNumber = lineNumber - 1;
break;
}
// Compute how many characters will be tokenized for this line
currentCharsToTokenize = this._lines[lineNumber - 1].text.length;
if (tokenizedChars > 0) {
// If we have enough history, estimate how long tokenizing this line would take
currentEstimatedTimeToTokenize = (elapsedTime / tokenizedChars) * currentCharsToTokenize;
if (elapsedTime + currentEstimatedTimeToTokenize > MAX_ALLOWED_TIME) {
// Tokenizing this line will go above MAX_ALLOWED_TIME
toLineNumber = lineNumber - 1;
break;
}
}
this._updateTokensUntilLine(eventBuilder, lineNumber);
tokenizedChars += currentCharsToTokenize;
// Skip the lines that got tokenized
lineNumber = Math.max(lineNumber, this._invalidLineStartIndex + 1);
}
elapsedTime = sw.elapsed();
this._updateTokensUntilLine(eventBuilder, lineNumber);
tokenizedChars += currentCharsToTokenize;
if (this._invalidLineStartIndex < this._lines.length) {
this._beginBackgroundTokenization();
}
});
// Skip the lines that got tokenized
lineNumber = Math.max(lineNumber, this._invalidLineStartIndex + 1);
}
elapsedTime = sw.elapsed();
if (this._invalidLineStartIndex < this._lines.length) {
this._beginBackgroundTokenization();
}
const e = eventBuilder.build();
if (e) {
this._onDidChangeTokens.fire(e);
}
}
private _updateTokensUntilLine(eventBuilder: ModelTokensChangedEventBuilder, lineNumber: number): void {
@@ -409,21 +407,9 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
this._invalidLineStartIndex = Math.max(this._invalidLineStartIndex, endLineIndex + 1);
}
private emitModelTokensChangedEvent(e: textModelEvents.IModelTokensChangedEvent): void {
private emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void {
if (!this._isDisposing) {
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelTokensChanged, e);
}
}
private _emitModelLanguageConfigurationEvent(e: textModelEvents.IModelLanguageConfigurationChangedEvent): void {
if (!this._isDisposing) {
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged, e);
}
}
private _emitModelModeChangedEvent(e: textModelEvents.IModelLanguageChangedEvent): void {
if (!this._isDisposing) {
this._eventEmitter.emit(textModelEvents.TextModelEventType.ModelLanguageChanged, e);
this._onDidChangeTokens.fire(e);
}
}
@@ -431,10 +417,10 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
public getWordAtPosition(_position: IPosition): editorCommon.IWordAtPosition {
this._assertNotDisposed();
let position = this.validatePosition(_position);
let lineContent = this.getLineContent(position.lineNumber);
const position = this.validatePosition(_position);
const lineContent = this.getLineContent(position.lineNumber);
if (this._invalidLineStartIndex <= position.lineNumber) {
if (this._invalidLineStartIndex <= position.lineNumber - 1) {
// this line is not tokenized
return getWordAtText(
position.column,
@@ -444,30 +430,29 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
);
}
let lineTokens = this._getLineTokens(position.lineNumber);
let offset = position.column - 1;
let token = lineTokens.findTokenAtOffset(offset);
const lineTokens = this._getLineTokens(position.lineNumber);
const offset = position.column - 1;
const token = lineTokens.findTokenAtOffset(offset);
const languageId = token.languageId;
let result = getWordAtText(
position.column,
LanguageConfigurationRegistry.getWordDefinition(token.languageId),
lineContent.substring(token.startOffset, token.endOffset),
token.startOffset
);
if (!result && token.hasPrev && token.startOffset === offset) {
// The position is right at the beginning of `modeIndex`, so try looking at `modeIndex` - 1 too
let prevToken = token.prev();
result = getWordAtText(
position.column,
LanguageConfigurationRegistry.getWordDefinition(prevToken.languageId),
lineContent.substring(prevToken.startOffset, prevToken.endOffset),
prevToken.startOffset
);
// go left until a different language is hit
let startOffset: number;
for (let leftToken = token.clone(); leftToken !== null && leftToken.languageId === languageId; leftToken = leftToken.prev()) {
startOffset = leftToken.startOffset;
}
return result;
// go right until a different language is hit
let endOffset: number;
for (let rightToken = token.clone(); rightToken !== null && rightToken.languageId === languageId; rightToken = rightToken.next()) {
endOffset = rightToken.endOffset;
}
return getWordAtText(
position.column,
LanguageConfigurationRegistry.getWordDefinition(languageId),
lineContent.substring(startOffset, endOffset),
startOffset
);
}
public getWordUntilPosition(position: IPosition): editorCommon.IWordAtPosition {
@@ -516,7 +501,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
let lineTokens = this._getLineTokens(lineNumber);
const lineText = this._lines[lineNumber - 1].text;
const currentToken = lineTokens.findTokenAtOffset(position.column - 1);
let currentToken = lineTokens.findTokenAtOffset(position.column - 1);
if (!currentToken) {
return null;
}
@@ -570,14 +555,14 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
// If position is in between two tokens, try also looking in the previous token
if (currentToken.hasPrev && currentToken.startOffset === position.column - 1) {
const prevToken = currentToken.prev();
const prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(prevToken.languageId);
const searchEndOffset = currentToken.startOffset;
currentToken = currentToken.prev();
const prevModeBrackets = LanguageConfigurationRegistry.getBracketsSupport(currentToken.languageId);
// check that previous token is not to be ignored
if (prevModeBrackets && !ignoreBracketsInToken(prevToken.tokenType)) {
if (prevModeBrackets && !ignoreBracketsInToken(currentToken.tokenType)) {
// limit search in case previous token is very large, there's no need to go beyond `maxBracketLength`
const searchStartOffset = Math.max(prevToken.startOffset, position.column - 1 - prevModeBrackets.maxBracketLength);
const searchEndOffset = currentToken.startOffset;
const searchStartOffset = Math.max(currentToken.startOffset, position.column - 1 - prevModeBrackets.maxBracketLength);
const foundBracket = BracketsUtils.findPrevBracketInToken(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);
// check that we didn't hit a bracket too far away from position
@@ -838,24 +823,6 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
};
}
protected _resetIndentRanges(): void {
this._indentRanges = null;
}
private _getIndentRanges(): IndentRanges {
if (!this._indentRanges) {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id);
let offSide = foldingRules && foldingRules.offSide;
let markers = foldingRules && foldingRules.markers;
this._indentRanges = computeRanges(this, offSide, markers);
}
return this._indentRanges;
}
public getIndentRanges(): IndentRanges {
return this._getIndentRanges();
}
private _computeIndentLevel(lineIndex: number): number {
return computeIndentLevel(this._lines[lineIndex].text, this._options.tabSize);
}

View File

@@ -16,6 +16,7 @@ import { Range, IRange } from 'vs/editor/common/core/range';
import Event from 'vs/base/common/event';
import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationRegistry';
import { Color } from 'vs/base/common/color';
import { IMarkerData } from 'vs/platform/markers/common/markers';
/**
* Open ended enum at runtime
@@ -275,6 +276,13 @@ export interface ISuggestSupport {
resolveCompletionItem?(model: editorCommon.IModel, position: Position, item: ISuggestion, token: CancellationToken): ISuggestion | Thenable<ISuggestion>;
}
export interface CodeAction {
title: string;
command?: Command;
edits?: WorkspaceEdit;
diagnostics?: IMarkerData[];
}
/**
* The code action interface defines the contract between extensions and
* the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature.
@@ -284,7 +292,7 @@ export interface CodeActionProvider {
/**
* Provide commands for the given document and range.
*/
provideCodeActions(model: editorCommon.IReadOnlyModel, range: Range, token: CancellationToken): Command[] | Thenable<Command[]>;
provideCodeActions(model: editorCommon.IReadOnlyModel, range: Range, token: CancellationToken): CodeAction[] | Thenable<CodeAction[]>;
}
/**
@@ -908,7 +916,7 @@ export interface ITokenizationRegistry {
setColorMap(colorMap: Color[]): void;
getColorMap(): Color[];
getDefaultForeground(): Color;
getDefaultBackground(): Color;
}

View File

@@ -1,130 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import * as modes from 'vs/editor/common/modes';
import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { Schemas } from 'vs/base/common/network';
export class EditorModeContext extends Disposable {
private _editor: ICommonCodeEditor;
private _langId: IContextKey<string>;
private _hasCompletionItemProvider: IContextKey<boolean>;
private _hasCodeActionsProvider: IContextKey<boolean>;
private _hasCodeLensProvider: IContextKey<boolean>;
private _hasDefinitionProvider: IContextKey<boolean>;
private _hasImplementationProvider: IContextKey<boolean>;
private _hasTypeDefinitionProvider: IContextKey<boolean>;
private _hasHoverProvider: IContextKey<boolean>;
private _hasDocumentHighlightProvider: IContextKey<boolean>;
private _hasDocumentSymbolProvider: IContextKey<boolean>;
private _hasReferenceProvider: IContextKey<boolean>;
private _hasRenameProvider: IContextKey<boolean>;
private _hasDocumentFormattingProvider: IContextKey<boolean>;
private _hasDocumentSelectionFormattingProvider: IContextKey<boolean>;
private _hasSignatureHelpProvider: IContextKey<boolean>;
private _isInWalkThrough: IContextKey<boolean>;
constructor(
editor: ICommonCodeEditor,
contextKeyService: IContextKeyService
) {
super();
this._editor = editor;
this._langId = EditorContextKeys.languageId.bindTo(contextKeyService);
this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(contextKeyService);
this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(contextKeyService);
this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(contextKeyService);
this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(contextKeyService);
this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(contextKeyService);
this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(contextKeyService);
this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(contextKeyService);
this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(contextKeyService);
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(contextKeyService);
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(contextKeyService);
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(contextKeyService);
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(contextKeyService);
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(contextKeyService);
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(contextKeyService);
this._isInWalkThrough = EditorContextKeys.isInEmbeddedEditor.bindTo(contextKeyService);
const update = () => this._update();
// update when model/mode changes
this._register(editor.onDidChangeModel(update));
this._register(editor.onDidChangeModelLanguage(update));
// update when registries change
this._register(modes.SuggestRegistry.onDidChange(update));
this._register(modes.CodeActionProviderRegistry.onDidChange(update));
this._register(modes.CodeLensProviderRegistry.onDidChange(update));
this._register(modes.DefinitionProviderRegistry.onDidChange(update));
this._register(modes.ImplementationProviderRegistry.onDidChange(update));
this._register(modes.TypeDefinitionProviderRegistry.onDidChange(update));
this._register(modes.HoverProviderRegistry.onDidChange(update));
this._register(modes.DocumentHighlightProviderRegistry.onDidChange(update));
this._register(modes.DocumentSymbolProviderRegistry.onDidChange(update));
this._register(modes.ReferenceProviderRegistry.onDidChange(update));
this._register(modes.RenameProviderRegistry.onDidChange(update));
this._register(modes.DocumentFormattingEditProviderRegistry.onDidChange(update));
this._register(modes.DocumentRangeFormattingEditProviderRegistry.onDidChange(update));
this._register(modes.SignatureHelpProviderRegistry.onDidChange(update));
update();
}
dispose() {
super.dispose();
}
reset() {
this._langId.reset();
this._hasCompletionItemProvider.reset();
this._hasCodeActionsProvider.reset();
this._hasCodeLensProvider.reset();
this._hasDefinitionProvider.reset();
this._hasImplementationProvider.reset();
this._hasTypeDefinitionProvider.reset();
this._hasHoverProvider.reset();
this._hasDocumentHighlightProvider.reset();
this._hasDocumentSymbolProvider.reset();
this._hasReferenceProvider.reset();
this._hasRenameProvider.reset();
this._hasDocumentFormattingProvider.reset();
this._hasDocumentSelectionFormattingProvider.reset();
this._hasSignatureHelpProvider.reset();
this._isInWalkThrough.reset();
}
private _update() {
const model = this._editor.getModel();
if (!model) {
this.reset();
return;
}
this._langId.set(model.getLanguageIdentifier().language);
this._hasCompletionItemProvider.set(modes.SuggestRegistry.has(model));
this._hasCodeActionsProvider.set(modes.CodeActionProviderRegistry.has(model));
this._hasCodeLensProvider.set(modes.CodeLensProviderRegistry.has(model));
this._hasDefinitionProvider.set(modes.DefinitionProviderRegistry.has(model));
this._hasImplementationProvider.set(modes.ImplementationProviderRegistry.has(model));
this._hasTypeDefinitionProvider.set(modes.TypeDefinitionProviderRegistry.has(model));
this._hasHoverProvider.set(modes.HoverProviderRegistry.has(model));
this._hasDocumentHighlightProvider.set(modes.DocumentHighlightProviderRegistry.has(model));
this._hasDocumentSymbolProvider.set(modes.DocumentSymbolProviderRegistry.has(model));
this._hasReferenceProvider.set(modes.ReferenceProviderRegistry.has(model));
this._hasRenameProvider.set(modes.RenameProviderRegistry.has(model));
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
}
}

View File

@@ -18,7 +18,7 @@ import { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common
import { createScopedLineTokens } from 'vs/editor/common/modes/supports';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
import { Range } from 'vs/editor/common/core/range';
import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule, FoldingRules } from 'vs/editor/common/modes/languageConfiguration';
import { IndentAction, EnterAction, IAutoClosingPair, LanguageConfiguration, IndentationRule, FoldingRules, IAutoClosingPairConditional } from 'vs/editor/common/modes/languageConfiguration';
import { LanguageIdentifier, LanguageId } from 'vs/editor/common/modes';
/**
@@ -46,18 +46,23 @@ export interface IIndentConverter {
export class RichEditSupport {
private readonly _conf: LanguageConfiguration;
private readonly _languageIdentifier: LanguageIdentifier;
private _brackets: RichEditBrackets;
private _electricCharacter: BracketElectricCharacterSupport;
public readonly electricCharacter: BracketElectricCharacterSupport;
public readonly comments: ICommentsConfiguration;
public readonly characterPair: CharacterPairSupport;
public readonly wordDefinition: RegExp;
public readonly onEnter: OnEnterSupport;
public readonly indentRulesSupport: IndentRulesSupport;
public readonly brackets: RichEditBrackets;
public readonly indentationRules: IndentationRule;
public readonly foldingRules: FoldingRules;
constructor(languageIdentifier: LanguageIdentifier, previous: RichEditSupport, rawConf: LanguageConfiguration) {
this._languageIdentifier = languageIdentifier;
this._brackets = null;
this._electricCharacter = null;
let prev: LanguageConfiguration = null;
if (previous) {
@@ -66,16 +71,11 @@ export class RichEditSupport {
this._conf = RichEditSupport._mergeConf(prev, rawConf);
if (this._conf.brackets) {
this.brackets = new RichEditBrackets(languageIdentifier, this._conf.brackets);
}
this.onEnter = RichEditSupport._handleOnEnter(this._conf);
this.comments = RichEditSupport._handleComments(this._conf);
this.characterPair = new CharacterPairSupport(this._conf);
this.electricCharacter = new BracketElectricCharacterSupport(this.brackets, this.characterPair.getAutoClosingPairs(), this._conf.__electricCharacterSupport);
this.wordDefinition = this._conf.wordPattern || DEFAULT_WORD_REGEXP;
@@ -87,6 +87,29 @@ export class RichEditSupport {
this.foldingRules = this._conf.folding || {};
}
public get brackets(): RichEditBrackets {
if (!this._brackets && this._conf.brackets) {
this._brackets = new RichEditBrackets(this._languageIdentifier, this._conf.brackets);
}
return this._brackets;
}
public get electricCharacter(): BracketElectricCharacterSupport {
if (!this._electricCharacter) {
let autoClosingPairs: IAutoClosingPairConditional[] = [];
if (this._conf.autoClosingPairs) {
autoClosingPairs = this._conf.autoClosingPairs;
} else if (this._conf.brackets) {
autoClosingPairs = this._conf.brackets.map(b => {
return { open: b[0], close: b[1] };
});
}
this._electricCharacter = new BracketElectricCharacterSupport(this.brackets, autoClosingPairs, this._conf.__electricCharacterSupport);
}
return this._electricCharacter;
}
private static _mergeConf(prev: LanguageConfiguration, current: LanguageConfiguration): LanguageConfiguration {
return {
comments: (prev ? current.comments || prev.comments : current.comments),
@@ -112,7 +135,6 @@ export class RichEditSupport {
}
if (conf.indentationRules) {
empty = false;
onEnter.indentationRules = conf.indentationRules;
}
if (conf.onEnterRules) {
empty = false;

View File

@@ -16,10 +16,6 @@ export interface LanguageFilter {
export type LanguageSelector = string | LanguageFilter | (string | LanguageFilter)[];
export default function matches(selection: LanguageSelector, uri: URI, language: string): boolean {
return score(selection, uri, language) > 0;
}
export function score(selector: LanguageSelector, candidateUri: URI, candidateLanguage: string): number {
if (Array.isArray(selector)) {

View File

@@ -71,10 +71,6 @@ export class ScopedLineTokens {
return this._actual.findTokenIndexAtOffset(offset + this.firstCharOffset) - this._firstTokenIndex;
}
public getTokenStartOffset(tokenIndex: number): number {
return this._actual.getTokenStartOffset(tokenIndex + this._firstTokenIndex) - this.firstCharOffset;
}
public getStandardTokenType(tokenIndex: number): modes.StandardTokenType {
return this._actual.getStandardTokenType(tokenIndex + this._firstTokenIndex);
}

View File

@@ -4,15 +4,14 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as strings from 'vs/base/common/strings';
import { IndentationRule, IndentAction } from 'vs/editor/common/modes/languageConfiguration';
import { IndentationRule } from 'vs/editor/common/modes/languageConfiguration';
export const enum IndentConsts {
INCREASE_MASK = 0b00000001,
DECREASE_MASK = 0b00000010,
INDENT_NEXTLINE_MASK = 0b00000100,
UNINDENT_MASK = 0b00001000,
};
}
export class IndentRulesSupport {
@@ -22,30 +21,6 @@ export class IndentRulesSupport {
this._indentationRules = indentationRules;
}
public onType(text: string): IndentAction {
if (this._indentationRules) {
if (this._indentationRules.unIndentedLinePattern && this._indentationRules.unIndentedLinePattern.test(text)) {
return null;
}
if (this._indentationRules.decreaseIndentPattern && this._indentationRules.decreaseIndentPattern.test(text)) {
return IndentAction.Outdent;
}
}
return null;
}
public containNonWhitespace(text: string): boolean {
// the text doesn't contain any non-whitespace character.
let nonWhitespaceIdx = strings.lastNonWhitespaceIndex(text);
if (nonWhitespaceIdx >= 0) {
return true;
}
return false;
}
public shouldIncrease(text: string): boolean {
if (this._indentationRules) {
if (this._indentationRules.increaseIndentPattern && this._indentationRules.increaseIndentPattern.test(text)) {
@@ -99,4 +74,3 @@ export class IndentRulesSupport {
return ret;
}
}

View File

@@ -9,7 +9,7 @@ import { IRange } from 'vs/editor/common/core/range';
export class BasicInplaceReplace {
public static INSTANCE = new BasicInplaceReplace();
public static readonly INSTANCE = new BasicInplaceReplace();
public navigateValueSet(range1: IRange, text1: string, range2: IRange, text2: string, up: boolean): IInplaceReplaceSupportResult {

View File

@@ -6,11 +6,10 @@
import { onUnexpectedError } from 'vs/base/common/errors';
import * as strings from 'vs/base/common/strings';
import { CharacterPair, IndentationRule, IndentAction, EnterAction, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { CharacterPair, IndentAction, EnterAction, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
export interface IOnEnterSupportOptions {
brackets?: CharacterPair[];
indentationRules?: IndentationRule;
regExpRules?: OnEnterRule[];
}
@@ -24,7 +23,6 @@ interface IProcessedBracketPair {
export class OnEnterSupport {
private readonly _brackets: IProcessedBracketPair[];
private readonly _indentationRules: IndentationRule;
private readonly _regExpRules: OnEnterRule[];
constructor(opts?: IOnEnterSupportOptions) {
@@ -44,7 +42,6 @@ export class OnEnterSupport {
};
});
this._regExpRules = opts.regExpRules || [];
this._indentationRules = opts.indentationRules;
}
public onEnter(oneLineAboveText: string, beforeEnterText: string, afterEnterText: string): EnterAction {
@@ -113,4 +110,3 @@ export class OnEnterSupport {
}
}
}

View File

@@ -280,14 +280,6 @@ export class ThemeTrieElementRule {
return new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);
}
public static cloneArr(arr: ThemeTrieElementRule[]): ThemeTrieElementRule[] {
let r: ThemeTrieElementRule[] = [];
for (let i = 0, len = arr.length; i < len; i++) {
r[i] = arr[i].clone();
}
return r;
}
public acceptOverwrite(fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {
if (fontStyle !== FontStyle.NotSet) {
this._fontStyle = fontStyle;

View File

@@ -60,10 +60,6 @@ export class TokenizationRegistryImpl implements ITokenizationRegistry {
return this._colorMap;
}
public getDefaultForeground(): Color {
return this._colorMap[ColorId.DefaultForeground];
}
public getDefaultBackground(): Color {
return this._colorMap[ColorId.DefaultBackground];
}

View File

@@ -1,158 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
import { ICommonCodeEditor, ICommonDiffEditor, IDecorationRenderOptions, IModelDecorationOptions, IModel } from 'vs/editor/common/editorCommon';
import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService';
export abstract class AbstractCodeEditorService implements ICodeEditorService {
_serviceBrand: any;
private _onCodeEditorAdd: Emitter<ICommonCodeEditor>;
private _onCodeEditorRemove: Emitter<ICommonCodeEditor>;
private _codeEditors: { [editorId: string]: ICommonCodeEditor; };
private _onDiffEditorAdd: Emitter<ICommonDiffEditor>;
private _onDiffEditorRemove: Emitter<ICommonDiffEditor>;
private _diffEditors: { [editorId: string]: ICommonDiffEditor; };
constructor() {
this._codeEditors = Object.create(null);
this._diffEditors = Object.create(null);
this._onCodeEditorAdd = new Emitter<ICommonCodeEditor>();
this._onCodeEditorRemove = new Emitter<ICommonCodeEditor>();
this._onDiffEditorAdd = new Emitter<ICommonDiffEditor>();
this._onDiffEditorRemove = new Emitter<ICommonDiffEditor>();
}
addCodeEditor(editor: ICommonCodeEditor): void {
this._codeEditors[editor.getId()] = editor;
this._onCodeEditorAdd.fire(editor);
}
get onCodeEditorAdd(): Event<ICommonCodeEditor> {
return this._onCodeEditorAdd.event;
}
removeCodeEditor(editor: ICommonCodeEditor): void {
if (delete this._codeEditors[editor.getId()]) {
this._onCodeEditorRemove.fire(editor);
}
}
get onCodeEditorRemove(): Event<ICommonCodeEditor> {
return this._onCodeEditorRemove.event;
}
getCodeEditor(editorId: string): ICommonCodeEditor {
return this._codeEditors[editorId] || null;
}
listCodeEditors(): ICommonCodeEditor[] {
return Object.keys(this._codeEditors).map(id => this._codeEditors[id]);
}
addDiffEditor(editor: ICommonDiffEditor): void {
this._diffEditors[editor.getId()] = editor;
this._onDiffEditorAdd.fire(editor);
}
get onDiffEditorAdd(): Event<ICommonDiffEditor> {
return this._onDiffEditorAdd.event;
}
removeDiffEditor(editor: ICommonDiffEditor): void {
if (delete this._diffEditors[editor.getId()]) {
this._onDiffEditorRemove.fire(editor);
}
}
get onDiffEditorRemove(): Event<ICommonDiffEditor> {
return this._onDiffEditorRemove.event;
}
getDiffEditor(editorId: string): ICommonDiffEditor {
return this._diffEditors[editorId] || null;
}
listDiffEditors(): ICommonDiffEditor[] {
return Object.keys(this._diffEditors).map(id => this._diffEditors[id]);
}
getFocusedCodeEditor(): ICommonCodeEditor {
let editorWithWidgetFocus: ICommonCodeEditor = null;
let editors = this.listCodeEditors();
for (let i = 0; i < editors.length; i++) {
let editor = editors[i];
if (editor.isFocused()) {
// bingo!
return editor;
}
if (editor.hasWidgetFocus()) {
editorWithWidgetFocus = editor;
}
}
return editorWithWidgetFocus;
}
abstract registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void;
abstract removeDecorationType(key: string): void;
abstract resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions;
private _transientWatchers: { [uri: string]: ModelTransientSettingWatcher; } = {};
public setTransientModelProperty(model: IModel, key: string, value: any): void {
const uri = model.uri.toString();
let w: ModelTransientSettingWatcher;
if (this._transientWatchers.hasOwnProperty(uri)) {
w = this._transientWatchers[uri];
} else {
w = new ModelTransientSettingWatcher(uri, model, this);
this._transientWatchers[uri] = w;
}
w.set(key, value);
}
public getTransientModelProperty(model: IModel, key: string): any {
const uri = model.uri.toString();
if (!this._transientWatchers.hasOwnProperty(uri)) {
return undefined;
}
return this._transientWatchers[uri].get(key);
}
_removeWatcher(w: ModelTransientSettingWatcher): void {
delete this._transientWatchers[w.uri];
}
}
export class ModelTransientSettingWatcher {
public readonly uri: string;
private readonly _values: { [key: string]: any; };
constructor(uri: string, model: IModel, owner: AbstractCodeEditorService) {
this.uri = uri;
this._values = {};
model.onWillDispose(() => owner._removeWatcher(this));
}
public set(key: string, value: any): void {
this._values[key] = value;
}
public get(key: string): any {
return this._values[key];
}
}

View File

@@ -1,391 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import { flatten } from 'vs/base/common/arrays';
import { IStringDictionary, forEach, values, groupBy, size } from 'vs/base/common/collections';
import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IFileService, IFileChange } from 'vs/platform/files/common/files';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Range, IRange } from 'vs/editor/common/core/range';
import { Selection, ISelection } from 'vs/editor/common/core/selection';
import { IIdentifiedSingleEditOperation, IModel, EndOfLineSequence, ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { IProgressRunner } from 'vs/platform/progress/common/progress';
export interface IResourceEdit {
resource: URI;
range?: IRange;
newText: string;
newEol?: EndOfLineSequence;
}
interface IRecording {
stop(): void;
hasChanged(resource: URI): boolean;
allChanges(): IFileChange[];
}
class ChangeRecorder {
private _fileService: IFileService;
constructor(fileService?: IFileService) {
this._fileService = fileService;
}
public start(): IRecording {
const changes: IStringDictionary<IFileChange[]> = Object.create(null);
let stop: IDisposable;
if (this._fileService) {
stop = this._fileService.onFileChanges((event) => {
event.changes.forEach(change => {
const key = String(change.resource);
let array = changes[key];
if (!array) {
changes[key] = array = [];
}
array.push(change);
});
});
}
return {
stop: () => { return stop && stop.dispose(); },
hasChanged: (resource: URI) => !!changes[resource.toString()],
allChanges: () => flatten(values(changes))
};
}
}
class EditTask implements IDisposable {
private _initialSelections: Selection[];
private _endCursorSelection: Selection;
private get _model(): IModel { return this._modelReference.object.textEditorModel; }
private _modelReference: IReference<ITextEditorModel>;
private _edits: IIdentifiedSingleEditOperation[];
private _newEol: EndOfLineSequence;
constructor(modelReference: IReference<ITextEditorModel>) {
this._endCursorSelection = null;
this._modelReference = modelReference;
this._edits = [];
}
public addEdit(edit: IResourceEdit): void {
if (typeof edit.newEol === 'number') {
// honor eol-change
this._newEol = edit.newEol;
}
if (edit.range || edit.newText) {
// create edit operation
let range: Range;
if (!edit.range) {
range = this._model.getFullModelRange();
} else {
range = Range.lift(edit.range);
}
this._edits.push(EditOperation.replaceMove(range, edit.newText));
}
}
public apply(): void {
if (this._edits.length > 0) {
this._edits = this._edits.map((value, index) => ({ value, index })).sort((a, b) => {
let ret = Range.compareRangesUsingStarts(a.value.range, b.value.range);
if (ret === 0) {
ret = a.index - b.index;
}
return ret;
}).map(element => element.value);
this._initialSelections = this._getInitialSelections();
this._model.pushStackElement();
this._model.pushEditOperations(this._initialSelections, this._edits, (edits) => this._getEndCursorSelections(edits));
this._model.pushStackElement();
}
if (this._newEol !== undefined) {
this._model.pushStackElement();
this._model.setEOL(this._newEol);
this._model.pushStackElement();
}
}
protected _getInitialSelections(): Selection[] {
const firstRange = this._edits[0].range;
const initialSelection = new Selection(
firstRange.startLineNumber,
firstRange.startColumn,
firstRange.endLineNumber,
firstRange.endColumn
);
return [initialSelection];
}
private _getEndCursorSelections(inverseEditOperations: IIdentifiedSingleEditOperation[]): Selection[] {
let relevantEditIndex = 0;
for (let i = 0; i < inverseEditOperations.length; i++) {
const editRange = inverseEditOperations[i].range;
for (let j = 0; j < this._initialSelections.length; j++) {
const selectionRange = this._initialSelections[j];
if (Range.areIntersectingOrTouching(editRange, selectionRange)) {
relevantEditIndex = i;
break;
}
}
}
const srcRange = inverseEditOperations[relevantEditIndex].range;
this._endCursorSelection = new Selection(
srcRange.endLineNumber,
srcRange.endColumn,
srcRange.endLineNumber,
srcRange.endColumn
);
return [this._endCursorSelection];
}
public getEndCursorSelection(): Selection {
return this._endCursorSelection;
}
dispose() {
if (this._model) {
this._modelReference.dispose();
this._modelReference = null;
}
}
}
class SourceModelEditTask extends EditTask {
private _knownInitialSelections: Selection[];
constructor(modelReference: IReference<ITextEditorModel>, initialSelections: Selection[]) {
super(modelReference);
this._knownInitialSelections = initialSelections;
}
protected _getInitialSelections(): Selection[] {
return this._knownInitialSelections;
}
}
class BulkEditModel implements IDisposable {
private _textModelResolverService: ITextModelService;
private _numberOfResourcesToModify: number = 0;
private _numberOfChanges: number = 0;
private _edits: IStringDictionary<IResourceEdit[]> = Object.create(null);
private _tasks: EditTask[];
private _sourceModel: URI;
private _sourceSelections: Selection[];
private _sourceModelTask: SourceModelEditTask;
constructor(textModelResolverService: ITextModelService, sourceModel: URI, sourceSelections: Selection[], edits: IResourceEdit[], private progress: IProgressRunner = null) {
this._textModelResolverService = textModelResolverService;
this._sourceModel = sourceModel;
this._sourceSelections = sourceSelections;
this._sourceModelTask = null;
for (let edit of edits) {
this._addEdit(edit);
}
}
public resourcesCount(): number {
return this._numberOfResourcesToModify;
}
public changeCount(): number {
return this._numberOfChanges;
}
private _addEdit(edit: IResourceEdit): void {
let array = this._edits[edit.resource.toString()];
if (!array) {
this._edits[edit.resource.toString()] = array = [];
this._numberOfResourcesToModify += 1;
}
this._numberOfChanges += 1;
array.push(edit);
}
public prepare(): TPromise<BulkEditModel> {
if (this._tasks) {
throw new Error('illegal state - already prepared');
}
this._tasks = [];
const promises: TPromise<any>[] = [];
if (this.progress) {
this.progress.total(this._numberOfResourcesToModify * 2);
}
forEach(this._edits, entry => {
const promise = this._textModelResolverService.createModelReference(URI.parse(entry.key)).then(ref => {
const model = ref.object;
if (!model || !model.textEditorModel) {
throw new Error(`Cannot load file ${entry.key}`);
}
const textEditorModel = model.textEditorModel;
let task: EditTask;
if (this._sourceModel && textEditorModel.uri.toString() === this._sourceModel.toString()) {
this._sourceModelTask = new SourceModelEditTask(ref, this._sourceSelections);
task = this._sourceModelTask;
} else {
task = new EditTask(ref);
}
entry.value.forEach(edit => task.addEdit(edit));
this._tasks.push(task);
if (this.progress) {
this.progress.worked(1);
}
});
promises.push(promise);
});
return TPromise.join(promises).then(_ => this);
}
public apply(): Selection {
this._tasks.forEach(task => this.applyTask(task));
let r: Selection = null;
if (this._sourceModelTask) {
r = this._sourceModelTask.getEndCursorSelection();
}
return r;
}
private applyTask(task: EditTask): void {
task.apply();
if (this.progress) {
this.progress.worked(1);
}
}
dispose(): void {
this._tasks = dispose(this._tasks);
}
}
export interface BulkEdit {
progress(progress: IProgressRunner): void;
add(edit: IResourceEdit[]): void;
finish(): TPromise<ISelection>;
ariaMessage(): string;
}
export function bulkEdit(textModelResolverService: ITextModelService, editor: ICommonCodeEditor, edits: IResourceEdit[], fileService?: IFileService, progress: IProgressRunner = null): TPromise<any> {
let bulk = createBulkEdit(textModelResolverService, editor, fileService);
bulk.add(edits);
bulk.progress(progress);
return bulk.finish();
}
export function createBulkEdit(textModelResolverService: ITextModelService, editor?: ICommonCodeEditor, fileService?: IFileService): BulkEdit {
let all: IResourceEdit[] = [];
let recording = new ChangeRecorder(fileService).start();
let progressRunner: IProgressRunner;
function progress(progress: IProgressRunner) {
progressRunner = progress;
}
function add(edits: IResourceEdit[]): void {
all.push(...edits);
}
function getConcurrentEdits() {
let names: string[];
for (let edit of all) {
if (recording.hasChanged(edit.resource)) {
if (!names) {
names = [];
}
names.push(edit.resource.fsPath);
}
}
if (names) {
return nls.localize('conflict', "These files have changed in the meantime: {0}", names.join(', '));
}
return undefined;
}
function finish(): TPromise<ISelection> {
if (all.length === 0) {
return TPromise.as(undefined);
}
let concurrentEdits = getConcurrentEdits();
if (concurrentEdits) {
return TPromise.wrapError<ISelection>(new Error(concurrentEdits));
}
let uri: URI;
let selections: Selection[];
if (editor && editor.getModel()) {
uri = editor.getModel().uri;
selections = editor.getSelections();
}
const model = new BulkEditModel(textModelResolverService, uri, selections, all, progressRunner);
return model.prepare().then(_ => {
let concurrentEdits = getConcurrentEdits();
if (concurrentEdits) {
throw new Error(concurrentEdits);
}
recording.stop();
const result = model.apply();
model.dispose();
return result;
});
}
function ariaMessage(): string {
let editCount = all.length;
let resourceCount = size(groupBy(all, edit => edit.resource.toString()));
if (editCount === 0) {
return nls.localize('summary.0', "Made no edits");
} else if (editCount > 1 && resourceCount > 1) {
return nls.localize('summary.nm', "Made {0} text edits in {1} files", editCount, resourceCount);
} else {
return nls.localize('summary.n0', "Made {0} text edits in one file", editCount, resourceCount);
}
}
return {
progress,
add,
finish,
ariaMessage
};
}

View File

@@ -1,80 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Event from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ICommonCodeEditor, ICommonDiffEditor, isCommonCodeEditor, isCommonDiffEditor, IDecorationRenderOptions, IModelDecorationOptions, IModel } from 'vs/editor/common/editorCommon';
import { IEditor } from 'vs/platform/editor/common/editor';
export var ICodeEditorService = createDecorator<ICodeEditorService>('codeEditorService');
export interface ICodeEditorService {
_serviceBrand: any;
onCodeEditorAdd: Event<ICommonCodeEditor>;
onCodeEditorRemove: Event<ICommonCodeEditor>;
onDiffEditorAdd: Event<ICommonDiffEditor>;
onDiffEditorRemove: Event<ICommonDiffEditor>;
addCodeEditor(editor: ICommonCodeEditor): void;
removeCodeEditor(editor: ICommonCodeEditor): void;
getCodeEditor(editorId: string): ICommonCodeEditor;
listCodeEditors(): ICommonCodeEditor[];
addDiffEditor(editor: ICommonDiffEditor): void;
removeDiffEditor(editor: ICommonDiffEditor): void;
getDiffEditor(editorId: string): ICommonDiffEditor;
listDiffEditors(): ICommonDiffEditor[];
/**
* Returns the current focused code editor (if the focus is in the editor or in an editor widget) or null.
*/
getFocusedCodeEditor(): ICommonCodeEditor;
registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void;
removeDecorationType(key: string): void;
resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions;
setTransientModelProperty(model: IModel, key: string, value: any): void;
getTransientModelProperty(model: IModel, key: string): any;
}
/**
* Uses `editor.getControl()` and returns either a `codeEditor` or a `diffEditor` or nothing.
*/
export function getCodeOrDiffEditor(editor: IEditor): { codeEditor: ICommonCodeEditor; diffEditor: ICommonDiffEditor } {
if (editor) {
let control = editor.getControl();
if (control) {
if (isCommonCodeEditor(control)) {
return {
codeEditor: control,
diffEditor: null
};
}
if (isCommonDiffEditor(control)) {
return {
codeEditor: null,
diffEditor: control
};
}
}
}
return {
codeEditor: null,
diffEditor: null
};
}
/**
* Uses `editor.getControl()` and returns either the code editor, or the modified editor of a diff editor or nothing.
*/
export function getCodeEditor(editor: IEditor): ICommonCodeEditor {
let r = getCodeOrDiffEditor(editor);
return r.codeEditor || (r.diffEditor && r.diffEditor.getModifiedEditor()) || null;
}

View File

@@ -342,7 +342,7 @@ export abstract class BaseEditorSimpleWorker {
// ---- BEGIN minimal edits ---------------------------------------------------------------
private static _diffLimit = 10000;
private static readonly _diffLimit = 10000;
public computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): TPromise<TextEdit[]> {
const model = this._getModel(modelUrl);
@@ -517,7 +517,7 @@ export abstract class BaseEditorSimpleWorker {
* @internal
*/
export class EditorSimpleWorkerImpl extends BaseEditorSimpleWorker implements IRequestHandler, IDisposable {
_requestHandlerTrait: any;
_requestHandlerBrand: any;
private _models: { [uri: string]: MirrorModel; };

View File

@@ -20,7 +20,6 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IRange } from 'vs/editor/common/core/range';
import { IModeService } from 'vs/editor/common/services/modeService';
/**
* Stop syncing a model to the worker if it was not needed for 1 min.
@@ -51,8 +50,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
constructor(
@IModelService modelService: IModelService,
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
@IModeService modeService: IModeService
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService
) {
super();
this._modelService = modelService;
@@ -67,7 +65,7 @@ export class EditorWorkerServiceImpl extends Disposable implements IEditorWorker
return wireCancellationToken(token, this._workerManager.withWorker().then(client => client.computeLinks(model.uri)));
}
}));
this._register(modes.SuggestRegistry.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, modeService, this._modelService)));
this._register(modes.SuggestRegistry.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService)));
}
public dispose(): void {
@@ -114,23 +112,20 @@ class WordBasedCompletionItemProvider implements modes.ISuggestSupport {
private readonly _workerManager: WorkerManager;
private readonly _configurationService: ITextResourceConfigurationService;
private readonly _modeService: IModeService;
private readonly _modelService: IModelService;
constructor(
workerManager: WorkerManager,
configurationService: ITextResourceConfigurationService,
modeService: IModeService,
modelService: IModelService
) {
this._workerManager = workerManager;
this._configurationService = configurationService;
this._modeService = modeService;
this._modelService = modelService;
}
provideCompletionItems(model: editorCommon.IModel, position: Position): TPromise<modes.ISuggestResult> {
const { wordBasedSuggestions } = this._configurationService.getConfiguration<IEditorOptions>(model.uri, position, 'editor');
const { wordBasedSuggestions } = this._configurationService.getValue<IEditorOptions>(model.uri, position, 'editor');
if (!wordBasedSuggestions) {
return undefined;
}

View File

@@ -36,13 +36,16 @@ export class LanguagesRegistry {
private _nameMap: { [name: string]: LanguageIdentifier; };
private _lowercaseNameMap: { [name: string]: LanguageIdentifier; };
constructor(useModesRegistry = true) {
private _warnOnOverwrite: boolean;
constructor(useModesRegistry = true, warnOnOverwrite = false) {
this._nextLanguageId = 1;
this._languages = {};
this._mimeTypesMap = {};
this._nameMap = {};
this._lowercaseNameMap = {};
this._languageIds = [];
this._warnOnOverwrite = warnOnOverwrite;
if (useModesRegistry) {
this._registerLanguages(ModesRegistry.getLanguages());
@@ -100,10 +103,10 @@ export class LanguagesRegistry {
this._languages[langId] = resolvedLanguage;
}
LanguagesRegistry._mergeLanguage(resolvedLanguage, lang);
this._mergeLanguage(resolvedLanguage, lang);
}
private static _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void {
private _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void {
const langId = lang.id;
let primaryMime: string = null;
@@ -124,21 +127,21 @@ export class LanguagesRegistry {
if (Array.isArray(lang.extensions)) {
for (let extension of lang.extensions) {
mime.registerTextMime({ id: langId, mime: primaryMime, extension: extension });
mime.registerTextMime({ id: langId, mime: primaryMime, extension: extension }, this._warnOnOverwrite);
resolvedLanguage.extensions.push(extension);
}
}
if (Array.isArray(lang.filenames)) {
for (let filename of lang.filenames) {
mime.registerTextMime({ id: langId, mime: primaryMime, filename: filename });
mime.registerTextMime({ id: langId, mime: primaryMime, filename: filename }, this._warnOnOverwrite);
resolvedLanguage.filenames.push(filename);
}
}
if (Array.isArray(lang.filenamePatterns)) {
for (let filenamePattern of lang.filenamePatterns) {
mime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern });
mime.registerTextMime({ id: langId, mime: primaryMime, filepattern: filenamePattern }, this._warnOnOverwrite);
}
}
@@ -150,7 +153,7 @@ export class LanguagesRegistry {
try {
let firstLineRegex = new RegExp(firstLineRegexStr);
if (!strings.regExpLeadsToEndlessLoop(firstLineRegex)) {
mime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex });
mime.registerTextMime({ id: langId, mime: primaryMime, firstline: firstLineRegex }, this._warnOnOverwrite);
}
} catch (err) {
// Most likely, the regex was bad

View File

@@ -11,11 +11,6 @@ import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';
export var IModeService = createDecorator<IModeService>('modeService');
export interface IModeLookupResult {
modeId: string;
isInstantiated: boolean;
}
export interface ILanguageExtensionPoint {
id: string;
extensions?: string[];
@@ -58,7 +53,6 @@ export interface IModeService {
getConfigurationFiles(modeId: string): string[];
// --- instantiation
lookup(commaSeparatedMimetypesOrCommaSeparatedIds: string): IModeLookupResult[];
getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): IMode;
getOrCreateMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): TPromise<IMode>;
getOrCreateModeByLanguageName(languageName: string): TPromise<IMode>;

View File

@@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes';
import { FrankensteinMode } from 'vs/editor/common/modes/abstractMode';
import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';
import { IModeLookupResult, IModeService } from 'vs/editor/common/services/modeService';
import { IModeService } from 'vs/editor/common/services/modeService';
export class ModeServiceImpl implements IModeService {
public _serviceBrand: any;
@@ -21,10 +21,10 @@ export class ModeServiceImpl implements IModeService {
private readonly _onDidCreateMode: Emitter<IMode> = new Emitter<IMode>();
public readonly onDidCreateMode: Event<IMode> = this._onDidCreateMode.event;
constructor() {
constructor(warnOnOverwrite = false) {
this._instantiatedModes = {};
this._registry = new LanguagesRegistry();
this._registry = new LanguagesRegistry(true, warnOnOverwrite);
}
protected _onReady(): TPromise<boolean> {
@@ -93,22 +93,6 @@ export class ModeServiceImpl implements IModeService {
// --- instantiation
public lookup(commaSeparatedMimetypesOrCommaSeparatedIds: string): IModeLookupResult[] {
var r: IModeLookupResult[] = [];
var modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds);
for (var i = 0; i < modeIds.length; i++) {
var modeId = modeIds[i];
r.push({
modeId: modeId,
isInstantiated: this._instantiatedModes.hasOwnProperty(modeId)
});
}
return r;
}
public getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): IMode {
var modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds);

View File

@@ -7,9 +7,8 @@
import * as nls from 'vs/nls';
import network = require('vs/base/common/network');
import Event, { Emitter } from 'vs/base/common/event';
import { EmitterEvent } from 'vs/base/common/eventEmitter';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -25,7 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry';
import { IRawTextSource, TextSource, RawTextSource, ITextSource } from 'vs/editor/common/model/textSource';
import * as textModelEvents from 'vs/editor/common/model/textModelEvents';
import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { ClassName } from 'vs/editor/common/model/intervalTree';
import { ISequence, LcsDiff } from 'vs/base/common/diff/diff';
import { EditOperation } from 'vs/editor/common/core/editOperation';
@@ -40,26 +39,28 @@ class ModelData implements IDisposable {
model: editorCommon.IModel;
private _markerDecorations: string[];
private _modelEventsListener: IDisposable;
private _modelEventListeners: IDisposable[];
constructor(model: editorCommon.IModel, eventsHandler: (modelData: ModelData, events: EmitterEvent[]) => void) {
constructor(
model: editorCommon.IModel,
onWillDispose: (model: editorCommon.IModel) => void,
onDidChangeLanguage: (model: editorCommon.IModel, e: IModelLanguageChangedEvent) => void
) {
this.model = model;
this._markerDecorations = [];
this._modelEventsListener = model.addBulkListener((events) => eventsHandler(this, events));
this._modelEventListeners = [];
this._modelEventListeners.push(model.onWillDispose(() => onWillDispose(model)));
this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
}
public dispose(): void {
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []);
this._modelEventsListener.dispose();
this._modelEventsListener = null;
this._modelEventListeners = dispose(this._modelEventListeners);
this.model = null;
}
public getModelId(): string {
return MODEL_ID(this.model.uri);
}
public acceptMarkerDecorations(newDecorations: editorCommon.IModelDeltaDecoration[]): void {
this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations);
}
@@ -272,7 +273,7 @@ export class ModelServiceImpl implements IModelService {
public getCreationOptions(language: string, resource: URI): editorCommon.ITextModelCreationOptions {
let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
if (!creationOptions) {
creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration({ overrideIdentifier: language, resource }));
creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getValue({ overrideIdentifier: language, resource }));
this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions;
}
return creationOptions;
@@ -366,7 +367,11 @@ export class ModelServiceImpl implements IModelService {
throw new Error('ModelService: Cannot add model because it already exists!');
}
let modelData = new ModelData(model, (modelData, events) => this._onModelEvents(modelData, events));
let modelData = new ModelData(
model,
(model) => this._onWillDispose(model),
(model, e) => this._onDidChangeLanguage(model, e)
);
this._models[modelId] = modelData;
return modelData;
@@ -559,7 +564,7 @@ export class ModelServiceImpl implements IModelService {
// --- end IModelService
private _onModelDisposing(model: editorCommon.IModel): void {
private _onWillDispose(model: editorCommon.IModel): void {
let modelId = MODEL_ID(model.uri);
let modelData = this._models[modelId];
@@ -570,30 +575,12 @@ export class ModelServiceImpl implements IModelService {
this._onModelRemoved.fire(model);
}
private _onModelEvents(modelData: ModelData, events: EmitterEvent[]): void {
// First look for dispose
for (let i = 0, len = events.length; i < len; i++) {
let e = events[i];
if (e.type === textModelEvents.TextModelEventType.ModelDispose) {
this._onModelDisposing(modelData.model);
// no more processing since model got disposed
return;
}
}
// Second, look for mode change
for (let i = 0, len = events.length; i < len; i++) {
let e = events[i];
if (e.type === textModelEvents.TextModelEventType.ModelLanguageChanged) {
const model = modelData.model;
const oldModeId = (<textModelEvents.IModelLanguageChangedEvent>e.data).oldLanguage;
const newModeId = model.getLanguageIdentifier().language;
const oldOptions = this.getCreationOptions(oldModeId, model.uri);
const newOptions = this.getCreationOptions(newModeId, model.uri);
ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions);
this._onModelModeChanged.fire({ model, oldModeId });
}
}
private _onDidChangeLanguage(model: editorCommon.IModel, e: IModelLanguageChangedEvent): void {
const oldModeId = e.oldLanguage;
const newModeId = model.getLanguageIdentifier().language;
const oldOptions = this.getCreationOptions(oldModeId, model.uri);
const newOptions = this.getCreationOptions(newModeId, model.uri);
ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions);
this._onModelModeChanged.fire({ model, oldModeId });
}
}

View File

@@ -21,15 +21,15 @@ export interface ITextResourceConfigurationService {
onDidChangeConfiguration: Event<IConfigurationChangeEvent>;
/**
* Fetches the appropriate section of the for the given resource with appropriate overrides (e.g. language).
* This will be an object keyed off the section name.
* Fetches the value of the section for the given resource by applying language overrides.
* Value can be of native type or an object keyed off the section name.
*
* @param resource - Resource for which the configuration has to be fetched. Can be `null` or `undefined`.
* @param postion - Position in the resource for which configuration has to be fetched. Can be `null` or `undefined`.
* @param section - Section of the configuraion. Can be `null` or `undefined`.
*
*/
getConfiguration<T>(resource: URI, section?: string): T;
getConfiguration<T>(resource: URI, position?: IPosition, section?: string): T;
getValue<T>(resource: URI, section?: string): T;
getValue<T>(resource: URI, position?: IPosition, section?: string): T;
}

View File

@@ -28,13 +28,13 @@ export class TextResourceConfigurationService extends Disposable implements ITex
this._register(this.configurationService.onDidChangeConfiguration(e => this._onDidChangeConfiguration.fire(e)));
}
getConfiguration<T>(resource: URI, section?: string): T
getConfiguration<T>(resource: URI, at?: IPosition, section?: string): T
getConfiguration<T>(resource: URI, arg2?: any, arg3?: any): T {
getValue<T>(resource: URI, section?: string): T;
getValue<T>(resource: URI, at?: IPosition, section?: string): T;
getValue<T>(resource: URI, arg2?: any, arg3?: any): T {
const position: IPosition = Position.isIPosition(arg2) ? arg2 : null;
const section: string = position ? (typeof arg3 === 'string' ? arg3 : void 0) : (typeof arg2 === 'string' ? arg2 : void 0);
const language = resource ? this.getLanguage(resource, position) : void 0;
return this.configurationService.getConfiguration<T>(section, { resource, overrideIdentifier: language });
return this.configurationService.getValue<T>(section, { resource, overrideIdentifier: language });
}
private getLanguage(resource: URI, position: IPosition): string {

View File

@@ -84,7 +84,7 @@ class MonacoWebWorkerImpl<T> extends EditorWorkerClient implements MonacoWebWork
};
};
let foreignProxy = <T><any>{};
let foreignProxy = {} as T;
for (let i = 0; i < foreignMethods.length; i++) {
foreignProxy[foreignMethods[i]] = createProxyMethod(foreignMethods[i], proxyMethodRequest);
}

View File

@@ -66,18 +66,6 @@ export class OverviewRulerZone {
return this._color;
}
public equals(other: OverviewRulerZone): boolean {
return (
this.startLineNumber === other.startLineNumber
&& this.endLineNumber === other.endLineNumber
&& this.position === other.position
&& this.forceHeight === other.forceHeight
&& this._color === other._color
&& this._darkColor === other._darkColor
&& this._hcColor === other._hcColor
);
}
public compareTo(other: OverviewRulerZone): number {
if (this.startLineNumber === other.startLineNumber) {
if (this.endLineNumber === other.endLineNumber) {

View File

@@ -58,13 +58,6 @@ export abstract class RestrictedRenderingContext {
return this._viewLayout.getVerticalOffsetForLineNumber(lineNumber);
}
public lineIsVisible(lineNumber: number): boolean {
return (
this.visibleRange.startLineNumber <= lineNumber
&& lineNumber <= this.visibleRange.endLineNumber
);
}
public getDecorationsInViewport(): ViewModelDecoration[] {
return this.viewportData.getDecorationsInViewport();
}

View File

@@ -4,23 +4,19 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { InlineDecoration } from 'vs/editor/common/viewModel/viewModel';
import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
import { Constants } from 'vs/editor/common/core/uint';
import * as strings from 'vs/base/common/strings';
export class LineDecoration {
_lineDecorationBrand: void;
public readonly startColumn: number;
public readonly endColumn: number;
public readonly className: string;
public readonly insertsBeforeOrAfter: boolean;
constructor(startColumn: number, endColumn: number, className: string, insertsBeforeOrAfter: boolean) {
this.startColumn = startColumn;
this.endColumn = endColumn;
this.className = className;
this.insertsBeforeOrAfter = insertsBeforeOrAfter;
constructor(
public readonly startColumn: number,
public readonly endColumn: number,
public readonly className: string,
public readonly type: InlineDecorationType
) {
}
private static _equals(a: LineDecoration, b: LineDecoration): boolean {
@@ -28,7 +24,7 @@ export class LineDecoration {
a.startColumn === b.startColumn
&& a.endColumn === b.endColumn
&& a.className === b.className
&& a.insertsBeforeOrAfter === b.insertsBeforeOrAfter
&& a.type === b.type
);
}
@@ -62,7 +58,7 @@ export class LineDecoration {
continue;
}
if (range.isEmpty()) {
if (range.isEmpty() && d.type === InlineDecorationType.Regular) {
// Ignore empty range decorations
continue;
}
@@ -70,12 +66,7 @@ export class LineDecoration {
let startColumn = (range.startLineNumber === lineNumber ? range.startColumn : minLineColumn);
let endColumn = (range.endLineNumber === lineNumber ? range.endColumn : maxLineColumn);
if (endColumn <= 1) {
// An empty decoration (endColumn === 1)
continue;
}
result[resultLen++] = new LineDecoration(startColumn, endColumn, d.inlineClassName, d.insertsBeforeOrAfter);
result[resultLen++] = new LineDecoration(startColumn, endColumn, d.inlineClassName, d.type);
}
return result;

View File

@@ -48,10 +48,6 @@ export class ViewLayout extends Disposable implements IViewLayout {
super.dispose();
}
public getScrollable(): Scrollable {
return this.scrollable;
}
public onHeightMaybeChanged(): void {
this._updateHeight();
}

View File

@@ -9,6 +9,7 @@ import { CharCode } from 'vs/base/common/charCode';
import { LineDecoration, LineDecorationsNormalizer } from 'vs/editor/common/viewLayout/lineDecorations';
import * as strings from 'vs/base/common/strings';
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
export const enum RenderWhitespace {
None = 0,
@@ -243,14 +244,14 @@ export function renderViewLine(input: RenderLineInput, sb: IStringBuilder): Rend
let classNames: string[] = [];
for (let i = 0, len = input.lineDecorations.length; i < len; i++) {
const lineDecoration = input.lineDecorations[i];
if (lineDecoration.insertsBeforeOrAfter) {
classNames[i] = input.lineDecorations[i].className;
if (lineDecoration.type !== InlineDecorationType.Regular) {
classNames.push(input.lineDecorations[i].className);
containsForeignElements = true;
}
}
if (containsForeignElements) {
content = `<span><span class="${classNames.join(' ')}">\u00a0</span></span>`;
content = `<span><span class="${classNames.join(' ')}"></span></span>`;
}
}
@@ -322,7 +323,7 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput
if (input.lineDecorations.length > 0) {
for (let i = 0, len = input.lineDecorations.length; i < len; i++) {
const lineDecoration = input.lineDecorations[i];
if (lineDecoration.insertsBeforeOrAfter) {
if (lineDecoration.type !== InlineDecorationType.Regular) {
containsForeignElements = true;
break;
}
@@ -568,6 +569,16 @@ function _applyInlineDecorations(lineContent: string, len: number, tokens: LineP
}
}
const lastTokenEndIndex = tokens[tokens.length - 1].endIndex;
if (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
let classNames: string[] = [];
while (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {
classNames.push(lineDecorations[lineDecorationIndex].className);
lineDecorationIndex++;
}
result[resultLen++] = new LinePart(lastResultEndIndex, classNames.join(' '));
}
return result;
}
@@ -618,7 +629,6 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
{
let _charIndex = charIndex;
let _tabsCharDelta = tabsCharDelta;
let _charOffsetInPart = charOffsetInPart;
for (; _charIndex < partEndIndex; _charIndex++) {
const charCode = lineContent.charCodeAt(_charIndex);
@@ -626,13 +636,10 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
if (charCode === CharCode.Tab) {
let insertSpacesCount = tabSize - (_charIndex + _tabsCharDelta) % tabSize;
_tabsCharDelta += insertSpacesCount - 1;
_charOffsetInPart += insertSpacesCount - 1;
partContentCnt += insertSpacesCount;
} else {
partContentCnt++;
}
_charOffsetInPart++;
}
}

View File

@@ -205,10 +205,6 @@ export class PrefixSumComputerWithCache {
this._cache = null;
}
public getCount(): number {
return this._actual.getCount();
}
public insertValues(insertIndex: number, insertValues: Uint32Array): void {
if (this._actual.insertValues(insertIndex, insertValues)) {
this._bustCache();

View File

@@ -5,7 +5,6 @@
'use strict';
import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { Range } from 'vs/editor/common/core/range';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { LineTokens } from 'vs/editor/common/core/lineTokens';
@@ -110,12 +109,6 @@ export class CoordinatesConverter implements ICoordinatesConverter {
return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
}
public convertViewSelectionToModelSelection(viewSelection: Selection): Selection {
let selectionStart = this._lines.convertViewPositionToModelPosition(viewSelection.selectionStartLineNumber, viewSelection.selectionStartColumn);
let position = this._lines.convertViewPositionToModelPosition(viewSelection.positionLineNumber, viewSelection.positionColumn);
return new Selection(selectionStart.lineNumber, selectionStart.column, position.lineNumber, position.column);
}
public validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position {
return this._lines.validateViewPosition(viewPosition.lineNumber, viewPosition.column, expectedModelPosition);
}
@@ -138,12 +131,6 @@ export class CoordinatesConverter implements ICoordinatesConverter {
return new Range(start.lineNumber, start.column, end.lineNumber, end.column);
}
public convertModelSelectionToViewSelection(modelSelection: Selection): Selection {
let selectionStart = this._lines.convertModelPositionToViewPosition(modelSelection.selectionStartLineNumber, modelSelection.selectionStartColumn);
let position = this._lines.convertModelPositionToViewPosition(modelSelection.positionLineNumber, modelSelection.positionColumn);
return new Selection(selectionStart.lineNumber, selectionStart.column, position.lineNumber, position.column);
}
public modelPositionIsVisible(modelPosition: Position): boolean {
return this._lines.modelPositionIsVisible(modelPosition.lineNumber, modelPosition.column);
}
@@ -790,7 +777,7 @@ export class SplitLinesCollection implements IViewModelLinesCollection {
class VisibleIdentitySplitLine implements ISplitLine {
public static INSTANCE = new VisibleIdentitySplitLine();
public static readonly INSTANCE = new VisibleIdentitySplitLine();
private constructor() { }
@@ -855,7 +842,7 @@ class VisibleIdentitySplitLine implements ISplitLine {
class InvisibleIdentitySplitLine implements ISplitLine {
public static INSTANCE = new InvisibleIdentitySplitLine();
public static readonly INSTANCE = new InvisibleIdentitySplitLine();
private constructor() { }
@@ -1097,12 +1084,6 @@ export class IdentityCoordinatesConverter implements ICoordinatesConverter {
return this._lines.model.validateRange(range);
}
private _validSelection(selection: Selection): Selection {
let selectionStart = this._validPosition(new Position(selection.selectionStartLineNumber, selection.selectionStartColumn));
let position = this._validPosition(new Position(selection.positionLineNumber, selection.positionColumn));
return new Selection(selectionStart.lineNumber, selectionStart.column, position.lineNumber, position.column);
}
// View -> Model conversion and related methods
public convertViewPositionToModelPosition(viewPosition: Position): Position {
@@ -1113,10 +1094,6 @@ export class IdentityCoordinatesConverter implements ICoordinatesConverter {
return this._validRange(viewRange);
}
public convertViewSelectionToModelSelection(viewSelection: Selection): Selection {
return this._validSelection(viewSelection);
}
public validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position {
return this._validPosition(expectedModelPosition);
}
@@ -1135,10 +1112,6 @@ export class IdentityCoordinatesConverter implements ICoordinatesConverter {
return this._validRange(modelRange);
}
public convertModelSelectionToViewSelection(modelSelection: Selection): Selection {
return this._validSelection(modelSelection);
}
public modelPositionIsVisible(modelPosition: Position): boolean {
const lineCount = this._lines.model.getLineCount();
if (modelPosition.lineNumber < 1 || modelPosition.lineNumber > lineCount) {

View File

@@ -8,7 +8,6 @@ import { INewScrollPosition, EndOfLinePreference, IViewState, IModelDecorationOp
import { ViewLineToken } from 'vs/editor/common/core/viewLineToken';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { ViewEvent, IViewEventListener } from 'vs/editor/common/view/viewEvents';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Scrollable, IScrollPosition } from 'vs/base/common/scrollable';
@@ -101,14 +100,12 @@ export interface ICoordinatesConverter {
// View -> Model conversion and related methods
convertViewPositionToModelPosition(viewPosition: Position): Position;
convertViewRangeToModelRange(viewRange: Range): Range;
convertViewSelectionToModelSelection(viewSelection: Selection): Selection;
validateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position;
validateViewRange(viewRange: Range, expectedModelRange: Range): Range;
// Model -> View conversion and related methods
convertModelPositionToViewPosition(modelPosition: Position): Position;
convertModelRangeToViewRange(modelRange: Range): Range;
convertModelSelectionToViewSelection(modelSelection: Selection): Selection;
modelPositionIsVisible(modelPosition: Position): boolean;
}
@@ -252,17 +249,18 @@ export class ViewLineRenderingData {
}
}
export const enum InlineDecorationType {
Regular = 0,
Before = 1,
After = 2
}
export class InlineDecoration {
_inlineDecorationBrand: void;
readonly range: Range;
readonly inlineClassName: string;
readonly insertsBeforeOrAfter: boolean;
constructor(range: Range, inlineClassName: string, insertsBeforeOrAfter: boolean) {
this.range = range;
this.inlineClassName = inlineClassName;
this.insertsBeforeOrAfter = insertsBeforeOrAfter;
constructor(
public readonly range: Range,
public readonly inlineClassName: string,
public readonly type: InlineDecorationType
) {
}
}

View File

@@ -8,7 +8,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { InlineDecoration, ViewModelDecoration, ICoordinatesConverter } from 'vs/editor/common/viewModel/viewModel';
import { InlineDecoration, ViewModelDecoration, ICoordinatesConverter, InlineDecorationType } from 'vs/editor/common/viewModel/viewModel';
import { IViewModelLinesCollection } from 'vs/editor/common/viewModel/splitLinesCollection';
export interface IDecorationsViewportData {
@@ -123,7 +123,7 @@ export class ViewModelDecorations implements IDisposable {
decorationsInViewport[decorationsInViewportLen++] = viewModelDecoration;
if (decorationOptions.inlineClassName) {
let inlineDecoration = new InlineDecoration(viewRange, decorationOptions.inlineClassName, false);
let inlineDecoration = new InlineDecoration(viewRange, decorationOptions.inlineClassName, InlineDecorationType.Regular);
let intersectedStartLineNumber = Math.max(startLineNumber, viewRange.startLineNumber);
let intersectedEndLineNumber = Math.min(endLineNumber, viewRange.endLineNumber);
for (let j = intersectedStartLineNumber; j <= intersectedEndLineNumber; j++) {
@@ -132,21 +132,20 @@ export class ViewModelDecorations implements IDisposable {
}
if (decorationOptions.beforeContentClassName) {
if (startLineNumber <= viewRange.startLineNumber && viewRange.startLineNumber <= endLineNumber) {
// TODO: What happens if the startLineNumber and startColumn is at the end of a line?
let inlineDecoration = new InlineDecoration(
new Range(viewRange.startLineNumber, viewRange.startColumn, viewRange.startLineNumber, viewRange.startColumn + 1),
new Range(viewRange.startLineNumber, viewRange.startColumn, viewRange.startLineNumber, viewRange.startColumn),
decorationOptions.beforeContentClassName,
true
InlineDecorationType.Before
);
inlineDecorations[viewRange.startLineNumber - startLineNumber].push(inlineDecoration);
}
}
if (decorationOptions.afterContentClassName) {
if (startLineNumber <= viewRange.endLineNumber && viewRange.endLineNumber <= endLineNumber && viewRange.endColumn > 1) {
if (startLineNumber <= viewRange.endLineNumber && viewRange.endLineNumber <= endLineNumber) {
let inlineDecoration = new InlineDecoration(
new Range(viewRange.endLineNumber, viewRange.endColumn - 1, viewRange.endLineNumber, viewRange.endColumn),
new Range(viewRange.endLineNumber, viewRange.endColumn, viewRange.endLineNumber, viewRange.endColumn),
decorationOptions.afterContentClassName,
true
InlineDecorationType.After
);
inlineDecorations[viewRange.endLineNumber - startLineNumber].push(inlineDecoration);
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { EmitterEvent } from 'vs/base/common/eventEmitter';
import * as strings from 'vs/base/common/strings';
import { Position, IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
@@ -38,7 +37,6 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
private readonly decorations: ViewModelDecorations;
private _isDisposing: boolean;
private _centeredViewLine: number;
constructor(editorId: number, configuration: editorCommon.IConfiguration, model: editorCommon.IModel, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {
@@ -79,21 +77,11 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
this._emit([new viewEvents.ViewScrollChangedEvent(e)]);
}));
this._isDisposing = false;
this._centeredViewLine = -1;
this.decorations = new ViewModelDecorations(this.editorId, this.model, this.configuration, this.lines, this.coordinatesConverter);
this._register(this.model.addBulkListener((events: EmitterEvent[]) => {
if (this._isDisposing) {
// Disposing the lines might end up sending model decoration changed events
// ...we no longer care about them...
return;
}
let eventsCollector = new ViewEventsCollector();
this._onModelEvents(eventsCollector, events);
this._emit(eventsCollector.finalize());
}));
this._registerModelEvents();
this._register(this.configuration.onDidChange((e) => {
const eventsCollector = new ViewEventsCollector();
@@ -107,10 +95,11 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
}
public dispose(): void {
this._isDisposing = true;
// First remove listeners, as disposing the lines might end up sending
// model decoration changed events ... and we no longer care about them ...
super.dispose();
this.decorations.dispose();
this.lines.dispose();
super.dispose();
}
private _onConfigurationChanged(eventsCollector: ViewEventsCollector, e: IConfigurationChangedEvent): void {
@@ -157,152 +146,119 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
}
}
private _onModelEvents(eventsCollector: ViewEventsCollector, events: EmitterEvent[]): void {
private _registerModelEvents(): void {
// A quick check if there are model content change events incoming
// in order to update the configuration and reset the centered view line
for (let i = 0, len = events.length; i < len; i++) {
const eventType = events[i].type;
if (eventType === textModelEvents.TextModelEventType.ModelRawContentChanged2) {
// There is a content change event
this._centeredViewLine = -1;
this.configuration.setMaxLineNumber(this.model.getLineCount());
this._register(this.model.onDidChangeRawContent((e) => {
const eventsCollector = new ViewEventsCollector();
break;
}
}
// Update the configuration and reset the centered view line
this._centeredViewLine = -1;
this.configuration.setMaxLineNumber(this.model.getLineCount());
let hadOtherModelChange = false;
let hadModelLineChangeThatChangedLineMapping = false;
let hadOtherModelChange = false;
let hadModelLineChangeThatChangedLineMapping = false;
for (let i = 0, len = events.length; i < len; i++) {
const _e = events[i];
const type = _e.type;
const data = _e.data;
const changes = e.changes;
const versionId = e.versionId;
switch (type) {
for (let j = 0, lenJ = changes.length; j < lenJ; j++) {
const change = changes[j];
case textModelEvents.TextModelEventType.ModelRawContentChanged2: {
const e = <textModelEvents.ModelRawContentChangedEvent>data;
const changes = e.changes;
const versionId = e.versionId;
for (let j = 0, lenJ = changes.length; j < lenJ; j++) {
const change = changes[j];
switch (change.changeType) {
case textModelEvents.RawContentChangedType.Flush: {
this.lines.onModelFlushed();
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
this.decorations.reset();
this.viewLayout.onFlushed(this.getLineCount());
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LinesDeleted: {
const linesDeletedEvent = this.lines.onModelLinesDeleted(versionId, change.fromLineNumber, change.toLineNumber);
if (linesDeletedEvent !== null) {
eventsCollector.emit(linesDeletedEvent);
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
}
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LinesInserted: {
const linesInsertedEvent = this.lines.onModelLinesInserted(versionId, change.fromLineNumber, change.toLineNumber, change.detail.split('\n'));
if (linesInsertedEvent !== null) {
eventsCollector.emit(linesInsertedEvent);
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
}
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LineChanged: {
const [lineMappingChanged, linesChangedEvent, linesInsertedEvent, linesDeletedEvent] = this.lines.onModelLineChanged(versionId, change.lineNumber, change.detail);
hadModelLineChangeThatChangedLineMapping = lineMappingChanged;
if (linesChangedEvent) {
eventsCollector.emit(linesChangedEvent);
}
if (linesInsertedEvent) {
eventsCollector.emit(linesInsertedEvent);
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
}
if (linesDeletedEvent) {
eventsCollector.emit(linesDeletedEvent);
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
}
break;
}
case textModelEvents.RawContentChangedType.EOLChanged: {
// Nothing to do. The new version will be accepted below
break;
}
}
}
this.lines.acceptVersionId(versionId);
break;
}
case textModelEvents.TextModelEventType.ModelTokensChanged: {
const e = <textModelEvents.IModelTokensChangedEvent>data;
let viewRanges: { fromLineNumber: number; toLineNumber: number; }[] = [];
for (let j = 0, lenJ = e.ranges.length; j < lenJ; j++) {
const modelRange = e.ranges[j];
const viewStartLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.fromLineNumber, 1)).lineNumber;
const viewEndLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.toLineNumber, this.model.getLineMaxColumn(modelRange.toLineNumber))).lineNumber;
viewRanges[j] = {
fromLineNumber: viewStartLineNumber,
toLineNumber: viewEndLineNumber
};
}
eventsCollector.emit(new viewEvents.ViewTokensChangedEvent(viewRanges));
break;
}
case textModelEvents.TextModelEventType.ModelLanguageChanged: {
// That's ok, a model tokens changed event will follow shortly
break;
}
case textModelEvents.TextModelEventType.ModelLanguageConfigurationChanged: {
eventsCollector.emit(new viewEvents.ViewLanguageConfigurationEvent());
break;
}
case textModelEvents.TextModelEventType.ModelContentChanged: {
// Ignore
break;
}
case textModelEvents.TextModelEventType.ModelOptionsChanged: {
// A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here
if (this.lines.setTabSize(this.model.getOptions().tabSize)) {
switch (change.changeType) {
case textModelEvents.RawContentChangedType.Flush: {
this.lines.onModelFlushed();
eventsCollector.emit(new viewEvents.ViewFlushedEvent());
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent());
this.decorations.onLineMappingChanged();
this.decorations.reset();
this.viewLayout.onFlushed(this.getLineCount());
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LinesDeleted: {
const linesDeletedEvent = this.lines.onModelLinesDeleted(versionId, change.fromLineNumber, change.toLineNumber);
if (linesDeletedEvent !== null) {
eventsCollector.emit(linesDeletedEvent);
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
}
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LinesInserted: {
const linesInsertedEvent = this.lines.onModelLinesInserted(versionId, change.fromLineNumber, change.toLineNumber, change.detail.split('\n'));
if (linesInsertedEvent !== null) {
eventsCollector.emit(linesInsertedEvent);
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
}
hadOtherModelChange = true;
break;
}
case textModelEvents.RawContentChangedType.LineChanged: {
const [lineMappingChanged, linesChangedEvent, linesInsertedEvent, linesDeletedEvent] = this.lines.onModelLineChanged(versionId, change.lineNumber, change.detail);
hadModelLineChangeThatChangedLineMapping = lineMappingChanged;
if (linesChangedEvent) {
eventsCollector.emit(linesChangedEvent);
}
if (linesInsertedEvent) {
eventsCollector.emit(linesInsertedEvent);
this.viewLayout.onLinesInserted(linesInsertedEvent.fromLineNumber, linesInsertedEvent.toLineNumber);
}
if (linesDeletedEvent) {
eventsCollector.emit(linesDeletedEvent);
this.viewLayout.onLinesDeleted(linesDeletedEvent.fromLineNumber, linesDeletedEvent.toLineNumber);
}
break;
}
case textModelEvents.RawContentChangedType.EOLChanged: {
// Nothing to do. The new version will be accepted below
break;
}
break;
}
case textModelEvents.TextModelEventType.ModelDecorationsChanged: {
this.decorations.onModelDecorationsChanged();
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent());
break;
}
case textModelEvents.TextModelEventType.ModelDispose: {
// Ignore, since the editor will take care of this and destroy the view shortly
break;
}
default:
console.info('View received unknown event: ');
console.info(type, data);
}
}
this.lines.acceptVersionId(versionId);
if (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent());
this.decorations.onLineMappingChanged();
}
if (!hadOtherModelChange && hadModelLineChangeThatChangedLineMapping) {
eventsCollector.emit(new viewEvents.ViewLineMappingChangedEvent());
eventsCollector.emit(new viewEvents.ViewDecorationsChangedEvent());
this.decorations.onLineMappingChanged();
}
this._emit(eventsCollector.finalize());
}));
this._register(this.model.onDidChangeTokens((e) => {
let viewRanges: { fromLineNumber: number; toLineNumber: number; }[] = [];
for (let j = 0, lenJ = e.ranges.length; j < lenJ; j++) {
const modelRange = e.ranges[j];
const viewStartLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.fromLineNumber, 1)).lineNumber;
const viewEndLineNumber = this.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.toLineNumber, this.model.getLineMaxColumn(modelRange.toLineNumber))).lineNumber;
viewRanges[j] = {
fromLineNumber: viewStartLineNumber,
toLineNumber: viewEndLineNumber
};
}
this._emit([new viewEvents.ViewTokensChangedEvent(viewRanges)]);
}));
this._register(this.model.onDidChangeLanguageConfiguration((e) => {
this._emit([new viewEvents.ViewLanguageConfigurationEvent()]);
}));
this._register(this.model.onDidChangeOptions((e) => {
// A tab size change causes a line mapping changed event => all view parts will repaint OK, no further event needed here
if (this.lines.setTabSize(this.model.getOptions().tabSize)) {
this.decorations.onLineMappingChanged();
this.viewLayout.onFlushed(this.getLineCount());
this._emit([
new viewEvents.ViewFlushedEvent(),
new viewEvents.ViewLineMappingChangedEvent(),
new viewEvents.ViewDecorationsChangedEvent(),
]);
}
}));
this._register(this.model.onDidChangeDecorations((e) => {
this.decorations.onModelDecorationsChanged();
this._emit([new viewEvents.ViewDecorationsChangedEvent()]);
}));
}
public setHiddenAreas(ranges: Range[]): void {