mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}));
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 [];
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; };
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -48,10 +48,6 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public getScrollable(): Scrollable {
|
||||
return this.scrollable;
|
||||
}
|
||||
|
||||
public onHeightMaybeChanged(): void {
|
||||
this._updateHeight();
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user