diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 7af6120a787..fbb819f0fbc 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -62,6 +62,7 @@ "./vs/base/common/idGenerator.ts", "./vs/base/common/iterator.ts", "./vs/base/common/jsonSchema.ts", + "./vs/base/common/keybindingLabels.ts", "./vs/base/common/keybindingParser.ts", "./vs/base/common/keyCodes.ts", "./vs/base/common/labels.ts", @@ -270,10 +271,15 @@ "./vs/editor/contrib/caretOperations/transpose.ts", "./vs/editor/contrib/clipboard/clipboard.ts", "./vs/editor/contrib/codeAction/codeActionTrigger.ts", + "./vs/editor/contrib/colorPicker/color.ts", "./vs/editor/contrib/colorPicker/colorPickerModel.ts", "./vs/editor/contrib/comment/blockCommentCommand.ts", + "./vs/editor/contrib/comment/comment.ts", + "./vs/editor/contrib/comment/lineCommentCommand.ts", "./vs/editor/contrib/cursorUndo/cursorUndo.ts", "./vs/editor/contrib/dnd/dragAndDropCommand.ts", + "./vs/editor/contrib/find/findDecorations.ts", + "./vs/editor/contrib/find/findModel.ts", "./vs/editor/contrib/find/findState.ts", "./vs/editor/contrib/find/replaceAllCommand.ts", "./vs/editor/contrib/find/replacePattern.ts", @@ -288,12 +294,19 @@ "./vs/editor/contrib/linesOperations/deleteLinesCommand.ts", "./vs/editor/contrib/linesOperations/sortLinesCommand.ts", "./vs/editor/contrib/links/getLinks.ts", + "./vs/editor/contrib/links/links.ts", "./vs/editor/contrib/quickOpen/quickOpen.ts", "./vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts", + "./vs/editor/contrib/wordHighlighter/wordHighlighter.ts", "./vs/editor/contrib/wordOperations/wordOperations.ts", + "./vs/editor/contrib/wordPartOperations/wordPartOperations.ts", "./vs/editor/editor.worker.ts", + "./vs/editor/standalone/browser/colorizer.ts", + "./vs/editor/standalone/browser/inspectTokens/inspectTokens.ts", "./vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts", "./vs/editor/standalone/browser/standaloneCodeServiceImpl.ts", + "./vs/editor/standalone/browser/standaloneThemeServiceImpl.ts", + "./vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts", "./vs/editor/standalone/common/monarch/monarchCommon.ts", "./vs/editor/standalone/common/monarch/monarchCompile.ts", "./vs/editor/standalone/common/monarch/monarchTypes.ts", @@ -334,6 +347,7 @@ "./vs/platform/instantiation/common/serviceCollection.ts", "./vs/platform/integrity/common/integrity.ts", "./vs/platform/jsonschemas/common/jsonContributionRegistry.ts", + "./vs/platform/keybinding/common/keybinding.ts", "./vs/platform/keybinding/common/keybindingResolver.ts", "./vs/platform/keybinding/common/keybindingsRegistry.ts", "./vs/platform/keybinding/common/resolvedKeybindingItem.ts", diff --git a/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts index 3cff751c75d..44036154809 100644 --- a/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts +++ b/src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts @@ -71,23 +71,23 @@ export class KeybindingLabel implements IDisposable { this.didEverRender = true; } - private renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches) { + private renderPart(parent: HTMLElement, part: ResolvedKeybindingPart, match: PartMatches | null) { const modifierLabels = UILabelProvider.modifierLabels[this.os]; if (part.ctrlKey) { - this.renderKey(parent, modifierLabels.ctrlKey, match && match.ctrlKey, modifierLabels.separator); + this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match && match.ctrlKey), modifierLabels.separator); } if (part.shiftKey) { - this.renderKey(parent, modifierLabels.shiftKey, match && match.shiftKey, modifierLabels.separator); + this.renderKey(parent, modifierLabels.shiftKey, Boolean(match && match.shiftKey), modifierLabels.separator); } if (part.altKey) { - this.renderKey(parent, modifierLabels.altKey, match && match.altKey, modifierLabels.separator); + this.renderKey(parent, modifierLabels.altKey, Boolean(match && match.altKey), modifierLabels.separator); } if (part.metaKey) { - this.renderKey(parent, modifierLabels.metaKey, match && match.metaKey, modifierLabels.separator); + this.renderKey(parent, modifierLabels.metaKey, Boolean(match && match.metaKey), modifierLabels.separator); } const keyLabel = part.keyLabel; if (keyLabel) { - this.renderKey(parent, keyLabel, match && match.keyCode, ''); + this.renderKey(parent, keyLabel, Boolean(match && match.keyCode), ''); } } @@ -99,7 +99,6 @@ export class KeybindingLabel implements IDisposable { } dispose() { - this.keybinding = null; } private static areSame(a: Matches, b: Matches): boolean { diff --git a/src/vs/base/common/keybindingLabels.ts b/src/vs/base/common/keybindingLabels.ts index 36afbab6a05..9c5955b6569 100644 --- a/src/vs/base/common/keybindingLabels.ts +++ b/src/vs/base/common/keybindingLabels.ts @@ -26,13 +26,13 @@ export class ModifierLabelProvider { public readonly modifierLabels: ModifierLabels[]; constructor(mac: ModifierLabels, windows: ModifierLabels, linux: ModifierLabels = windows) { - this.modifierLabels = [null]; + this.modifierLabels = [null!]; // index 0 will never me accessed. this.modifierLabels[OperatingSystem.Macintosh] = mac; this.modifierLabels[OperatingSystem.Windows] = windows; this.modifierLabels[OperatingSystem.Linux] = linux; } - public toLabel(firstPartMod: Modifiers, firstPartKey: string, chordPartMod: Modifiers, chordPartKey: string, OS: OperatingSystem): string { + public toLabel(firstPartMod: Modifiers, firstPartKey: string, chordPartMod: Modifiers, chordPartKey: string, OS: OperatingSystem): string | null { if (firstPartKey === null && chordPartKey === null) { return null; } diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 9f53afd1eca..651d1bf9fec 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -803,14 +803,6 @@ export interface IActiveCodeEditor extends ICodeEditor { */ getDomNode(): HTMLElement; - /** - * Get the hit test target at coordinates `clientX` and `clientY`. - * The coordinates are relative to the top-left of the viewport. - * - * @returns Hit test target or null if the coordinates fall outside the editor or the editor has no model. - */ - getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget; - /** * Get the visible position for `position`. * The result position takes scrolling into account and is relative to the top left corner of the editor. diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 0ac94b2b5e4..22842cb2cdf 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -201,17 +201,16 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public readonly isSimpleWidget: boolean; private readonly _telemetryData: object | null; - private readonly domElement: HTMLElement; - private readonly id: number; + private readonly _domElement: HTMLElement; + private readonly _id: number; private readonly _configuration: editorCommon.IConfiguration; - protected _contributions: { [key: string]: editorCommon.IEditorContribution; }; - protected _actions: { [key: string]: editorCommon.IEditorAction; }; + protected readonly _contributions: { [key: string]: editorCommon.IEditorContribution; }; + protected readonly _actions: { [key: string]: editorCommon.IEditorAction; }; // --- Members logically associated to a model protected _modelData: ModelData | null; - protected readonly _instantiationService: IInstantiationService; protected readonly _contextKeyService: IContextKeyService; private readonly _notificationService: INotificationService; @@ -219,10 +218,10 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE private readonly _commandService: ICommandService; private readonly _themeService: IThemeService; - private _focusTracker: CodeEditorWidgetFocusTracker; + private readonly _focusTracker: CodeEditorWidgetFocusTracker; - private contentWidgets: { [key: string]: IContentWidgetData; }; - private overlayWidgets: { [key: string]: IOverlayWidgetData; }; + private readonly _contentWidgets: { [key: string]: IContentWidgetData; }; + private readonly _overlayWidgets: { [key: string]: IOverlayWidgetData; }; /** * map from "parent" decoration type to live decoration ids. @@ -242,8 +241,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE @INotificationService notificationService: INotificationService ) { super(); - this.domElement = domElement; - this.id = (++EDITOR_ID); + this._domElement = domElement; + this._id = (++EDITOR_ID); this._decorationTypeKeysToIds = {}; this._decorationTypeSubtypes = {}; this.isSimpleWidget = codeEditorWidgetOptions.isSimpleWidget || false; @@ -258,13 +257,13 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._onDidLayoutChange.fire(this._configuration.editor.layoutInfo); } if (this._configuration.editor.showUnused) { - this.domElement.classList.add(SHOW_UNUSED_ENABLED_CLASS); + this._domElement.classList.add(SHOW_UNUSED_ENABLED_CLASS); } else { - this.domElement.classList.remove(SHOW_UNUSED_ENABLED_CLASS); + this._domElement.classList.remove(SHOW_UNUSED_ENABLED_CLASS); } })); - this._contextKeyService = this._register(contextKeyService.createScoped(this.domElement)); + this._contextKeyService = this._register(contextKeyService.createScoped(this._domElement)); this._notificationService = notificationService; this._codeEditorService = codeEditorService; this._commandService = commandService; @@ -284,8 +283,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._editorWidgetFocus.setValue(this._focusTracker.hasFocus()); }); - this.contentWidgets = {}; - this.overlayWidgets = {}; + this._contentWidgets = {}; + this._overlayWidgets = {}; mark('editor/start/contrib'); let contributions: IEditorContributionCtor[]; @@ -325,11 +324,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } protected _createConfiguration(options: editorOptions.IEditorOptions): editorCommon.IConfiguration { - return new Configuration(options, this.domElement); + return new Configuration(options, this._domElement); } public getId(): string { - return this.getEditorType() + ':' + this.id; + return this.getEditorType() + ':' + this._id; } public getEditorType(): string { @@ -339,9 +338,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public dispose(): void { this._codeEditorService.removeCodeEditor(this); - this.contentWidgets = {}; - this.overlayWidgets = {}; - this._focusTracker.dispose(); let keys = Object.keys(this._contributions); @@ -349,10 +345,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE let contributionId = keys[i]; this._contributions[contributionId].dispose(); } - this._contributions = {}; - // editor actions don't need to be disposed - this._actions = {}; this._removeDecorationTypes(); this._postDetachModelCleanup(this._detachModel()); @@ -1026,14 +1019,14 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE // callback will not be called return null; } - return this._modelData.model.changeDecorations(callback, this.id); + return this._modelData.model.changeDecorations(callback, this._id); } public getLineDecorations(lineNumber: number): IModelDecoration[] | null { if (!this._modelData) { return null; } - return this._modelData.model.getLineDecorations(lineNumber, this.id, this._configuration.editor.readOnly); + return this._modelData.model.getLineDecorations(lineNumber, this._id, this._configuration.editor.readOnly); } public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] { @@ -1045,7 +1038,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return oldDecorations; } - return this._modelData.model.deltaDecorations(oldDecorations, newDecorations, this.id); + return this._modelData.model.deltaDecorations(oldDecorations, newDecorations, this._id); } public setDecorations(decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void { @@ -1178,11 +1171,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE position: widget.getPosition() }; - if (this.contentWidgets.hasOwnProperty(widget.getId())) { + if (this._contentWidgets.hasOwnProperty(widget.getId())) { console.warn('Overwriting a content widget with the same id.'); } - this.contentWidgets[widget.getId()] = widgetData; + this._contentWidgets[widget.getId()] = widgetData; if (this._modelData && this._modelData.hasRealView) { this._modelData.view.addContentWidget(widgetData); @@ -1191,8 +1184,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public layoutContentWidget(widget: editorBrowser.IContentWidget): void { let widgetId = widget.getId(); - if (this.contentWidgets.hasOwnProperty(widgetId)) { - let widgetData = this.contentWidgets[widgetId]; + if (this._contentWidgets.hasOwnProperty(widgetId)) { + let widgetData = this._contentWidgets[widgetId]; widgetData.position = widget.getPosition(); if (this._modelData && this._modelData.hasRealView) { this._modelData.view.layoutContentWidget(widgetData); @@ -1202,9 +1195,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public removeContentWidget(widget: editorBrowser.IContentWidget): void { let widgetId = widget.getId(); - if (this.contentWidgets.hasOwnProperty(widgetId)) { - let widgetData = this.contentWidgets[widgetId]; - delete this.contentWidgets[widgetId]; + if (this._contentWidgets.hasOwnProperty(widgetId)) { + let widgetData = this._contentWidgets[widgetId]; + delete this._contentWidgets[widgetId]; if (this._modelData && this._modelData.hasRealView) { this._modelData.view.removeContentWidget(widgetData); } @@ -1217,11 +1210,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE position: widget.getPosition() }; - if (this.overlayWidgets.hasOwnProperty(widget.getId())) { + if (this._overlayWidgets.hasOwnProperty(widget.getId())) { console.warn('Overwriting an overlay widget with the same id.'); } - this.overlayWidgets[widget.getId()] = widgetData; + this._overlayWidgets[widget.getId()] = widgetData; if (this._modelData && this._modelData.hasRealView) { this._modelData.view.addOverlayWidget(widgetData); @@ -1230,8 +1223,8 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void { let widgetId = widget.getId(); - if (this.overlayWidgets.hasOwnProperty(widgetId)) { - let widgetData = this.overlayWidgets[widgetId]; + if (this._overlayWidgets.hasOwnProperty(widgetId)) { + let widgetData = this._overlayWidgets[widgetId]; widgetData.position = widget.getPosition(); if (this._modelData && this._modelData.hasRealView) { this._modelData.view.layoutOverlayWidget(widgetData); @@ -1241,9 +1234,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void { let widgetId = widget.getId(); - if (this.overlayWidgets.hasOwnProperty(widgetId)) { - let widgetData = this.overlayWidgets[widgetId]; - delete this.overlayWidgets[widgetId]; + if (this._overlayWidgets.hasOwnProperty(widgetId)) { + let widgetData = this._overlayWidgets[widgetId]; + delete this._overlayWidgets[widgetId]; if (this._modelData && this._modelData.hasRealView) { this._modelData.view.removeOverlayWidget(widgetData); } @@ -1311,17 +1304,17 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const listenersToRemove: IDisposable[] = []; - this.domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language); + this._domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language); this._configuration.setIsDominatedByLongLines(model.isDominatedByLongLines()); this._configuration.setMaxLineNumber(model.getLineCount()); model.onBeforeAttached(); - const viewModel = new ViewModel(this.id, this._configuration, model, (callback) => dom.scheduleAtNextAnimationFrame(callback)); + const viewModel = new ViewModel(this._id, this._configuration, model, (callback) => dom.scheduleAtNextAnimationFrame(callback)); listenersToRemove.push(model.onDidChangeDecorations((e) => this._onDidChangeModelDecorations.fire(e))); listenersToRemove.push(model.onDidChangeLanguage((e) => { - this.domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language); + this._domElement.setAttribute('data-mode-id', model.getLanguageIdentifier().language); this._onDidChangeModelLanguage.fire(e); })); listenersToRemove.push(model.onDidChangeLanguageConfiguration((e) => this._onDidChangeModelLanguageConfiguration.fire(e))); @@ -1365,18 +1358,18 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE const [view, hasRealView] = this._createView(viewModel, cursor); if (hasRealView) { - this.domElement.appendChild(view.domNode.domNode); + this._domElement.appendChild(view.domNode.domNode); - let keys = Object.keys(this.contentWidgets); + let keys = Object.keys(this._contentWidgets); for (let i = 0, len = keys.length; i < len; i++) { let widgetId = keys[i]; - view.addContentWidget(this.contentWidgets[widgetId]); + view.addContentWidget(this._contentWidgets[widgetId]); } - keys = Object.keys(this.overlayWidgets); + keys = Object.keys(this._overlayWidgets); for (let i = 0, len = keys.length; i < len; i++) { let widgetId = keys[i]; - view.addOverlayWidget(this.overlayWidgets[widgetId]); + view.addOverlayWidget(this._overlayWidgets[widgetId]); } view.render(false, true); @@ -1479,7 +1472,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE protected _postDetachModelCleanup(detachedModel: ITextModel | null): void { if (detachedModel) { - detachedModel.removeAllDecorationsWithOwnerId(this.id); + detachedModel.removeAllDecorationsWithOwnerId(this._id); } } @@ -1493,9 +1486,9 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE this._modelData.dispose(); this._modelData = null; - this.domElement.removeAttribute('data-mode-id'); + this._domElement.removeAttribute('data-mode-id'); if (removeDomNode) { - this.domElement.removeChild(removeDomNode); + this._domElement.removeChild(removeDomNode); } return model; diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 585dfea30e2..80622c9e094 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -1231,8 +1231,13 @@ abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWi public abstract layout(): number; } -interface IMyViewZone extends editorBrowser.IViewZone { +interface IMyViewZone { shouldNotShrink?: boolean; + afterLineNumber: number; + heightInLines: number; + minWidthInPx?: number; + domNode: HTMLElement | null; + marginDomNode?: HTMLElement | null; } class ForeignViewZonesIterator { @@ -1270,7 +1275,7 @@ abstract class ViewZonesComputer { } public getViewZones(): IEditorsZones { - let result: IEditorsZones = { + let result: { original: IMyViewZone[]; modified: IMyViewZone[]; } = { original: [], modified: [] }; @@ -1286,7 +1291,7 @@ abstract class ViewZonesComputer { return a.afterLineNumber - b.afterLineNumber; }; - let addAndCombineIfPossible = (destination: editorBrowser.IViewZone[], item: IMyViewZone) => { + let addAndCombineIfPossible = (destination: IMyViewZone[], item: IMyViewZone) => { if (item.domNode === null && destination.length > 0) { let lastItem = destination[destination.length - 1]; if (lastItem.afterLineNumber === item.afterLineNumber && lastItem.domNode === null) { diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index d010a6bd55a..46cec746b26 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -354,28 +354,33 @@ export class Range { * A function that compares ranges, useful for sorting ranges * It will first compare ranges on the startPosition and then on the endPosition */ - public static compareRangesUsingStarts(a: IRange, b: IRange): number { - let aStartLineNumber = a.startLineNumber | 0; - let bStartLineNumber = b.startLineNumber | 0; + public static compareRangesUsingStarts(a: IRange | null | undefined, b: IRange | null | undefined): number { + if (a && b) { + const aStartLineNumber = a.startLineNumber | 0; + const bStartLineNumber = b.startLineNumber | 0; - if (aStartLineNumber === bStartLineNumber) { - let aStartColumn = a.startColumn | 0; - let bStartColumn = b.startColumn | 0; + if (aStartLineNumber === bStartLineNumber) { + const aStartColumn = a.startColumn | 0; + const bStartColumn = b.startColumn | 0; - if (aStartColumn === bStartColumn) { - let aEndLineNumber = a.endLineNumber | 0; - let bEndLineNumber = b.endLineNumber | 0; + if (aStartColumn === bStartColumn) { + const aEndLineNumber = a.endLineNumber | 0; + const bEndLineNumber = b.endLineNumber | 0; - if (aEndLineNumber === bEndLineNumber) { - let aEndColumn = a.endColumn | 0; - let bEndColumn = b.endColumn | 0; - return aEndColumn - bEndColumn; + if (aEndLineNumber === bEndLineNumber) { + const aEndColumn = a.endColumn | 0; + const bEndColumn = b.endColumn | 0; + return aEndColumn - bEndColumn; + } + return aEndLineNumber - bEndLineNumber; } - return aEndLineNumber - bEndLineNumber; + return aStartColumn - bStartColumn; } - return aStartColumn - bStartColumn; + return aStartLineNumber - bStartLineNumber; } - return aStartLineNumber - bStartLineNumber; + const aExists = (a ? 1 : 0); + const bExists = (b ? 1 : 0); + return aExists - bExists; } /** diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index d523c8de262..cb4c3128f10 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -17,9 +17,9 @@ export class SearchParams { public readonly searchString: string; public readonly isRegex: boolean; public readonly matchCase: boolean; - public readonly wordSeparators: string; + public readonly wordSeparators: string | null; - constructor(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string) { + constructor(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null) { this.searchString = searchString; this.isRegex = isRegex; this.matchCase = matchCase; diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 92d30766481..a1d1c0f7222 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -200,7 +200,7 @@ export interface ITokenizationSupport { getInitialState(): IState; // add offsetDelta to each of the returned indices - tokenize?(line: string, state: IState, offsetDelta: number): TokenizationResult; + tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult; tokenize2(line: string, state: IState, offsetDelta: number): TokenizationResult2; } diff --git a/src/vs/editor/common/modes/languageConfiguration.ts b/src/vs/editor/common/modes/languageConfiguration.ts index 6d5645cef2f..d12a89f0c69 100644 --- a/src/vs/editor/common/modes/languageConfiguration.ts +++ b/src/vs/editor/common/modes/languageConfiguration.ts @@ -12,11 +12,11 @@ export interface CommentRule { /** * The line comment token, like `// this is a comment` */ - lineComment?: string; + lineComment?: string | null; /** * The block comment character pair, like `/* block comment */` */ - blockComment?: CharacterPair; + blockComment?: CharacterPair | null; } /** diff --git a/src/vs/editor/common/modes/textToHtmlTokenizer.ts b/src/vs/editor/common/modes/textToHtmlTokenizer.ts index d932f8d0e44..88a888c06d7 100644 --- a/src/vs/editor/common/modes/textToHtmlTokenizer.ts +++ b/src/vs/editor/common/modes/textToHtmlTokenizer.ts @@ -4,18 +4,23 @@ *--------------------------------------------------------------------------------------------*/ import * as strings from 'vs/base/common/strings'; -import { ITokenizationSupport, IState, LanguageId } from 'vs/editor/common/modes'; +import { IState, LanguageId } from 'vs/editor/common/modes'; import { LineTokens, IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { CharCode } from 'vs/base/common/charCode'; import { NULL_STATE, nullTokenize2 } from 'vs/editor/common/modes/nullMode'; +import { TokenizationResult2 } from 'vs/editor/common/core/token'; -const fallback: ITokenizationSupport = { +export interface IReducedTokenizationSupport { + getInitialState(): IState; + tokenize2(line: string, state: IState, offsetDelta: number): TokenizationResult2; +} + +const fallback: IReducedTokenizationSupport = { getInitialState: () => NULL_STATE, - tokenize: undefined, tokenize2: (buffer: string, state: IState, deltaOffset: number) => nullTokenize2(LanguageId.Null, buffer, state, deltaOffset) }; -export function tokenizeToString(text: string, tokenizationSupport: ITokenizationSupport = fallback): string { +export function tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport = fallback): string { return _tokenizeToString(text, tokenizationSupport || fallback); } @@ -88,7 +93,7 @@ export function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens return result; } -function _tokenizeToString(text: string, tokenizationSupport: ITokenizationSupport): string { +function _tokenizeToString(text: string, tokenizationSupport: IReducedTokenizationSupport): string { let result = `
`; let lines = text.split(/\r\n|\r|\n/); let currentState = tokenizationSupport.getInitialState(); diff --git a/src/vs/editor/contrib/colorPicker/color.ts b/src/vs/editor/contrib/colorPicker/color.ts index 5dc35f511e3..18a48205012 100644 --- a/src/vs/editor/contrib/colorPicker/color.ts +++ b/src/vs/editor/contrib/colorPicker/color.ts @@ -32,7 +32,7 @@ export function getColors(model: ITextModel, token: CancellationToken): Promise< return Promise.all(promises).then(() => colors); } -export function getColorPresentations(model: ITextModel, colorInfo: IColorInformation, provider: DocumentColorProvider, token: CancellationToken): Promise { +export function getColorPresentations(model: ITextModel, colorInfo: IColorInformation, provider: DocumentColorProvider, token: CancellationToken): Promise { return Promise.resolve(provider.provideColorPresentations(model, colorInfo, token)); } diff --git a/src/vs/editor/contrib/comment/comment.ts b/src/vs/editor/contrib/comment/comment.ts index d0cd2682560..5792573e3bc 100644 --- a/src/vs/editor/contrib/comment/comment.ts +++ b/src/vs/editor/contrib/comment/comment.ts @@ -24,11 +24,11 @@ abstract class CommentLineAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { - let model = editor.getModel(); - if (!model) { + if (!editor.hasModel()) { return; } + let model = editor.getModel(); let commands: ICommand[] = []; let selections = editor.getSelections(); let opts = model.getOptions(); @@ -122,9 +122,12 @@ class BlockCommentAction extends EditorAction { } public run(accessor: ServicesAccessor, editor: ICodeEditor): void { + if (!editor.hasModel()) { + return; + } + let commands: ICommand[] = []; let selections = editor.getSelections(); - for (let i = 0; i < selections.length; i++) { commands.push(new BlockCommentCommand(selections[i])); } diff --git a/src/vs/editor/contrib/comment/lineCommentCommand.ts b/src/vs/editor/contrib/comment/lineCommentCommand.ts index ec591640e3e..b442b4d402c 100644 --- a/src/vs/editor/contrib/comment/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/lineCommentCommand.ts @@ -26,11 +26,15 @@ export interface ILinePreflightData { commentStrLength: number; } -export interface IPreflightData { - supported: boolean; +export interface IPreflightDataSupported { + supported: true; shouldRemoveComments: boolean; lines: ILinePreflightData[]; } +export interface IPreflightDataUnsupported { + supported: false; +} +export type IPreflightData = IPreflightDataSupported | IPreflightDataUnsupported; export interface ISimpleModel { getLineContent(lineNumber: number): string; @@ -62,7 +66,7 @@ export class LineCommentCommand implements editorCommon.ICommand { * Do an initial pass over the lines and gather info about the line comment string. * Returns null if any of the lines doesn't support a line comment string. */ - public static _gatherPreflightCommentStrings(model: ITextModel, startLineNumber: number, endLineNumber: number): ILinePreflightData[] { + public static _gatherPreflightCommentStrings(model: ITextModel, startLineNumber: number, endLineNumber: number): ILinePreflightData[] | null { model.tokenizeIfCheap(startLineNumber); const languageId = model.getLanguageIdAtPosition(startLineNumber, 1); @@ -170,9 +174,7 @@ export class LineCommentCommand implements editorCommon.ICommand { const lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber); if (lines === null) { return { - supported: false, - shouldRemoveComments: false, - lines: null + supported: false }; } @@ -182,7 +184,7 @@ export class LineCommentCommand implements editorCommon.ICommand { /** * Given a successful analysis, execute either insert line comments, either remove line comments */ - private _executeLineComments(model: ISimpleModel, builder: editorCommon.IEditOperationBuilder, data: IPreflightData, s: Selection): void { + private _executeLineComments(model: ISimpleModel, builder: editorCommon.IEditOperationBuilder, data: IPreflightDataSupported, s: Selection): void { let ops: IIdentifiedSingleEditOperation[]; @@ -200,7 +202,7 @@ export class LineCommentCommand implements editorCommon.ICommand { if (ops[i].range.isEmpty() && ops[i].range.getStartPosition().equals(cursorPosition)) { const lineContent = model.getLineContent(cursorPosition.lineNumber); if (lineContent.length + 1 === cursorPosition.column) { - this._deltaColumn = ops[i].text.length; + this._deltaColumn = (ops[i].text || '').length; } } } @@ -208,7 +210,7 @@ export class LineCommentCommand implements editorCommon.ICommand { this._selectionId = builder.trackSelection(s); } - private _attemptRemoveBlockComment(model: ITextModel, s: Selection, startToken: string, endToken: string): IIdentifiedSingleEditOperation[] { + private _attemptRemoveBlockComment(model: ITextModel, s: Selection, startToken: string, endToken: string): IIdentifiedSingleEditOperation[] | null { let startLineNumber = s.startLineNumber; let endLineNumber = s.endLineNumber; diff --git a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts index c415a3a9689..2fdd2f5f173 100644 --- a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts @@ -91,6 +91,9 @@ suite('Editor Contrib - Line Comment Command', () => { ' c', '\t\td' ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1); + if (!r.supported) { + throw new Error(`unexpected`); + } assert.equal(r.shouldRemoveComments, false); @@ -119,6 +122,9 @@ suite('Editor Contrib - Line Comment Command', () => { ' !@# c', '\t\t!@#d' ]), createBasicLinePreflightData(['//', 'rem', '!@#', '!@#']), 1); + if (!r.supported) { + throw new Error(`unexpected`); + } assert.equal(r.shouldRemoveComments, true); diff --git a/src/vs/editor/contrib/find/findDecorations.ts b/src/vs/editor/contrib/find/findDecorations.ts index 5ab9a026a9b..e36236e6b3f 100644 --- a/src/vs/editor/contrib/find/findDecorations.ts +++ b/src/vs/editor/contrib/find/findDecorations.ts @@ -9,12 +9,12 @@ import { Range } from 'vs/editor/common/core/range'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IModelDecorationsChangeAccessor, FindMatch, IModelDeltaDecoration, TrackedRangeStickiness, OverviewRulerLane } from 'vs/editor/common/model'; export class FindDecorations implements IDisposable { - private _editor: ICodeEditor; + private _editor: IActiveCodeEditor; private _decorations: string[]; private _overviewRulerApproximateDecorations: string[]; private _findScopeDecorationId: string | null; @@ -22,7 +22,7 @@ export class FindDecorations implements IDisposable { private _highlightedDecorationId: string | null; private _startPosition: Position; - constructor(editor: ICodeEditor) { + constructor(editor: IActiveCodeEditor) { this._editor = editor; this._decorations = []; this._overviewRulerApproximateDecorations = []; @@ -35,13 +35,11 @@ export class FindDecorations implements IDisposable { public dispose(): void { this._editor.deltaDecorations(this._allDecorations(), []); - this._editor = null; this._decorations = []; this._overviewRulerApproximateDecorations = []; this._findScopeDecorationId = null; this._rangeHighlightDecorationId = null; this._highlightedDecorationId = null; - this._startPosition = null; } public reset(): void { @@ -56,7 +54,7 @@ export class FindDecorations implements IDisposable { return this._decorations.length; } - public getFindScope(): Range { + public getFindScope(): Range | null { if (this._findScopeDecorationId) { return this._editor.getModel().getDecorationRange(this._findScopeDecorationId); } @@ -92,7 +90,7 @@ export class FindDecorations implements IDisposable { return 1; } - public setCurrentFindMatch(nextMatch: Range): number { + public setCurrentFindMatch(nextMatch: Range | null): number { let newCurrentDecorationId: string | null = null; let matchPosition = 0; if (nextMatch) { @@ -121,7 +119,7 @@ export class FindDecorations implements IDisposable { this._rangeHighlightDecorationId = null; } if (newCurrentDecorationId !== null) { - let rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId); + let rng = this._editor.getModel().getDecorationRange(newCurrentDecorationId)!; if (rng.startLineNumber !== rng.endLineNumber && rng.endColumn === 1) { let lineBeforeEnd = rng.endLineNumber - 1; let lineBeforeEndMaxColumn = this._editor.getModel().getLineMaxColumn(lineBeforeEnd); @@ -135,7 +133,7 @@ export class FindDecorations implements IDisposable { return matchPosition; } - public set(findMatches: FindMatch[], findScope: Range): void { + public set(findMatches: FindMatch[], findScope: Range | null): void { this._editor.changeDecorations((accessor) => { let findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION; @@ -207,7 +205,7 @@ export class FindDecorations implements IDisposable { }); } - public matchBeforePosition(position: Position): Range { + public matchBeforePosition(position: Position): Range | null { if (this._decorations.length === 0) { return null; } @@ -229,7 +227,7 @@ export class FindDecorations implements IDisposable { return this._editor.getModel().getDecorationRange(this._decorations[this._decorations.length - 1]); } - public matchAfterPosition(position: Position): Range { + public matchAfterPosition(position: Position): Range | null { if (this._decorations.length === 0) { return null; } diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 146d28ad3d8..b5b4102a821 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -20,7 +20,7 @@ import { SearchParams } from 'vs/editor/common/model/textModelSearch'; import { IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ITextModel, FindMatch, EndOfLinePreference } from 'vs/editor/common/model'; export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false); @@ -69,7 +69,7 @@ const RESEARCH_DELAY = 240; export class FindModelBoundToEditorModel { - private _editor: ICodeEditor; + private _editor: IActiveCodeEditor; private _state: FindReplaceState; private _toDispose: IDisposable[]; private _decorations: FindDecorations; @@ -79,7 +79,7 @@ export class FindModelBoundToEditorModel { private _updateDecorationsScheduler: RunOnceScheduler; private _isDisposed: boolean; - constructor(editor: ICodeEditor, state: FindReplaceState) { + constructor(editor: IActiveCodeEditor, state: FindReplaceState) { this._editor = editor; this._state = state; this._toDispose = []; @@ -158,18 +158,16 @@ export class FindModelBoundToEditorModel { } } - private static _getSearchRange(model: ITextModel, findScope: Range): Range { - let searchRange = model.getFullModelRange(); - + private static _getSearchRange(model: ITextModel, findScope: Range | null): Range { // If we have set now or before a find scope, use it for computing the search range if (findScope) { - searchRange = searchRange.intersectRanges(findScope); + return findScope; } - return searchRange; + return model.getFullModelRange(); } - private research(moveCursor: boolean, newFindScope?: Range): void { + private research(moveCursor: boolean, newFindScope?: Range | null): void { let findScope: Range | null = null; if (typeof newFindScope !== 'undefined') { findScope = newFindScope; @@ -299,7 +297,7 @@ export class FindModelBoundToEditorModel { if (!prevMatch) { // there is precisely one match and selection is on top of it - return null; + return; } if (!isRecursed && !searchRange.containsRange(prevMatch.range)) { @@ -358,7 +356,7 @@ export class FindModelBoundToEditorModel { } } - private _getNextMatch(after: Position, captureMatches: boolean, forceMove: boolean, isRecursed: boolean = false): FindMatch { + private _getNextMatch(after: Position, captureMatches: boolean, forceMove: boolean, isRecursed: boolean = false): FindMatch | null { if (this._cannotFind()) { return null; } @@ -438,7 +436,7 @@ export class FindModelBoundToEditorModel { } } - private _findMatches(findScope: Range, captureMatches: boolean, limitResultCount: number): FindMatch[] { + private _findMatches(findScope: Range | null, captureMatches: boolean, limitResultCount: number): FindMatch[] { let searchRange = FindModelBoundToEditorModel._getSearchRange(this._editor.getModel(), findScope); return this._editor.getModel().findMatches(this._state.searchString, searchRange, this._state.isRegex, this._state.matchCase, this._state.wholeWord ? this._editor.getConfiguration().wordSeparators : null, captureMatches, limitResultCount); } @@ -497,7 +495,7 @@ export class FindModelBoundToEditorModel { this._executeEditorCommand('replaceAll', command); } - private _regularReplaceAll(findScope: Range): void { + private _regularReplaceAll(findScope: Range | null): void { const replacePattern = this._getReplacePattern(); // Get all the ranges (even more than the highlighted ones) let matches = this._findMatches(findScope, replacePattern.hasReplacementPatterns, Constants.MAX_SAFE_SMALL_INTEGER); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index fdd0b9093ba..35ff1e4dbf5 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -110,7 +110,7 @@ export class FindReplaceState implements IDisposable { public dispose(): void { } - public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range): void { + public changeMatchInfo(matchesPosition: number, matchesCount: number, currentMatch: Range | undefined): void { let changeEvent: FindReplaceStateChangedEvent = { moveCursor: false, updateHistory: false, diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index a4ee990ea20..3bd09a78e2d 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -48,7 +48,7 @@ export class ReplacePattern { } } - public buildReplaceString(matches: string[]): string { + public buildReplaceString(matches: string[] | null): string { if (this._state.kind === ReplacePatternKind.StaticValue) { return this._state.staticValue; } @@ -69,7 +69,10 @@ export class ReplacePattern { return result; } - private static _substitute(matchIndex: number, matches: string[]): string { + private static _substitute(matchIndex: number, matches: string[] | null): string { + if (matches === null) { + return ''; + } if (matchIndex === 0) { return matches[0]; } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 56797d59cc0..17ffc1ed5b2 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -111,7 +111,7 @@ class LinkOccurrence { } private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { - if (/^command:/i.test(link.url)) { + if (link.url && /^command:/i.test(link.url)) { if (useMetaKey) { return (isActive ? decoration.metaCommandActive : decoration.metaCommand); } else { @@ -157,8 +157,8 @@ class LinkDetector implements editorCommon.IEditorContribution { private enabled: boolean; private listenersToRemove: IDisposable[]; private timeout: async.TimeoutTimer; - private computePromise: async.CancelablePromise; - private activeLinkDecorationId: string; + private computePromise: async.CancelablePromise | null; + private activeLinkDecorationId: string | null; private openerService: IOpenerService; private notificationService: INotificationService; private currentOccurrences: { [decorationId: string]: LinkOccurrence; }; @@ -236,15 +236,17 @@ class LinkDetector implements editorCommon.IEditorContribution { } private async beginCompute(): Promise { - if (!this.editor.getModel() || !this.enabled) { + if (!this.editor.hasModel() || !this.enabled) { return; } - if (!LinkProviderRegistry.has(this.editor.getModel())) { + const model = this.editor.getModel(); + + if (!LinkProviderRegistry.has(model)) { return; } - this.computePromise = async.createCancelablePromise(token => getLinks(this.editor.getModel(), token)); + this.computePromise = async.createCancelablePromise(token => getLinks(model, token)); try { const links = await this.computePromise; this.updateDecorations(links); @@ -283,11 +285,11 @@ class LinkDetector implements editorCommon.IEditorContribution { } } - private _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent): void { + private _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent, withKey: ClickLinkKeyboardEvent | null): void { const useMetaKey = (this.editor.getConfiguration().multiCursorModifier === 'altKey'); if (this.isEnabled(mouseEvent, withKey)) { this.cleanUpActiveLinkDecoration(); // always remove previous link decoration as their can only be one - const occurrence = this.getLinkOccurrence(mouseEvent.target.position); + const occurrence = this.getLinkOccurrence(mouseEvent.target!.position); if (occurrence) { this.editor.changeDecorations((changeAccessor) => { occurrence.activate(changeAccessor, useMetaKey); @@ -317,7 +319,7 @@ class LinkDetector implements editorCommon.IEditorContribution { if (!this.isEnabled(mouseEvent)) { return; } - const occurrence = this.getLinkOccurrence(mouseEvent.target.position); + const occurrence = this.getLinkOccurrence(mouseEvent.target!.position); if (!occurrence) { return; } @@ -348,7 +350,10 @@ class LinkDetector implements editorCommon.IEditorContribution { }); } - public getLinkOccurrence(position: Position): LinkOccurrence { + public getLinkOccurrence(position: Position | null): LinkOccurrence | null { + if (!this.editor.hasModel() || !position) { + return null; + } const decorations = this.editor.getModel().getDecorationsInRange({ startLineNumber: position.lineNumber, startColumn: position.column, @@ -367,9 +372,9 @@ class LinkDetector implements editorCommon.IEditorContribution { return null; } - private isEnabled(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent): boolean { - return ( - mouseEvent.target.type === MouseTargetType.CONTENT_TEXT + private isEnabled(mouseEvent: ClickLinkMouseEvent, withKey?: ClickLinkKeyboardEvent | null): boolean { + return Boolean( + (mouseEvent.target && mouseEvent.target.type === MouseTargetType.CONTENT_TEXT) && (mouseEvent.hasTriggerModifier || (withKey && withKey.keyCodeIsTriggerKey)) ); } @@ -405,6 +410,9 @@ class OpenLinkAction extends EditorAction { if (!linkDetector) { return; } + if (!editor.hasModel()) { + return; + } let selections = editor.getSelections(); diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index 4fcd25fbd03..1c720f23753 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -9,9 +9,10 @@ import { first, createCancelablePromise, CancelablePromise, timeout } from 'vs/b import { onUnexpectedExternalError, onUnexpectedError } from 'vs/base/common/errors'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; +import * as arrays from 'vs/base/common/arrays'; import { registerEditorContribution, EditorAction, IActionOptions, registerEditorAction, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegistry } from 'vs/editor/common/modes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Position } from 'vs/editor/common/core/position'; import { Selection } from 'vs/editor/common/core/selection'; import { registerColor, editorSelectionHighlight, overviewRulerSelectionHighlightForeground, activeContrastBorder, editorSelectionHighlightBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -22,8 +23,7 @@ import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/cont import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { firstIndex, isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ITextModel, TrackedRangeStickiness, OverviewRulerLane, IModelDeltaDecoration } from 'vs/editor/common/model'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -38,17 +38,17 @@ export const overviewRulerWordHighlightStrongForeground = registerColor('editorO export const ctxHasWordHighlights = new RawContextKey('hasWordHighlights', false); -export function getOccurrencesAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { +export function getOccurrencesAtPosition(model: ITextModel, position: Position, token: CancellationToken): Promise { const orderedByScore = DocumentHighlightProviderRegistry.ordered(model); // in order of score ask the occurrences provider // until someone response with a good result // (good = none empty array) - return first(orderedByScore.map(provider => () => { + return first(orderedByScore.map(provider => () => { return Promise.resolve(provider.provideDocumentHighlights(model, position, token)) .then(undefined, onUnexpectedExternalError); - }), result => !isFalsyOrEmpty(result)); + }), result => !arrays.isFalsyOrEmpty(result)); } interface IOccurenceAtPositionRequest { @@ -59,7 +59,7 @@ interface IOccurenceAtPositionRequest { abstract class OccurenceAtPositionRequest implements IOccurenceAtPositionRequest { - private readonly _wordRange: Range; + private readonly _wordRange: Range | null; public readonly result: CancelablePromise; constructor(model: ITextModel, selection: Selection, wordSeparators: string) { @@ -69,7 +69,7 @@ abstract class OccurenceAtPositionRequest implements IOccurenceAtPositionRequest protected abstract _compute(model: ITextModel, selection: Selection, wordSeparators: string, token: CancellationToken): Thenable; - private _getCurrentWordRange(model: ITextModel, selection: Selection): Range { + private _getCurrentWordRange(model: ITextModel, selection: Selection): Range | null { const word = model.getWordAtPosition(selection.getPosition()); if (word) { return new Range(selection.startLineNumber, word.startColumn, selection.startLineNumber, word.endColumn); @@ -84,7 +84,7 @@ abstract class OccurenceAtPositionRequest implements IOccurenceAtPositionRequest const endColumn = selection.endColumn; const currentWordRange = this._getCurrentWordRange(model, selection); - let requestIsValid = (this._wordRange && this._wordRange.equalsRange(currentWordRange)); + let requestIsValid = Boolean(this._wordRange && this._wordRange.equalsRange(currentWordRange)); // Even if we are on a different word, if that word is in the decorations ranges, the request is still valid // (Same symbol) @@ -161,14 +161,14 @@ registerDefaultLanguageCommand('_executeDocumentHighlights', (model, position) = class WordHighlighter { - private editor: ICodeEditor; + private editor: IActiveCodeEditor; private occurrencesHighlight: boolean; private model: ITextModel; private _decorationIds: string[]; private toUnhook: IDisposable[]; private workerRequestTokenId: number = 0; - private workerRequest: IOccurenceAtPositionRequest; + private workerRequest: IOccurenceAtPositionRequest | null; private workerRequestCompleted: boolean = false; private workerRequestValue: DocumentHighlight[] = []; @@ -178,7 +178,7 @@ class WordHighlighter { private _hasWordHighlights: IContextKey; private _ignorePositionChangeEvent: boolean; - constructor(editor: ICodeEditor, contextKeyService: IContextKeyService) { + constructor(editor: IActiveCodeEditor, contextKeyService: IContextKeyService) { this.editor = editor; this._hasWordHighlights = ctxHasWordHighlights.bindTo(contextKeyService); this._ignorePositionChangeEvent = false; @@ -200,10 +200,6 @@ class WordHighlighter { this._onPositionChanged(e); })); - this.toUnhook.push(editor.onDidChangeModel((e) => { - this._stopAll(); - this.model = this.editor.getModel(); - })); this.toUnhook.push(editor.onDidChangeModelContent((e) => { this._stopAll(); })); @@ -236,14 +232,16 @@ class WordHighlighter { } private _getSortedHighlights(): Range[] { - return this._decorationIds - .map((id) => this.model.getDecorationRange(id)) - .sort(Range.compareRangesUsingStarts); + return arrays.coalesce( + this._decorationIds + .map((id) => this.model.getDecorationRange(id)) + .sort(Range.compareRangesUsingStarts) + ); } public moveNext() { let highlights = this._getSortedHighlights(); - let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let index = arrays.firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); let newIndex = ((index + 1) % highlights.length); let dest = highlights[newIndex]; try { @@ -257,7 +255,7 @@ class WordHighlighter { public moveBack() { let highlights = this._getSortedHighlights(); - let index = firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); + let index = arrays.firstIndex(highlights, (range) => range.containsPosition(this.editor.getPosition())); let newIndex = ((index - 1 + highlights.length) % highlights.length); let dest = highlights[newIndex]; try { @@ -461,7 +459,7 @@ class WordHighlighter { } } -class WordHighlighterContribution implements editorCommon.IEditorContribution { +class WordHighlighterContribution extends Disposable implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.wordHighlighter'; @@ -469,10 +467,23 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution { return editor.getContribution(WordHighlighterContribution.ID); } - private wordHighligher: WordHighlighter; + private wordHighligher: WordHighlighter | null; constructor(editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { - this.wordHighligher = new WordHighlighter(editor, contextKeyService); + super(); + const createWordHighlighterIfPossible = () => { + if (editor.hasModel()) { + this.wordHighligher = new WordHighlighter(editor, contextKeyService); + } + }; + this._register(editor.onDidChangeModel((e) => { + if (this.wordHighligher) { + this.wordHighligher.dispose(); + this.wordHighligher = null; + } + createWordHighlighterIfPossible(); + })); + createWordHighlighterIfPossible(); } public getId(): string { @@ -480,28 +491,36 @@ class WordHighlighterContribution implements editorCommon.IEditorContribution { } public saveViewState(): boolean { - if (this.wordHighligher.hasDecorations()) { + if (this.wordHighligher && this.wordHighligher.hasDecorations()) { return true; } return false; } public moveNext() { - this.wordHighligher.moveNext(); + if (this.wordHighligher) { + this.wordHighligher.moveNext(); + } } public moveBack() { - this.wordHighligher.moveBack(); + if (this.wordHighligher) { + this.wordHighligher.moveBack(); + } } public restoreViewState(state: boolean | undefined): void { - if (state) { + if (this.wordHighligher && state) { this.wordHighligher.restore(); } } public dispose(): void { - this.wordHighligher.dispose(); + if (this.wordHighligher) { + this.wordHighligher.dispose(); + this.wordHighligher = null; + } + super.dispose(); } } diff --git a/src/vs/editor/standalone/browser/colorizer.ts b/src/vs/editor/standalone/browser/colorizer.ts index 47a2bc4aa05..245b4559fef 100644 --- a/src/vs/editor/standalone/browser/colorizer.ts +++ b/src/vs/editor/standalone/browser/colorizer.ts @@ -31,29 +31,32 @@ export class Colorizer { let mimeType = options.mimeType || domNode.getAttribute('lang') || domNode.getAttribute('data-lang'); if (!mimeType) { console.error('Mode not detected'); - return undefined; + return Promise.resolve(); } themeService.setTheme(theme); - let text = domNode.firstChild.nodeValue; + let text = domNode.firstChild ? domNode.firstChild.nodeValue : ''; domNode.className += ' ' + theme; let render = (str: string) => { domNode.innerHTML = str; }; - return this.colorize(modeService, text, mimeType, options).then(render, (err) => console.error(err)); + return this.colorize(modeService, text || '', mimeType, options).then(render, (err) => console.error(err)); } - public static colorize(modeService: IModeService, text: string, mimeType: string, options: IColorizerOptions): Promise { + public static colorize(modeService: IModeService, text: string, mimeType: string, options: IColorizerOptions | null | undefined): Promise { + let tabSize = 4; + if (options && typeof options.tabSize === 'number') { + tabSize = options.tabSize; + } + if (strings.startsWithUTF8BOM(text)) { text = text.substr(1); } let lines = text.split(/\r\n|\r|\n/); let language = modeService.getModeId(mimeType); - - options = options || {}; - if (typeof options.tabSize === 'undefined') { - options.tabSize = 4; + if (!language) { + return Promise.resolve(_fakeColorize(lines, tabSize)); } // Send out the event to create the mode @@ -61,7 +64,7 @@ export class Colorizer { let tokenizationSupport = TokenizationRegistry.get(language); if (tokenizationSupport) { - return Promise.resolve(_colorize(lines, options.tabSize, tokenizationSupport)); + return Promise.resolve(_colorize(lines, tabSize, tokenizationSupport)); } return new Promise((resolve, reject) => { @@ -77,18 +80,18 @@ export class Colorizer { timeout.dispose(); timeout = null; } - const tokenizationSupport = TokenizationRegistry.get(language); + const tokenizationSupport = TokenizationRegistry.get(language!); if (tokenizationSupport) { - return resolve(_colorize(lines, options.tabSize, tokenizationSupport)); + return resolve(_colorize(lines, tabSize, tokenizationSupport)); } - return resolve(_fakeColorize(lines, options.tabSize)); + return resolve(_fakeColorize(lines, tabSize)); }; // wait 500ms for mode to load, then give up timeout = new TimeoutTimer(); timeout.cancelAndSet(execute, 500); listener = TokenizationRegistry.onDidChange((e) => { - if (e.changedLanguages.indexOf(language) >= 0) { + if (e.changedLanguages.indexOf(language!) >= 0) { execute(); } }); diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index f8c84e50ead..9372dbd7e58 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -11,7 +11,7 @@ import { Position } from 'vs/editor/common/core/position'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { registerEditorAction, registerEditorContribution, EditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; -import { ICodeEditor, ContentWidgetPositionPreference, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, ContentWidgetPositionPreference, IContentWidget, IContentWidgetPosition, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { IModeService } from 'vs/editor/common/services/modeService'; import { TokenizationRegistry, LanguageIdentifier, FontStyle, StandardTokenType, ITokenizationSupport, IState, TokenMetadata } from 'vs/editor/common/modes'; import { CharCode } from 'vs/base/common/charCode'; @@ -32,7 +32,6 @@ class InspectTokensController extends Disposable implements IEditorContribution } private _editor: ICodeEditor; - private _standaloneThemeService: IStandaloneThemeService; private _modeService: IModeService; private _widget: InspectTokensWidget | null; @@ -43,7 +42,6 @@ class InspectTokensController extends Disposable implements IEditorContribution ) { super(); this._editor = editor; - this._standaloneThemeService = standaloneColorService; this._modeService = modeService; this._widget = null; @@ -68,7 +66,7 @@ class InspectTokensController extends Disposable implements IEditorContribution if (!this._editor.hasModel()) { return; } - this._widget = new InspectTokensWidget(this._editor, this._standaloneThemeService, this._modeService); + this._widget = new InspectTokensWidget(this._editor, this._modeService); } public stop(): void { @@ -164,15 +162,14 @@ class InspectTokensWidget extends Disposable implements IContentWidget { // Editor.IContentWidget.allowEditorOverflow public allowEditorOverflow = true; - private _editor: ICodeEditor; + private _editor: IActiveCodeEditor; private _modeService: IModeService; private _tokenizationSupport: ITokenizationSupport; private _model: ITextModel; private _domNode: HTMLElement; constructor( - editor: ICodeEditor, - standaloneThemeService: IStandaloneThemeService, + editor: IActiveCodeEditor, modeService: IModeService ) { super(); @@ -249,14 +246,14 @@ class InspectTokensWidget extends Disposable implements IContentWidget { } private _decodeMetadata(metadata: number): IDecodedMetadata { - let colorMap = TokenizationRegistry.getColorMap(); + let colorMap = TokenizationRegistry.getColorMap()!; let languageId = TokenMetadata.getLanguageId(metadata); let tokenType = TokenMetadata.getTokenType(metadata); let fontStyle = TokenMetadata.getFontStyle(metadata); let foreground = TokenMetadata.getForeground(metadata); let background = TokenMetadata.getBackground(metadata); return { - languageIdentifier: this._modeService.getLanguageIdentifier(languageId), + languageIdentifier: this._modeService.getLanguageIdentifier(languageId)!, tokenType: tokenType, fontStyle: fontStyle, foreground: colorMap[foreground], diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 35235073a96..f25911aa714 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -27,9 +27,9 @@ class StandaloneTheme implements IStandaloneTheme { public readonly themeName: string; private themeData: IStandaloneThemeData; - private colors: { [colorId: string]: Color }; - private defaultColors: { [colorId: string]: Color }; - private _tokenTheme: TokenTheme; + private colors: { [colorId: string]: Color } | null; + private defaultColors: { [colorId: string]: Color | null; }; + private _tokenTheme: TokenTheme | null; constructor(name: string, standaloneThemeData: IStandaloneThemeData) { this.themeData = standaloneThemeData; @@ -77,7 +77,7 @@ class StandaloneTheme implements IStandaloneTheme { return this.colors; } - public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color { + public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color | null { const color = this.getColors()[colorId]; if (color) { return color; @@ -88,7 +88,7 @@ class StandaloneTheme implements IStandaloneTheme { return null; } - private getDefault(colorId: ColorIdentifier): Color { + private getDefault(colorId: ColorIdentifier): Color | null { let color = this.defaultColors[colorId]; if (color) { return color; @@ -113,7 +113,7 @@ class StandaloneTheme implements IStandaloneTheme { public get tokenTheme(): TokenTheme { if (!this._tokenTheme) { let rules: ITokenThemeRule[] = []; - let encodedTokensColors = []; + let encodedTokensColors: string[] = []; if (this.themeData.inherit) { let baseData = getBuiltinRules(this.themeData.base); rules = baseData.rules; diff --git a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts index fbb0790bae1..0b59bc960a6 100644 --- a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts +++ b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts @@ -10,7 +10,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; class ToggleHighContrast extends EditorAction { - private _originalThemeName: string; + private _originalThemeName: string | null; constructor() { super({ diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 8c1006e4bea..6ecfcd74608 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -675,7 +675,7 @@ declare namespace monaco { * A function that compares ranges, useful for sorting ranges * It will first compare ranges on the startPosition and then on the endPosition */ - static compareRangesUsingStarts(a: IRange, b: IRange): number; + static compareRangesUsingStarts(a: IRange | null | undefined, b: IRange | null | undefined): number; /** * A function that compares ranges, useful for sorting ranges * It will first compare ranges on the endPosition and then on the startPosition @@ -4403,11 +4403,11 @@ declare namespace monaco.languages { /** * The line comment token, like `// this is a comment` */ - lineComment?: string; + lineComment?: string | null; /** * The block comment character pair, like `/* block comment */` */ - blockComment?: CharacterPair; + blockComment?: CharacterPair | null; } /** diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index a06dafa5d90..a719d8647dd 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -52,7 +52,7 @@ export interface ITheme { * @param color the id of the color * @param useDefault specifies if the default color should be used. If not set, the default is used. */ - getColor(color: ColorIdentifier, useDefault?: boolean): Color; + getColor(color: ColorIdentifier, useDefault?: boolean): Color | null; /** * Returns wheter the theme defines a value for the color. If not, that means the