enableBreakpointsFor?: { languageIds: string[] }; configurationAttributes?: any; initialConfigurations?: any[]; <ins> aiKey?: string; </ins> win?: IRawEnvAdapter; winx86?: IRawEnvAdapter; windows?: IRawEnvAdapter;


import { TPromise } from 'vs/base/common/winjs.base'; import editor = require('vs/editor/common/editorCommon'); import aria = require('vs/base/browser/ui/aria/aria'); <ins> import { AIAdapter } from 'vs/base/node/aiAdapter'; </ins> import editorbrowser = require('vs/editor/browser/editorBrowser'); import { IKeybindingService, IKeybindingContextKey } from 'vs/platform/keybinding/common/keybindingService'; import {IMarkerService} from 'vs/platform/markers/common/markers';


private viewModel: viewmodel.ViewModel; private configurationManager: ConfigurationManager; private debugStringEditorInputs: DebugStringEditorInput[]; <ins> private telemetryAdapter: AIAdapter; </ins> private lastTaskEvent: TaskEvent; private toDispose: lifecycle.IDisposable[]; private inDebugMode: IKeybindingContextKey<boolean>;


this.toDispose.push(this.session.addListener2(debug.SessionEvents.OUTPUT, (event: DebugProtocol.OutputEvent) => { if (event.body && event.body.category === 'telemetry') { <del> this.telemetryService.publicLog(event.body.output, event.body.data); </del> <ins> const key = this.configurationManager.getAdapter().aiKey; // only log telemetry events from debug adapter if the adapter provided the telemetry key if (key) { if (!this.telemetryAdapter) { this.telemetryAdapter = new AIAdapter(key, this.session.getType()); } this.telemetryAdapter.log(event.body.output, event.body.data); } </ins> } else if (event.body && typeof event.body.output === 'string' && event.body.output.length > 0) { this.onOutput(event); }


}); this.model.updateBreakpoints(data); <ins> if (this.telemetryAdapter) { this.telemetryAdapter.dispose(); this.telemetryAdapter = null; } </ins> this.inDebugMode.reset(); }


private configurationAttributes: any; public initialConfigurations: any[]; public enableBreakpointsFor: { languageIds: string[] }; <ins> public aiKey: string; </ins> constructor(rawAdapter: debug.IRawAdapter, systemVariables: SystemVariables, extensionFolderPath: string) { if (rawAdapter.windows) {


this.initialConfigurations = rawAdapter.initialConfigurations; this._label = rawAdapter.label; this.enableBreakpointsFor = rawAdapter.enableBreakpointsFor; <ins> this.aiKey = rawAdapter.aiKey; </ins> } public get label() {


// Trim whitespaces path = strings.trim(strings.trim(path, ' '), 't'); <del> // Remove trailing dots path = strings.rtrim(path, '.'); </del> return path; }


.monaco-editor .detected-link, .monaco-editor .detected-link-active { text-decoration: underline; <ins> text-underline-position: under; </ins> } .monaco-editor .detected-link-active {


"type": "boolean", "description": "%config.enableSmartCommit%", "default": false <ins> }, "git.enableCommitSigning": { "type": "boolean", "description": "%config.enableCommitSigning%", "default": false </ins> } } }


"config.ignoreLegacyWarning": "Ignores the legacy Git warning", "config.ignoreLimitWarning": "Ignores the warning when there are too many changes in a repository", "config.defaultCloneDirectory": "The default location where to clone a git repository", <del> "config.enableSmartCommit": "Commit all changes when there are no staged changes." </del> <ins> "config.enableSmartCommit": "Commit all changes when there are no staged changes.", "config.enableCommitSigning": "Enables commit signing with GPG." </ins> }  No newline at end of file


): Promise<boolean> { const config = workspace.getConfiguration('git'); const enableSmartCommit = config.get<boolean>('enableSmartCommit') === true; <ins> const enableCommitSigning = config.get<boolean>('enableCommitSigning') === true; </ins> const noStagedChanges = this.model.indexGroup.resources.length === 0; const noUnstagedChanges = this.model.workingTreeGroup.resources.length === 0;


opts = { all: noStagedChanges }; } <ins> // enable signing of commits if configurated opts.signCommit = enableCommitSigning; </ins> if ( // no changes (noStagedChanges && noUnstagedChanges)


} } <del> async commit(message: string, opts: { all?: boolean, amend?: boolean, signoff?: boolean } = Object.create(null)): Promise<void> { </del> <ins> async commit(message: string, opts: { all?: boolean, amend?: boolean, signoff?: boolean, signCommit?: boolean } = Object.create(null)): Promise<void> { </ins> const args = ['commit', '--quiet', '--allow-empty-message', '--file', '-']; if (opts.all) {


args.push('--signoff'); } <ins> if (opts.signCommit) { args.push('-S'); } </ins> try { await this.run(args, { input: message || '' }); } catch (commitErr) {


all?: boolean; amend?: boolean; signoff?: boolean; <ins> signCommit?: boolean; </ins> } export class Model implements Disposable {


return function () { var desktop = gulp.src('resources/linux/code.desktop', { base: '.' }) .pipe(replace('@@NAME_LONG@@', product.nameLong)) <ins> .pipe(replace('@@NAME_SHORT@@', product.nameShort)) </ins> .pipe(replace('@@NAME@@', product.applicationName)) .pipe(rename('usr/share/applications/' + product.applicationName + '.desktop'));


return function () { var desktop = gulp.src('resources/linux/code.desktop', { base: '.' }) .pipe(replace('@@NAME_LONG@@', product.nameLong)) <ins> .pipe(replace('@@NAME_SHORT@@', product.nameShort)) </ins> .pipe(replace('@@NAME@@', product.applicationName)) .pipe(rename('BUILD/usr/share/applications/' + product.applicationName + '.desktop'));


Name=@@NAME_LONG@@ Comment=Code Editing. Redefined. GenericName=Text Editor <del> Exec=/usr/bin/@@NAME@@ %U </del> <ins> Exec=/usr/share/@@NAME@@/@@NAME@@ %U </ins> Icon=@@NAME@@ Type=Application StartupNotify=true <del> StartupWMClass=@@NAME@@ </del> <ins> StartupWMClass=@@NAME_SHORT@@ </ins> Categories=Utility;TextEditor;Development;IDE; MimeType=text/plain; Actions=new-window;


Name[ru]=Новое окно Name[zh_CN]=新建窗口 Name[zh_TW]=開新視窗 <del> Exec=/usr/bin/@@NAME@@ --new-window %U </del> <ins> Exec=/usr/share/@@NAME@@/@@NAME@@ --new-window %U </ins> Icon=@@NAME@@


this.focusTerminal(); } })); <ins> this.toDispose.push(DOM.addDisposableListener(this.parentDomElement, 'keyup', (event: KeyboardEvent) => { // Keep terminal open on escape if (event.keyCode === 27) { event.stopPropagation(); } })); </ins> this.toDispose.push(this.themeService.onDidThemeChange((themeId) => { <del> this.setTerminalTheme(themeId); </del> <ins> this.setTerminalTheme(); })); this.toDispose.push(this.configurationService.onDidUpdateConfiguration((e) => { this.setTerminalFont(); </ins> })); this.terminal.open(this.terminalDomElement); this.parentDomElement.appendChild(terminalScrollbar.getDomNode()); <del> let config = this.configurationService.getConfiguration<ITerminalConfiguration>(); this.terminalDomElement.style.fontFamily = config.terminal.integrated.fontFamily; this.setTerminalTheme(this.themeService.getTheme()); </del> <ins> this.setTerminalFont(); this.setTerminalTheme(); </ins> resolve(void 0); }); } <del> private setTerminalTheme(themeId: string) { </del> <ins> private setTerminalTheme() { </ins> if (!this.terminal) { return; } <del> let baseThemeId = getBaseThemeId(themeId); </del> <ins> let baseThemeId = getBaseThemeId(this.themeService.getTheme()); </ins> this.terminal.colors = DEFAULT_ANSI_COLORS[baseThemeId]; this.terminal.refresh(0, this.terminal.rows); } <ins> private setTerminalFont() { let config = this.configurationService.getConfiguration<ITerminalConfiguration>(); this.terminalDomElement.style.fontFamily = config.terminal.integrated.fontFamily; } </ins> public focus(): void { this.focusTerminal(true); }


private static COMMIT_KEYBINDING = Platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'; private static NEED_MESSAGE = nls.localize('needMessage', "Please provide a commit message. You can always press **{0}** to commit changes. If there are any staged changes, only those will be committed; otherwise, all changes will.", ChangesView.COMMIT_KEYBINDING); private static NOTHING_TO_COMMIT = nls.localize('nothingToCommit', "Once there are some changes to commit, type in the commit message and either press **{0}** to commit changes. If there are any staged changes, only those will be committed; otherwise, all changes will.", ChangesView.COMMIT_KEYBINDING); <ins> private static LONG_COMMIT = nls.localize('longCommit', "Great commit summaries are 50 characters or less. Place extra information in next lines."); </ins> private instantiationService: IInstantiationService; private editorService: IWorkbenchEditorService;


placeholder: nls.localize('commitMessage', "Message (press {0} to commit)", ChangesView.COMMIT_KEYBINDING), validationOptions: { showMessage: true, <del> validation: (): InputBox.IMessage => null </del> <ins> validation: (value): InputBox.IMessage => { if (Strings.trim(value.split('n')[0]).length > 50) { return { content: ChangesView.LONG_COMMIT, type: InputBox.MessageType.WARNING }; } return null; } </ins> }, ariaLabel: nls.localize('commitMessageAriaLabel', "Git: Type commit message and press {0} to commit", ChangesView.COMMIT_KEYBINDING), flexibleHeight: true


class NoUnexternalizedStringsRuleWalker extends Lint.RuleWalker { <del> private static ImportFailureMessage = 'Do not use double qoutes for imports.'; </del> <ins> private static ImportFailureMessage = 'Do not use double quotes for imports.'; </ins> private static DOUBLE_QUOTE: string = '"';


* Writes text to the system clipboard. */ writeText(text: string): void; <ins> /** * Reads the content of the clipboard in plain text */ readText(): string; </ins> }  No newline at end of file


public writeText(text: string): void { clipboard.writeText(text); } <ins> public readText(): string { return clipboard.readText(); } </ins> }  No newline at end of file


import { Action, IAction } from 'vs/base/common/actions'; import { ActionItem, BaseActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions'; <del> import { GlobalNewUntitledFileAction, SaveFileAsAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction } from 'vs/workbench/parts/files/browser/fileActions'; </del> <ins> import { GlobalNewUntitledFileAction, SaveFileAsAction, ShowOpenedFileInNewWindow, CopyPathAction, GlobalCopyPathAction, RevealInOSAction, GlobalRevealInOSAction, pasteIntoFocusedFilesExplorerViewItem, FocusOpenEditorsView, FocusFilesExplorer, GlobalCompareResourcesAction, GlobalNewFileAction, GlobalNewFolderAction, RevertFileAction, SaveFilesAction, SaveAllAction, SaveFileAction, MoveFileToTrashAction, TriggerRenameFileAction, PasteFileAction, CopyFileAction, SelectResourceForCompareAction, CompareResourcesAction, NewFolderAction, NewFileAction, OpenToSideAction, ShowActiveFileInExplorer, CollapseExplorerView, RefreshExplorerView, CompareWithSavedAction, CompareWithClipboardAction } from 'vs/workbench/parts/files/browser/fileActions'; </ins> import { revertLocalChangesCommand, acceptLocalChangesCommand, CONFLICT_RESOLUTION_CONTEXT } from 'vs/workbench/parts/files/browser/saveErrorHandler'; import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';


registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRevealInOSAction, GlobalRevealInOSAction.ID, GlobalRevealInOSAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_R) }), 'File: Reveal Active File', category); registry.registerWorkbenchAction(new SyncActionDescriptor(ShowOpenedFileInNewWindow, ShowOpenedFileInNewWindow.ID, ShowOpenedFileInNewWindow.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_O) }), 'File: Open Active File in New Window', category); registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithSavedAction, CompareWithSavedAction.ID, CompareWithSavedAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_D) }), 'File: Compare Active File with Saved', category); <ins> registry.registerWorkbenchAction(new SyncActionDescriptor(CompareWithClipboardAction, CompareWithClipboardAction.ID, CompareWithClipboardAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_C) }), 'File: Compare Active File with Clipboard', category); </ins> // Commands CommandsRegistry.registerCommand('_files.windowOpen', openWindowCommand);


import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService'; <del> import { IEditorViewState } from 'vs/editor/common/editorCommon'; </del> <ins> import { IEditorViewState, IModel } from 'vs/editor/common/editorCommon'; </ins> import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, copyPathCommand } from 'vs/workbench/parts/files/browser/fileCommands'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; <del> import { ITextModelService } from 'vs/editor/common/services/resolverService'; </del> <ins> import { ITextModelService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; </ins> import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { once } from 'vs/base/common/event'; <ins> import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; </ins> export interface IEditableData { action: IAction;


} } <ins> export class CompareWithClipboardAction extends Action { public static ID = 'workbench.files.action.compareWithClipboard'; public static LABEL = nls.localize('compareWithClipboard', "Compare Active File with Clipboard"); private static SCHEME = 'clipboard'; private toDispose: IDisposable[]; constructor( id: string, label: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IInstantiationService private instantiationService: IInstantiationService, @ITextModelService private textModelService: ITextModelService, ) { super(id, label); this.enabled = true; this.toDispose = []; } public run(): TPromise<any> { let resource: URI = toResource(this.editorService.getActiveEditorInput(), { supportSideBySide: true, filter: 'file' } ); const provider = this.instantiationService.createInstance(ClipboardContentProvider); const registrationDisposal = this.textModelService.registerTextModelContentProvider(CompareWithClipboardAction.SCHEME, provider); this.toDispose.push(registrationDisposal); if (resource) { const name = paths.basename(resource.fsPath); const editorLabel = nls.localize('clipboardComparisonLabel', "Clipboard ↔ {0}", name); return this.editorService.openEditor({ leftResource: URI.from({ scheme: CompareWithClipboardAction.SCHEME, path: resource.fsPath }), rightResource: resource, label: editorLabel }); } return TPromise.as(true); } public dispose(): void { super.dispose(); this.toDispose = dispose(this.toDispose); } } class ClipboardContentProvider implements ITextModelContentProvider { constructor( @IClipboardService private clipboardService: IClipboardService, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService ) { } provideTextContent(resource: URI): TPromise<IModel> { const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.getOrCreateMode('text/plain'), resource); return TPromise.as(model); } } </ins> // Diagnostics support let diag: (...args: any[]) => void; if (!diag) {


getLineNumberAtVerticalOffset(verticalOffset: number): number; getVerticalOffsetForLineNumber(lineNumber: number): number; getWhitespaceAtVerticalOffset(verticalOffset:number): editorCommon.IViewWhitespaceViewportData; <del> shouldSuppressMouseDownOnViewZone(viewZoneId:number): boolean; </del> <ins> shouldSuppressMouseDownOnViewZone(viewZoneId: number): boolean; shouldSuppressMouseDownOnWidget(widgetId: string): boolean; </ins> /** * Decode an Editor.IPosition from a rendered dom node


let targetIsLineNumbers = (t.type === editorCommon.MouseTargetType.GUTTER_LINE_NUMBERS); let selectOnLineNumbers = this._context.configuration.editor.viewInfo.selectOnLineNumbers; let targetIsViewZone = (t.type === editorCommon.MouseTargetType.CONTENT_VIEW_ZONE || t.type === editorCommon.MouseTargetType.GUTTER_VIEW_ZONE); <ins> let targetIsWidget = (t.type === editorCommon.MouseTargetType.CONTENT_WIDGET); </ins> let shouldHandle = e.leftButton; if (platform.isMacintosh && e.ctrlKey) { shouldHandle = false; } <del> if (shouldHandle && (targetIsContent || (targetIsLineNumbers && selectOnLineNumbers))) { </del> <ins> var focus = () => { </ins> if (browser.isIE11orEarlier) { // IE does not want to focus when coming in from the browser's address bar if ((<any>e.browserEvent).fromElement) {


e.preventDefault(); this.viewHelper.focusTextArea(); } <ins> }; if (shouldHandle && (targetIsContent || (targetIsLineNumbers && selectOnLineNumbers))) { focus(); </ins> this._mouseDownOperation.start(t.type, e); } else if (targetIsGutter) {


} else if (targetIsViewZone) { let viewZoneData = <editorBrowser.IViewZoneData>t.detail; if (this.viewHelper.shouldSuppressMouseDownOnViewZone(viewZoneData.viewZoneId)) { <ins> focus(); this._mouseDownOperation.start(t.type, e); </ins> e.preventDefault(); } <ins> } else if (targetIsWidget && this.viewHelper.shouldSuppressMouseDownOnWidget(<string>t.detail)) { focus(); e.preventDefault(); </ins> } this.viewController.emitMouseDown({


} return this.viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId); }, <ins> shouldSuppressMouseDownOnWidget: (widgetId: string) => { if (this._isDisposed) { throw new Error('ViewImpl.pointerHandler.shouldSuppressMouseDownOnWidget: View is disposed'); } return this.contentWidgets.shouldSuppressMouseDownOnWidget(widgetId); }, </ins> getPositionFromDOMInfo: (spanNode: HTMLElement, offset: number) => { if (this._isDisposed) { throw new Error('ViewImpl.pointerHandler.getPositionFromDOMInfo: View is disposed');


} } <ins> public shouldSuppressMouseDownOnWidget(widgetId: string): boolean { if (this._widgets.hasOwnProperty(widgetId)) { let widgetData = this._widgets[widgetId]; return widgetData.widget.suppressMouseDown; } return false; } </ins> private _layoutBoxInViewport(position:Position, domNode:HTMLElement, ctx:IRenderingContext): IBoxLayoutResult { let visibleRange = ctx.visibleRangeForPosition(position);


private static ID: number = 0; <ins> public suppressMouseDown: boolean; </ins> private _id: string; private _domNode: HTMLElement;


this._id = 'codeLensWidget' + (++CodeLensContentWidget.ID); this._editor = editor; <ins> this.suppressMouseDown = true; </ins> this.setSymbolRange(symbolRange); this._domNode = document.createElement('span');


* Render this content widget in a location where it could overflow the editor's view dom node. */ allowEditorOverflow?: boolean; <ins> suppressMouseDown?: boolean; </ins> /** * Get a unique identifier of the content widget. */


public $show(terminalId: number, preserveFocus: boolean): void { this._terminalService.show(!preserveFocus).then((terminalPanel) => { this._terminalService.setActiveTerminalById(terminalId); <ins> if (!preserveFocus) { // If the panel was already showing an explicit focus call is necessary here. terminalPanel.focus(); } </ins> }); }


export interface ITerminalPanel { closeTerminalById(terminalId: number): TPromise<void>; <ins> focus(): void; </ins> sendTextToActiveTerminal(text: string, addNewLine: boolean): void; }


return this.show(false).then((terminalPanel) => { this.activeTerminalIndex = index; terminalPanel.setActiveTerminal(this.activeTerminalIndex); <del> terminalPanel.focus(); </del> this._onActiveInstanceChanged.fire(); }); }


// Escape codes // http://en.wikipedia.org/wiki/ANSI_escape_code const EL = /x1Bx5B[12]?K/g; // Erase in line <del> const LF = /xA/g; // line feed </del> const COLOR_START = /x1b[d+m/g; // Color const COLOR_END = /x1b[0?m/g; // Color export function removeAnsiEscapeCodes(str: string): string { if (str) { str = str.replace(EL, ''); <del> str = str.replace(LF, 'n'); </del> str = str.replace(COLOR_START, ''); str = str.replace(COLOR_END, ''); }


return clb(startPort); }); <del> client.connect(startPort); </del> <ins> client.connect(startPort, '127.0.0.1'); </ins> } function dispose(socket: net.Socket): void {


} .monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) { <del> max-width: 500px; </del> word-wrap: break-word; }


position: absolute; width: 100%; height: 100%; <del> background: transparent; </del> <ins> background: red; </ins> } .monaco-workbench:not(.reduce-motion) .monaco-sash:before {


import { Context as SuggestContext } from 'vs/editor/contrib/suggest/browser/suggest'; import { AsyncIterableObject } from 'vs/base/common/async'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; <ins> import { ResizableHoverWidget } from 'vs/editor/contrib/hover/browser/resizableHoverWidget'; </ins> const $ = dom.$; export class ContentHoverController extends Disposable { private readonly _participants: IEditorHoverParticipant[]; <del> private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); </del> <ins> // INITIALLY: private readonly _widget = this._register(this._instantiationService.createInstance(ContentHoverWidget, this._editor)); private readonly _widget; </ins> private readonly _computer: ContentHoverComputer; private readonly _hoverOperation: HoverOperation<IHoverPart>;


) { super(); <ins> this._widget = this._register(this._instantiationService.createInstance(ResizableHoverWidget, this._editor)); </ins> // Instantiate participants and sort them by `hoverOrdinal` which is relevant for rendering order. this._participants = []; for (const participant of HoverParticipantRegistry.getAll()) {


<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ .monaco-editor .resizable-widget { z-index: 40; display: block; } </ins>


<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { IResizeEvent, ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable'; import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IPosition } from 'vs/editor/common/core/position'; import { PositionAffinity } from 'vs/editor/common/model'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import * as dom from 'vs/base/browser/dom'; import { clamp } from 'vs/base/common/numbers'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; import { Emitter, Event } from 'vs/base/common/event'; export abstract class ResizableWidget implements IDisposable { readonly element: ResizableHTMLElement; private readonly _disposables = new DisposableStore(); private readonly _persistingMechanism: IPersistingMechanism; constructor( private readonly _editor: ICodeEditor, private readonly _persistingOptions: IPersistingOptions, ) { console.log('Inside of ResizableWidget constructor'); this.element = new ResizableHTMLElement(); this.element.domNode.classList.add('editor-widget', 'resizable-widget'); if (this._persistingOptions instanceof SingleSizePersistingOptions) { this._persistingMechanism = new SingleSizePersistingMechanism(this, this.element, this._editor, this._persistingOptions); } else if (this._persistingOptions instanceof MultipleSizePersistingOptions) { this._persistingMechanism = new MultipleSizePersistingMechanism(this, this.element, this._editor); } else { throw new Error('Please specify a valid persisting mechanism'); } } dispose(): void { this._disposables.dispose(); this.element.dispose(); } resize(dimension: dom.Dimension): void { } hide(): void { this.element.clearSashHoverState(); } findMaximumRenderingHeight(): number | undefined { return Infinity; } findMaximumRenderingWidth(): number | undefined { return Infinity; } findPersistedSize(): dom.Dimension | undefined { return this._persistingMechanism.findSize(); } } export abstract class ResizableContentWidget implements IContentWidget { abstract ID: string; private _position: IPosition | null = null; private _secondaryPosition: IPosition | null = null; private _preference: ContentWidgetPositionPreference[] = []; private _positionAffinity: PositionAffinity | undefined = undefined; constructor(private readonly resizableWidget: ResizableWidget, private readonly editor: ICodeEditor) { this.editor.addContentWidget(this); console.log('Inisde of ResizableContentWidget constructor'); } findPersistedSize(): dom.Dimension | undefined { return this.resizableWidget.findPersistedSize(); } getId(): string { console.log('this.ID : ', this.ID); return this.ID; } getDomNode(): HTMLElement { console.log('Inside of getDomNode of ResizableContentWidget'); console.log('this.resizableWidget.element.domNode : ', this.resizableWidget.element.domNode); this.resizableWidget.element.domNode.style.zIndex = '49'; this.resizableWidget.element.domNode.style.position = 'fixed'; // this.resizableWidget.element.domNode.style.display = 'block'; return this.resizableWidget.element.domNode; } getPosition(): IContentWidgetPosition | null { console.log('Inside of getPosition of ResizableContentWidget'); const contentWidgetPosition = { position: this._position, secondaryPosition: this._secondaryPosition, preference: (this._preference), positionAffinity: this._positionAffinity }; console.log('contentWidgetPosition: ', contentWidgetPosition); return contentWidgetPosition; } hide(): void { this.editor.layoutContentWidget(this); } set position(position: IPosition | null) { this._position = position; } set secondaryPosition(position: IPosition | null) { this._secondaryPosition = position; } set preference(preference: ContentWidgetPositionPreference[]) { this._preference = preference; } set positionAffinity(affinity: PositionAffinity | undefined) { this._positionAffinity = affinity; } } interface IPersistingOptions { } export class SingleSizePersistingOptions implements IPersistingOptions { constructor( public readonly key: string, public readonly defaultSize: dom.Dimension, @IStorageService public readonly storageService: IStorageService ) { } } export class MultipleSizePersistingOptions implements IPersistingOptions { constructor() { } } interface IPersistingMechanism extends IDisposable { findSize(): dom.Dimension | undefined; } // TODO: maybe need to make more generic, this is specific to the suggest widget class SingleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSize: PersistedWidgetSize | null = null; private readonly _disposables = new DisposableStore(); constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, private readonly editor: ICodeEditor, private readonly persistingOptions: SingleSizePersistingOptions ) { this._persistedWidgetSize = new PersistedWidgetSize(this.persistingOptions.key, this.persistingOptions.storageService, this.editor); class ResizeState { constructor( readonly persistedSize: dom.Dimension | undefined, readonly currentSize: dom.Dimension, public persistHeight = false, public persistWidth = false, ) { } } let state: ResizeState | undefined; this._disposables.add(this.element.onDidWillResize(() => { // TODO: add back, this._contentWidget.lockPreference(); state = new ResizeState(this._persistedWidgetSize!.restore(), this.element.size); })); this._disposables.add(this.element.onDidResize(e => { this.resizableWidget.resize(new dom.Dimension(e.dimension.width, e.dimension.height)); if (state) { state.persistHeight = state.persistHeight || !!e.north || !!e.south; state.persistWidth = state.persistWidth || !!e.east || !!e.west; } if (!e.done) { return; } if (state) { const fontInfo = this.editor.getOption(EditorOption.fontInfo); const itemHeight = clamp(this.editor.getOption(EditorOption.suggestLineHeight) || fontInfo.lineHeight, 8, 1000); const threshold = Math.round(itemHeight / 2); let { width, height } = this.element.size; if (!state.persistHeight || Math.abs(state.currentSize.height - height) <= threshold) { height = state.persistedSize?.height ?? this.persistingOptions.defaultSize.height; } if (!state.persistWidth || Math.abs(state.currentSize.width - width) <= threshold) { width = state.persistedSize?.width ?? this.persistingOptions.defaultSize.width; } this._persistedWidgetSize!.store(new dom.Dimension(width, height)); } // TODO: add back, reset working state // this._contentWidget.unlockPreference(); state = undefined; })); } findSize(): dom.Dimension | undefined { return undefined; } dispose(): void { this._disposables.dispose(); } } class MultipleSizePersistingMechanism implements IPersistingMechanism { private readonly _persistedWidgetSizes: ResourceMap<Map<string, dom.Dimension>> = new ResourceMap<Map<string, dom.Dimension>>(); private readonly _disposables = new DisposableStore(); private _tooltipPosition: IPosition | null = null; // TODO: not sure if I need the following // private _initialHeight: number = 0; // private _initialTop: number = 0; private _resizing: boolean = false; private _size: dom.Dimension | undefined = undefined; private _maxRenderingHeight: number | undefined = Infinity; private _maxRenderingWidth: number | undefined = Infinity; private readonly _onDidResize = new Emitter<IResizeEvent>(); readonly onDidResize: Event<IResizeEvent> = this._onDidResize.event; // private _renderingAbove: ContentWidgetPositionPreference | undefined = undefined; constructor( private readonly resizableWidget: ResizableWidget, private readonly element: ResizableHTMLElement, public readonly editor: ICodeEditor ) { this.element.minSize = new dom.Dimension(10, 24); this._disposables.add(this.editor.onDidChangeModelContent((e) => { const uri = this.editor.getModel()?.uri; if (!uri || !this._persistedWidgetSizes.has(uri)) { return; } const persistedSizesForUri = this._persistedWidgetSizes.get(uri)!; const updatedPersistedSizesForUri = new Map<string, dom.Dimension>(); for (const change of e.changes) { const changeOffset = change.rangeOffset; const rangeLength = change.rangeLength; const endOffset = changeOffset + rangeLength; const textLength = change.text.length; for (const key of persistedSizesForUri.keys()) { const parsedKey = JSON.parse(key); const tokenOffset = parsedKey[0]; const tokenLength = parsedKey[1]; if (endOffset < tokenOffset) { const oldSize = persistedSizesForUri.get(key)!; const newKey: [number, number] = [tokenOffset - rangeLength + textLength, tokenLength]; updatedPersistedSizesForUri.set(JSON.stringify(newKey), oldSize); } else if (changeOffset >= tokenOffset + tokenLength) { updatedPersistedSizesForUri.set(key, persistedSizesForUri.get(key)!); } } } this._persistedWidgetSizes.set(uri, updatedPersistedSizesForUri); })); this._disposables.add(this.element.onDidWillResize(() => { this._resizing = true; // this._initialHeight = this.element.domNode.clientHeight; // this._initialTop = this.element.domNode.offsetTop; })); this._disposables.add(this.element.onDidResize(e => { let height = e.dimension.height; let width = e.dimension.width; const maxWidth = this.element.maxSize.width; const maxHeight = this.element.maxSize.height; width = Math.min(maxWidth, width); height = Math.min(maxHeight, height); if (!this._maxRenderingHeight) { return; } this._size = new dom.Dimension(width, height); this.element.layout(height, width); // Calling the resize function of the this.resizableWidget.resize(new dom.Dimension(width, height)); // Update the top parameters only when we decided to render above // TODO: presumably do not need to resize the element // if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { // 	this.element.domNode.style.top = this._initialTop - (height - this._initialHeight) + 'px'; // } // const horizontalSashWidth = width - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.northSash.el.style.width = horizontalSashWidth; // this.element.southSash.el.style.width = horizontalSashWidth; // const verticalSashWidth = height - 2 * SASH_WIDTH + 2 * TOTAL_BORDER_WIDTH + 'px'; // this.element.eastSash.el.style.height = verticalSashWidth; // this.element.westSash.el.style.height = verticalSashWidth; // this.element.eastSash.el.style.top = TOTAL_BORDER_WIDTH + 'px'; // Fire the current dimension // TODO: probably don't need to listen on the firing event? // this._onDidResize.fire({ dimension: this._size, done: false }); this._maxRenderingWidth = this.resizableWidget.findMaximumRenderingWidth(); this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(); // this._maxRenderingHeight = this.resizableWidget.findMaximumRenderingHeight(this._renderingAbove); if (!this._maxRenderingHeight || !this._maxRenderingWidth) { return; } this.element.maxSize = new dom.Dimension(this._maxRenderingWidth, this._maxRenderingHeight); // Persist the height only when the resizing has stopped if (e.done) { if (!this.editor.hasModel()) { return; } const uri = this.editor.getModel().uri; if (!uri || !this._tooltipPosition) { return; } const persistedSize = new dom.Dimension(width, height); const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; // Suppose that the uri does not exist in the persisted widget hover sizes, then create a map if (!this._persistedWidgetSizes.get(uri)) { const persistedWidgetSizesForUri = new Map<string, dom.Dimension>([]); persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); this._persistedWidgetSizes.set(uri, persistedWidgetSizesForUri); } else { const persistedWidgetSizesForUri = this._persistedWidgetSizes.get(uri)!; persistedWidgetSizesForUri.set(JSON.stringify([offset, length]), persistedSize); } this._resizing = false; } // this.editor.layoutOverlayWidget(this); // this.editor.render(); })); } set tooltipPosition(position: IPosition) { this._tooltipPosition = position; } findSize(): dom.Dimension | undefined { console.log('Inside of findSize of the MultiplePersistingMechanisms'); if (!this._tooltipPosition || !this.editor.hasModel()) { return; } const wordPosition = this.editor.getModel().getWordAtPosition(this._tooltipPosition); if (!wordPosition) { return; } const offset = this.editor.getModel().getOffsetAt({ lineNumber: this._tooltipPosition.lineNumber, column: wordPosition.startColumn }); const length = wordPosition.word.length; const uri = this.editor.getModel().uri; const persistedSizesForUri = this._persistedWidgetSizes.get(uri); if (!persistedSizesForUri) { return; } return persistedSizesForUri.get(JSON.stringify([offset, length])); } dispose(): void { this._disposables.dispose(); } } class PersistedWidgetSize { constructor( private readonly _key: string, private readonly _service: IStorageService, editor: ICodeEditor ) { } restore(): dom.Dimension | undefined { const raw = this._service.get(this._key, StorageScope.PROFILE) ?? ''; try { const obj = JSON.parse(raw); if (dom.Dimension.is(obj)) { return dom.Dimension.lift(obj); } } catch { // ignore } return undefined; } store(size: dom.Dimension) { this._service.store(this._key, JSON.stringify(size), StorageScope.PROFILE, StorageTarget.MACHINE); } reset(): void { this._service.remove(this._key, StorageScope.PROFILE); } } </ins>


<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { MultipleSizePersistingOptions, ResizableContentWidget, ResizableWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget'; import * as dom from 'vs/base/browser/dom'; import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; import { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { PositionAffinity } from 'vs/editor/common/model'; import { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes'; const SCROLLBAR_WIDTH = 10; // TODO: maybe don't need the resizable widget class export class ResizableHoverWidget extends ResizableWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); // The ContentWidget is a child of the resizable widget private resizableContentWidget: ResizableContentHoverWidget; public readonly allowEditorOverflow = true; public readonly _hover: HoverWidget = this.hoverDisposables.add(new HoverWidget()); private readonly editor: ICodeEditor; private readonly _hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(this._contextKeyService); private readonly _hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(this._contextKeyService); private readonly _focusTracker = this.hoverDisposables.add(dom.trackFocus(this.getDomNode())); private readonly _horizontalScrollingBy: number = 30; private _visibleData: ContentHoverVisibleData | null = null; private _renderingAbove: ContentWidgetPositionPreference; constructor( editor: ICodeEditor, @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { super(editor, new MultipleSizePersistingOptions()); this.editor = editor; // create here the dom node and all other logic should go here that was in the super abstract class this.resizableContentWidget = new ResizableContentHoverWidget(this, editor); this._renderingAbove = this.editor.getOption(EditorOption.hover).above ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; this.hoverDisposables.add(this.element.onDidResize((e) => { // When the resizable hover overlay changes, resize the widget // this._widget.resize(e.dimension); })); this.hoverDisposables.add(this.editor.onDidLayoutChange(() => this._layout())); this.hoverDisposables.add(this.editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => { if (e.hasChanged(EditorOption.fontInfo)) { this._updateFont(); } })); this._setVisibleData(null); this._layout(); this.hoverDisposables.add(this._focusTracker.onDidFocus(() => { this._hoverFocusedKey.set(true); })); this.hoverDisposables.add(this._focusTracker.onDidBlur(() => { this._hoverFocusedKey.set(false); })); dom.append(this.element.domNode, this._hover.containerDomNode); } public get position(): Position | null { return this._visibleData?.showAtPosition ?? null; } public get isColorPickerVisible(): boolean { return Boolean(this._visibleData?.colorPicker); } public get isVisibleFromKeyboard(): boolean { return (this._visibleData?.source === HoverStartSource.Keyboard); } public get isVisible(): boolean { return this._hoverVisibleKey.get() ?? false; } public get renderingAbove(): ContentWidgetPositionPreference { return this._renderingAbove; } public set renderingAbove(renderingAbove: ContentWidgetPositionPreference) { this._renderingAbove = renderingAbove; } // NEW public override resize(size: dom.Dimension) { console.log('Inside of resize'); // Removing the max height and max width here - the max size is controlled by the resizable overlay this._hover.contentsDomNode.style.maxHeight = 'none'; this._hover.contentsDomNode.style.maxWidth = 'none'; const width = size.width + 'px'; // const width = size.width - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; this._hover.containerDomNode.style.width = width; this._hover.contentsDomNode.style.width = width; // const height = size.height - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH + 'px'; const height = size.height + 'px'; this._hover.containerDomNode.style.height = height; this._hover.contentsDomNode.style.height = height; const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // When there is a horizontal scroll-bar use a different height to make the scroll-bar visible const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; } this._hover.contentsDomNode.style.height = size.height - SCROLLBAR_WIDTH + 'px'; // - 2 * SASH_WIDTH + TOTAL_BORDER_WIDTH } this._hover.scrollbar.scanDomNode(); this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); } public override findMaximumRenderingHeight(): number | undefined { if (!this.editor || !this.editor.hasModel() || !this._visibleData?.showAtPosition) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const mouseBox = this.editor.getScrolledVisiblePosition(this._visibleData.showAtPosition); const bodyBox = dom.getClientArea(document.body); let availableSpace: number; if (this._renderingAbove === ContentWidgetPositionPreference.ABOVE) { availableSpace = editorBox.top + mouseBox.top - 30; } else { const mouseBottom = editorBox.top + mouseBox!.top + mouseBox!.height; availableSpace = bodyBox.height - mouseBottom; } let divMaxHeight = 0; for (const childHtmlElement of this._hover.contentsDomNode.children) { divMaxHeight += childHtmlElement.clientHeight; } if (this._hover.contentsDomNode.clientWidth < this._hover.contentsDomNode.scrollWidth) { divMaxHeight += SCROLLBAR_WIDTH; } return Math.min(availableSpace, divMaxHeight); } public findMaxRenderingWidth(): number | undefined { if (!this.editor || !this.editor.hasModel()) { return; } const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const widthOfEditor = editorBox.width; const leftOfEditor = editorBox.left; const glyphMarginWidth = this.editor.getLayoutInfo().glyphMarginWidth; const leftOfContainer = this._hover.containerDomNode.offsetLeft; return widthOfEditor + leftOfEditor - leftOfContainer - glyphMarginWidth; } public override dispose(): void { this.editor.removeContentWidget(this.resizableContentWidget); if (this._visibleData) { this._visibleData.disposables.dispose(); } super.dispose(); } public getDomNode() { return this._hover.containerDomNode; } public getContentsDomNode() { return this._hover.contentsDomNode; } public isMouseGettingCloser(posx: number, posy: number): boolean { if (!this._visibleData) { return false; } if (typeof this._visibleData.initialMousePosX === 'undefined' || typeof this._visibleData.initialMousePosY === 'undefined') { this._visibleData.initialMousePosX = posx; this._visibleData.initialMousePosY = posy; return false; } const widgetRect = dom.getDomNodePagePosition(this.resizableContentWidget.getDomNode()); if (typeof this._visibleData.closestMouseDistance === 'undefined') { this._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(this._visibleData.initialMousePosX, this._visibleData.initialMousePosY, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); } const distance = computeDistanceFromPointToRectangle(posx, posy, widgetRect.left, widgetRect.top, widgetRect.width, widgetRect.height); if (!distance || !this._visibleData.closestMouseDistance || distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) { // The mouse is getting farther away return false; } this._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance); return true; } private _setVisibleData(visibleData: ContentHoverVisibleData | null): void { if (this._visibleData) { this._visibleData.disposables.dispose(); } this._visibleData = visibleData; this._hoverVisibleKey.set(!!this._visibleData); this._hover.containerDomNode.classList.toggle('hidden', !this._visibleData); } private _layout(): void { const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); const { fontSize, lineHeight } = this.editor.getOption(EditorOption.fontInfo); this._hover.contentsDomNode.style.fontSize = `${fontSize}px`; this._hover.contentsDomNode.style.lineHeight = `${lineHeight / fontSize}`; this._hover.contentsDomNode.style.maxHeight = `${height}px`; this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; } private _updateFont(): void { const codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code')); codeClasses.forEach(node => this.editor.applyFontInfo(node)); } public showAt(node: DocumentFragment, visibleData: ContentHoverVisibleData): void { this.editor.addContentWidget(this.resizableContentWidget); const persistedSize = this.findPersistedSize(); if (!this.editor || !this.editor.hasModel()) { return; } this._setVisibleData(visibleData); this._hover.contentsDomNode.textContent = ''; this._hover.contentsDomNode.appendChild(node); this._hover.contentsDomNode.style.paddingBottom = ''; this._updateFont(); const containerDomNode = this.resizableContentWidget.getDomNode(); let height; // If the persisted size has already been found then set a maximum height and width if (!persistedSize) { this._hover.contentsDomNode.style.maxHeight = `${Math.max(this.editor.getLayoutInfo().height / 4, 250)}px`; this._hover.contentsDomNode.style.maxWidth = `${Math.max(this.editor.getLayoutInfo().width * 0.66, 500)}px`; this.onContentsChanged(); // Simply force a synchronous render on the editor // such that the widget does not really render with left = '0px' this.editor.render(); height = containerDomNode.clientHeight; } // When there is a persisted size then do not use a maximum height or width else { this._hover.contentsDomNode.style.maxHeight = 'none'; this._hover.contentsDomNode.style.maxWidth = 'none'; height = persistedSize.height; } // The dimensions of the document in which we are displaying the hover const bodyBox = dom.getClientArea(document.body); // Hard-coded in the hover.css file as 1.5em or 24px const minHeight = 24; // The full height is already passed in as a parameter const fullHeight = height; const editorBox = dom.getDomNodePagePosition(this.editor.getDomNode()); const mouseBox = this.editor.getScrolledVisiblePosition(visibleData.showAtPosition); // Position where the editor box starts + the top of the mouse box relatve to the editor + mouse box height const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height; // Total height of the box minus the position of the bottom of the mouse, this is the maximum height below the mouse position const availableSpaceBelow = bodyBox.height - mouseBottom; // Max height below is the minimum of the available space below and the full height of the widget const maxHeightBelow = Math.min(availableSpaceBelow, fullHeight); // The available space above the mouse position is the height of the top of the editor plus the top of the mouse box relative to the editor const availableSpaceAbove = editorBox.top + mouseBox.top - 30; const maxHeightAbove = Math.min(availableSpaceAbove, fullHeight); // We find the maximum height of the widget possible on the top or on the bottom const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), fullHeight); if (height < minHeight) { height = minHeight; } if (height > maxHeight) { height = maxHeight; } // Determining whether we should render above or not ideally if (this.editor.getOption(EditorOption.hover).above) { this._renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW; } else { this._renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE; } // See https://github.com/microsoft/vscode/issues/140339 // TODO: Doing a second layout of the hover after force rendering the editor if (!persistedSize) { this.onContentsChanged(); } if (visibleData.stoleFocus) { this._hover.containerDomNode.focus(); } visibleData.colorPicker?.layout(); if (!this._visibleData) { return; } const clientHeight = this._hover.containerDomNode.clientHeight; const clientWidth = this._hover.containerDomNode.clientWidth; this.element.layout(clientHeight, clientWidth); this.resizableContentWidget.position = this._visibleData.showAtPosition; this.resizableContentWidget.secondaryPosition = this._visibleData.showAtSecondaryPosition; this.resizableContentWidget.preference = [this._renderingAbove]; this.resizableContentWidget.positionAffinity = this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined; this.editor.layoutContentWidget(this.resizableContentWidget); this.editor.render(); console.log('At the end of showAt'); } public override hide(): void { this.element.clearSashHoverState(); if (this._visibleData) { const stoleFocus = this._visibleData.stoleFocus; this._setVisibleData(null); this.editor.layoutContentWidget(this.resizableContentWidget); if (stoleFocus) { this.editor.focus(); } } } // NEW public onContentsChanged(persistedSize?: dom.Dimension | undefined): void { console.log('Inside of onContentsChanged'); const containerDomNode = this.getDomNode(); const contentsDomNode = this.getContentsDomNode(); // Suppose a persisted size is defined if (persistedSize) { const widthMinusSash = Math.min(this.findMaximumRenderingWidth() ?? Infinity, persistedSize.width); //  - SASH_WIDTH // const heightMinusSash = Math.min(this.findMaxRenderingHeight(this._renderingAbove) ?? Infinity, persistedSize.height - SASH_WIDTH); const heightMinusSash = Math.min(this.findMaximumRenderingHeight() ?? Infinity, persistedSize.height); // SASH_WIDTH // Already setting directly the height and width parameters containerDomNode.style.width = widthMinusSash + 'px'; containerDomNode.style.height = heightMinusSash + 'px'; contentsDomNode.style.width = widthMinusSash + 'px'; contentsDomNode.style.height = heightMinusSash + 'px'; } else { // Otherwise the height and width are set to auto containerDomNode.style.width = 'auto'; containerDomNode.style.height = 'auto'; contentsDomNode.style.width = 'auto'; contentsDomNode.style.height = 'auto'; } this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // There is just a horizontal scrollbar const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; let reposition = false; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; reposition = true; } const maxRenderingHeight = this.findMaximumRenderingHeight(); // Need the following code since we are using an exact height when using the persisted size. If not used the horizontal scrollbar would just not be visible. if (persistedSize && maxRenderingHeight) { containerDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height) + 'px'; //  - SASH_WIDTH contentsDomNode.style.height = Math.min(maxRenderingHeight, persistedSize.height - SCROLLBAR_WIDTH) + 'px'; //  - SASH_WIDTH reposition = true; } if (reposition) { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); } } } // OLD FUNCTION /* public onContentsChanged(): void { this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); const scrollDimensions = this._hover.scrollbar.getScrollDimensions(); const hasHorizontalScrollbar = (scrollDimensions.scrollWidth > scrollDimensions.width); if (hasHorizontalScrollbar) { // There is just a horizontal scrollbar const extraBottomPadding = `${this._hover.scrollbar.options.horizontalScrollbarSize}px`; if (this._hover.contentsDomNode.style.paddingBottom !== extraBottomPadding) { this._hover.contentsDomNode.style.paddingBottom = extraBottomPadding; this.editor.layoutContentWidget(this.resizableContentWidget); this._hover.onContentsChanged(); } } } */ public clear(): void { this._hover.contentsDomNode.textContent = ''; } public focus(): void { this._hover.containerDomNode.focus(); } public scrollUp(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight }); } public scrollDown(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const fontInfo = this.editor.getOption(EditorOption.fontInfo); this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight }); } public scrollLeft(): void { const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - this._horizontalScrollingBy }); } public scrollRight(): void { const scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft; this._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + this._horizontalScrollingBy }); } public pageUp(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight }); } public pageDown(): void { const scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop; const scrollHeight = this._hover.scrollbar.getScrollDimensions().height; this._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight }); } public goToTop(): void { this._hover.scrollbar.setScrollPosition({ scrollTop: 0 }); } public goToBottom(): void { this._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight }); } public escape(): void { this.editor.focus(); } } export class ResizableContentHoverWidget extends ResizableContentWidget { public ID = 'editor.contrib.resizableContentHoverWidget'; private hoverDisposables = new DisposableStore(); constructor(resizableHoverWidget: ResizableHoverWidget, editor: ICodeEditor) { super(resizableHoverWidget, editor); console.log('Inside of resizable content hover widget'); } } class ContentHoverVisibleData { public closestMouseDistance: number | undefined = undefined; constructor( public readonly colorPicker: IEditorHoverColorPickerWidget | null, public readonly showAtPosition: Position, public readonly showAtSecondaryPosition: Position, public readonly preferAbove: boolean, public readonly stoleFocus: boolean, public readonly source: HoverStartSource, public readonly isBeforeContent: boolean, public initialMousePosX: number | undefined, public initialMousePosY: number | undefined, public readonly disposables: DisposableStore ) { } } function computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number { const x = (left + width / 2); // x center of rectangle const y = (top + height / 2); // y center of rectangle const dx = Math.max(Math.abs(pointX - x) - width / 2, 0); const dy = Math.max(Math.abs(pointY - y) - height / 2, 0); return Math.sqrt(dx * dx + dy * dy); } </ins>


}, 'emmet.excludeLanguages': { 'type': 'array', <del> 'default': [], </del> <ins> 'default': ['markdown'], </ins> 'description': nls.localize('emmetExclude', "An array of languages where emmet abbreviations should not be expanded.") }, }


public show(configFileName: string, largeRoots: string, onExecute: () => void) { this._currentHint = { message: largeRoots.length > 0 <del> ? localize('hintExclude', "For better performance exclude folders with many files, like: {0}", largeRoots) : localize('hintExclude.generic', "For better performance exclude folders with many files."), </del> <ins> ? localize('hintExclude', "To enable JavaScript/TypeScript IntelliSense, exclude folders with many files, like: {0}", largeRoots) : localize('hintExclude.generic', "To enable JavaScript/TypeScript IntelliSense, exclude large folders with source files that you do not work on."), </ins> options: [{ title: localize('open', "Configure Excludes"), execute: () => {


}; this._item.tooltip = this._currentHint.message; this._item.text = localize('large.label', "Configure Excludes"); <del> this._item.tooltip = localize('hintExclude.tooltip', "For better performance exclude folders with many files."); </del> <ins> this._item.tooltip = localize('hintExclude.tooltip', "To enable JavaScript/TypeScript IntelliSense, exclude large folders with source files that you do not work on."); </ins> this._item.color = '#A5DF3B'; this._item.show(); this._client.logTelemetry('js.hintProjectExcludes');


} else if (enterAction.indentAction === IndentAction.Indent) { // Indent once <del> executeCommand = TypeOperations.typeCommand(range, beforeText + 'n' + config.normalizeIndentation(indentation + 't' + enterAction.appendText), keepPosition); </del> <ins> executeCommand = TypeOperations.typeCommand(range, beforeText + 'n' + config.normalizeIndentation(indentation + enterAction.appendText), keepPosition); </ins> } else if (enterAction.indentAction === IndentAction.IndentOutdent) { // Ultra special let normalIndent = config.normalizeIndentation(indentation); <del> let increasedIndent = config.normalizeIndentation(indentation + 't' + enterAction.appendText); </del> <ins> let increasedIndent = config.normalizeIndentation(indentation + enterAction.appendText); </ins> let typeText = beforeText + 'n' + increasedIndent + 'n' + normalIndent;


if (!enterResult) { enterResult = { indentAction: IndentAction.None, appendText: '' }; } else { <ins> // Here we add `t` to appendText first because enterAction is leveraging appendText and removeText to change indentation. </ins> if (!enterResult.appendText) { <del> enterResult.appendText = ''; </del> <ins> if ( (enterResult.indentAction === IndentAction.Indent) || (enterResult.indentAction === IndentAction.IndentOutdent) ) { enterResult.appendText = 't'; } else { enterResult.appendText = ''; } </ins> } }


}); ptyProcess.on('exit', function (exitCode) { <ins> ptyProcess.kill(); </ins> process.exit(exitCode); });


const pathSeparatorClause = '/'; const excludedPathCharactersClause = '[^0s!$`&*()[]+'":;]'; // '":; are allowed in paths but they are often separators so ignore them const escapedExcludedPathCharactersClause = '(s|!|$|`|&|*|(|)|+)'; <del> /** A regex that matches paths in the form /path, ~/path, ./path, ../path */ const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('(' + pathPrefix + '?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); const winPathPrefix = '([a-zA-Z]:|..?|~)'; </del> <ins> /** A regex that matches paths in the form /foo, ~/foo, ./foo, ../foo, foo/bar */ const UNIX_LIKE_LOCAL_LINK_REGEX = new RegExp('((' + pathPrefix + '|(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)?(' + pathSeparatorClause + '(' + excludedPathCharactersClause + '|' + escapedExcludedPathCharactersClause + ')+)+)'); const winDrivePrefix = '[a-zA-Z]:'; const winPathPrefix = '(' + winDrivePrefix + '|..?|~)'; </ins> const winPathSeparatorClause = '(|/)'; const winExcludedPathCharactersClause = '[^0<>?|/s!$`&*()[]+'":;]'; <del> /** A regex that matches paths in the form c:path, ~path, .path */ const WINDOWS_LOCAL_LINK_REGEX = new RegExp('(' + winPathPrefix + '?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); </del> <ins> /** A regex that matches paths in the form c:foo, ~foo, .foo, ..foo, foobar */ const WINDOWS_LOCAL_LINK_REGEX = new RegExp('((' + winPathPrefix + '|(' + winExcludedPathCharactersClause + ')+)?(' + winPathSeparatorClause + '(' + winExcludedPathCharactersClause + ')+)+)'); </ins> /** Higher than local link, lower than hypertext */ const CUSTOM_LINK_PRIORITY = -1; /** Lowest */


}); } <del> private _resolvePath(link: string): TPromise<string> { </del> <ins> protected _preprocessPath(link: string): string { </ins> if (this._platform === platform.Platform.Windows) { // Resolve ~ -> %HOMEDRIVE%%HOMEPATH% if (link.charAt(0) === '~') { if (!process.env.HOMEDRIVE || !process.env.HOMEPATH) { <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = `${process.env.HOMEDRIVE}${process.env.HOMEPATH + link.substring(1)}`; } <del> } else { // Resolve workspace path . / .. -> <path>/. / <path/.. if (link.charAt(0) === '.') { if (!this._contextService.hasWorkspace) { </del> <ins> // Resolve relative paths (.a, ..a, ~a, ab) if (!link.match('^' + winDrivePrefix)) { if (!this._contextService.hasWorkspace()) { </ins> // Abort if no workspace is open <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = path.join(this._contextService.getWorkspace().resource.fsPath, link); } } <del> // Resolve workspace path . / .. -> <path>/. / <path/.. if (link.charAt(0) === '.') { if (!this._contextService.hasWorkspace) { </del> <ins> // Resolve workspace path . | .. | <relative_path> -> <path>/. | <path>/.. | <path>/<relative_path> else if (link.charAt(0) !== '/' && link.charAt(0) !== '~') { if (!this._contextService.hasWorkspace()) { </ins> // Abort if no workspace is open <del> return TPromise.as(void 0); </del> <ins> return null; </ins> } link = path.join(this._contextService.getWorkspace().resource.fsPath, link); } <ins> return link; } private _resolvePath(link: string): TPromise<string> { link = this._preprocessPath(link); if (!link) { return TPromise.as(void 0); } </ins> // Open an editor if the path exists return pfs.fileExists(link).then(isFile => {


import * as assert from 'assert'; import { Platform } from 'vs/base/common/platform'; import { TerminalLinkHandler } from 'vs/workbench/parts/terminal/electron-browser/terminalLinkHandler'; <ins> import { IWorkspace, WorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; import * as path from 'path'; import * as sinon from 'sinon'; </ins> class TestTerminalLinkHandler extends TerminalLinkHandler { public get localLinkRegex(): RegExp { return this._localLinkRegex; } <ins> public preprocessPath(link: string): string { return this._preprocessPath(link); } </ins> } class TestXterm {


public setHypertextValidationCallback() { } } <ins> class TestURI extends URI { constructor(private _fakePath: string) { super(); }; get fsPath(): string { return this._fakePath; } } class TestWorkspace implements IWorkspace { resource: URI; constructor(basePath: string) { this.resource = new TestURI(basePath); } } </ins> suite('Workbench - TerminalLinkHandler', () => { suite('localLinkRegex', () => { test('Windows', () => {


testLink('c:/a/long/path'); testLink('c:alongpath'); testLink('c:mixed/slashpath'); <ins> testLink('a/relative/path'); </ins> }); test('Linux', () => {


testLink('./foo'); testLink('../foo'); testLink('/a/long/path'); <ins> testLink('a/relative/path'); }); }); suite('preprocessPath', () => { test('Windows', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Windows, null, new WorkspaceContextService(new TestWorkspace('C:base'))); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '' + arg2; }); assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:base./src/file1'); assert.equal(linkHandler.preprocessPath('srcfile2'), 'C:basesrcfile2'); assert.equal(linkHandler.preprocessPath('C:absolutepathfile3'), 'C:absolutepathfile3'); stub.restore(); }); test('Linux', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null, new WorkspaceContextService(new TestWorkspace('/base'))); let stub = sinon.stub(path, 'join', function (arg1, arg2) { return arg1 + '/' + arg2; }); assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/./src/file1'); assert.equal(linkHandler.preprocessPath('src/file2'), '/base/src/file2'); assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3'); stub.restore(); }); test('No Workspace', () => { const linkHandler = new TestTerminalLinkHandler(null, new TestXterm(), Platform.Linux, null, new WorkspaceContextService(null)); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); assert.equal(linkHandler.preprocessPath('/absolute/path/file3'), '/absolute/path/file3'); </ins> }); }); });  No newline at end of file


} export class TerminalInstance implements ITerminalInstance { <del> private static readonly EOL_REGEX = /r?n/g; </del> <ins> private static readonly WINDOWS_EOL_REGEX = /r?n/g; </ins> private static _terminalProcessFactory: ITerminalProcessFactory = new StandardTerminalProcessFactory(); private static _lastKnownDimensions: Dimension = null;


} public sendText(text: string, addNewLine: boolean): void { <del> if (addNewLine && text.substr(text.length - os.EOL.length) !== os.EOL) { text += os.EOL; </del> <ins> text = this._sanitizeInput(text); if (addNewLine && text.substr(text.length - 1) !== 'r') { text += 'r'; </ins> } this._process.send({ event: 'input',


} private _sanitizeInput(data: any) { <del> return typeof data === 'string' ? data.replace(TerminalInstance.EOL_REGEX, os.EOL) : data; </del> <ins> return typeof data === 'string' ? data.replace(TerminalInstance.WINDOWS_EOL_REGEX, 'r') : data; </ins> } protected _getCwd(shell: IShellLaunchConfig, workspace: IWorkspace): string {


*--------------------------------------------------------------------------------------------*/ import uri from 'vs/base/common/uri'; <del> import * as paths from 'vs/base/common/paths'; </del> import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { guessMimeTypes, MIME_TEXT } from 'vs/base/common/mime';


return TPromise.wrapError(localize('unable', "Unable to resolve the resource without a debug session")); } const source = process.sources.get(resource.toString()); <del> const rawSource = source ? source.raw : { path: paths.normalize(resource.fsPath, true) }; </del> <ins> let rawSource: DebugProtocol.Source; if (source) { rawSource = source.raw; } else { // Remove debug: scheme rawSource = { path: resource.with({ scheme: '' }).toString(true) }; } </ins> return process.session.source({ sourceReference: source ? source.reference : undefined, source: rawSource }).then(response => { const mime = response.body.mimeType || guessMimeTypes(resource.toString())[0];


return ''; } <ins> private get selectedText(): string { const activeEditor = this.editorService.getActiveEditor(); if (activeEditor) { const editorControl = (<ICodeEditor>activeEditor.getControl()); if (editorControl) { const editorModel = editorControl.getModel(); const editorSelection = editorControl.getSelection(); if (editorModel && editorSelection) { return editorModel.getValueInRange(editorSelection); } } } return ''; } </ins> private getFilePath(): string { let input = this.editorService.getActiveEditorInput(); if (input instanceof DiffEditorInput) {


assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${lineNumber} xyz'), `abc ${editorService.mockLineNumber} xyz`); }); <ins> test('current selected text', () => { assert.strictEqual(configurationResolverService.resolve(workspace, 'abc ${selectedText} xyz'), `abc ${editorService.mockSelectedText} xyz`); }); </ins> test('substitute many', () => { if (platform.isWindows) { assert.strictEqual(configurationResolverService.resolve(workspace, '${workspaceFolder} - ${workspaceFolder}'), 'VSCodeworkspaceLocation - VSCodeworkspaceLocation');


public activeEditorOptions: IEditorOptions; public activeEditorPosition: Position; public mockLineNumber: number; <ins> public mockSelectedText: string; </ins> private callback: (method: string) => void; constructor(callback?: (method: string) => void) { this.callback = callback || ((s: string) => { }); this.mockLineNumber = 15; <ins> this.mockSelectedText = 'selected text'; </ins> } public openEditors(inputs: any[]): Promise {


getId: () => { return null; }, getControl: () => { return { <del> getSelection: () => { return { positionLineNumber: this.mockLineNumber }; } </del> <ins> getSelection: () => { return { positionLineNumber: this.mockLineNumber }; }, getModel: () => { return { getValueInRange: () => this.mockSelectedText }; } </ins> }; }, focus: () => { },


) { super(null, action, [], 0); <del> this.toDispose.push(this.outputService.onOutputChannel(() => this.setOptions(this.getOptions(), this.getSelected(undefined)))); </del> <ins> this.toDispose.push(this.outputService.onOutputChannel(() => { const activeChannelIndex = this.getSelected(this.outputService.getActiveChannel().id); this.setOptions(this.getOptions(), activeChannelIndex); })); </ins> this.toDispose.push(this.outputService.onActiveOutputChannel(activeChannelId => this.setOptions(this.getOptions(), this.getSelected(activeChannelId)))); this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService));


display: flex; padding: 4px; align-items: center; <ins> width: 220px; max-width: calc(100% - 28px - 28px - 8px); </ins> -webkit-transition: top 200ms linear; -o-transition: top 200ms linear;


top: 0; } <ins> .monaco-workbench .simple-find-part .monaco-findInput { flex: 1; } </ins> /* Temporarily we don't show match numbers */ .monaco-workbench .simple-find-part .monaco-findInput .controls { display: none;


) { super(); this._findInput = this._register(new FindInput(null, this._contextViewService, { <del> width: 155, </del> label: NLS_FIND_INPUT_LABEL, placeholder: NLS_FIND_INPUT_", }));


* * @param listener The listener function which takes the processes' data stream (including * ANSI escape sequences). <ins> * * @deprecated onLineData will replace this. </ins> */ onData(listener: (data: string) => void): IDisposable; /** <ins> * Attach a listener to listen for new lines added to this terminal instance. * * @param listener The listener function which takes new line strings added to the terminal, * excluding ANSI escape sequences. The line event will fire when an LF character is added to * the terminal (ie. the line is not wrapped), note that this means taht the line data will * never fire for the last line, until the line is ended with a LF character. The lineData * string will contain the fully wrapped line, not containing any LF/CR characters. */ onLineData(listener: (lineData: string) => void): IDisposable; /** </ins> * Attach a listener that fires when the terminal's pty process exits. * * @param listener The listener function which takes the processes' exit code, an exit code of


}; } <ins> public onLineData(listener: (lineData: string) => void): lifecycle.IDisposable { if (!this._xterm) { throw new Error('xterm must be initialized'); } const lineFeedListener = () => { const buffer = (<any>this._xterm.buffer); const newLine = buffer.lines.get(buffer.ybase + buffer.y); if (!newLine.isWrapped) { let i = buffer.ybase + buffer.y - 1; let lineData = buffer.translateBufferLineToString(i, true); while (i >= 0 && buffer.lines.get(i--).isWrapped) { lineData = buffer.translateBufferLineToString(i, true) + lineData; } listener(lineData); } }; this._xterm.on('lineFeed', lineFeedListener); return { dispose: () => { if (this._xterm) { this._xterm.off('lineFeed', lineFeedListener); } } }; } </ins> public onExit(listener: (exitCode: number) => void): lifecycle.IDisposable { if (this._process) { this._process.on('exit', listener);


const text = data.contents.join('n'); const newDocument = new DOMParser().parseFromString(text, 'text/html'); <ins> newDocument.querySelectorAll('a').forEach(a => { if (!a.title) { a.title = a.href; } }); </ins> // set base-url if applicable if (initData.baseUrl && newDocument.head.getElementsByTagName('base').length === 0) { const baseElement = newDocument.createElement('base');


position: absolute; bottom: 0; top: 0; <ins> padding-bottom: 2px; </ins> } .monaco-workbench .panel.integrated-terminal .xterm a:not(.xterm-invalid-link) {


} const padding = parseInt(getComputedStyle(document.querySelector('.terminal-outer-container')).paddingLeft.split('px')[0], 10); <ins> const paddingBottom = parseInt(getComputedStyle(document.querySelector('.terminal-wrapper.active')).paddingBottom.split('px')[0], 10); </ins> // Use left padding as right padding, right padding is not defined in CSS just in case // xterm.js causes an unexpected overflow. const innerWidth = width - padding * 2; <del> TerminalInstance._lastKnownDimensions = new Dimension(innerWidth, height); </del> <ins> const innerHeight = height - paddingBottom; TerminalInstance._lastKnownDimensions = new Dimension(innerWidth, innerHeight); </ins> return TerminalInstance._lastKnownDimensions; }


dom.addClass(this._wrapperElement, 'terminal-wrapper'); this._xtermElement = document.createElement('div'); <ins> // Attach the xterm object to the DOM, exposing it to the smoke tests (<any>this._wrapperElement).xterm = this._xterm; </ins> this._xterm.open(this._xtermElement); this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent) => { // Disable all input if the terminal is exiting


import { SpectronApplication } from '../../spectron/application'; <del> export class Terminal { static TERMINAL_SELECTOR = '.panel.integrated-terminal'; static TERMINAL_ROWS_SELECTOR = `${Terminal.TERMINAL_SELECTOR} .xterm-rows > div`; static TERMINAL_CURSOR = `${Terminal.TERMINAL_SELECTOR} .terminal-cursor`; </del> <ins> const PANEL_SELECTOR = 'div[id="workbench.panel.terminal"]'; const XTERM_SELECTOR = `${PANEL_SELECTOR} .terminal-wrapper`; export class Terminal { </ins> constructor(private spectron: SpectronApplication) { } public async showTerminal(): Promise<void> { if (!await this.isVisible()) { await this.spectron.workbench.quickopen.runCommand('View: Toggle Integrated Terminal'); <del> await this.spectron.client.waitForElement(Terminal.TERMINAL_CURSOR); </del> <ins> await this.spectron.client.waitForElement(XTERM_SELECTOR); </ins> await this.waitForTerminalText(text => text.length > 0, 'Waiting for Terminal to be ready'); } } public async isVisible(): Promise<boolean> { <del> const element = await this.spectron.client.element(Terminal.TERMINAL_SELECTOR); </del> <ins> const element = await this.spectron.client.element(PANEL_SELECTOR); </ins> return !!element; }


} private async getTerminalText(): Promise<string[]> { <del> const linesText: string[] = await this.spectron.webclient.selectorExecute<string[]>(Terminal.TERMINAL_ROWS_SELECTOR, div => (Array.isArray(div) ? div : [div]) .map(element => { function getTextFromAll(spanElements: NodeList): string { let text = ''; for (let i = 0; i < spanElements.length; i++) { text += getText(spanElements.item(i) as HTMLElement); } return text; } function getText(spanElement: HTMLElement): string { if (spanElement.hasChildNodes()) { return getTextFromAll(spanElement.childNodes); } return spanElement.textContent || ''; } return getTextFromAll(element.querySelectorAll('span')); })); let lastLineIndex = 0; for (let index = 0; index < linesText.length; index++) { if (linesText[index].trim()) { lastLineIndex = index; </del> <ins> return await this.spectron.webclient.selectorExecute(XTERM_SELECTOR, div => { const xterm = (<any>(Array.isArray(div) ? div[0] : div)).xterm; const buffer = xterm.buffer; const lines: string[] = []; for (let i = 0; i < buffer.lines.length; i++) { lines.push(buffer.translateBufferLineToString(i, true)); } return lines; </ins> } <del> } return linesText.slice(0, lastLineIndex + 1); </del> <ins> ); </ins> } }  No newline at end of file


if (ref === '~') { const fileUri = Uri.file(path); const uriString = fileUri.toString(); <del> const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.original.toString() === uriString); </del> <ins> const [indexStatus] = repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString); </ins> ref = indexStatus ? '' : 'HEAD'; }


"Import external module.": { "prefix": "import statement", "body": [ <del> "import ${1:name} = require('$0');" </del> <ins> "import { $0 } from "${1:module}";" </ins> ], "description": "Import external module." },


if (offset + needleLength > haystackLength) { return false; } <ins> const haystackUpper = haystack.toUpperCase(); const needleUpper = needle.toUpperCase(); </ins> for (let i = 0; i < needleLength; i++) { <del> if (haystack.charCodeAt(offset + i) !== needle.charCodeAt(i)) { </del> <ins> if (haystackUpper.charCodeAt(offset + i) !== needleUpper.charCodeAt(i)) { </ins> return false; } }


}, "css.webkitProperties": { "type": "string", <del> "default": "", </del> <ins> "default": "animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-clip, background-composite, background-origin, background-size, border-fit, border-horizontal-spacing, border-image, border-vertical-spacing, box-align, box-direction, box-flex, box-flex-group, box-lines, box-ordinal-group, box-orient, box-pack, box-reflect, box-shadow, color-correction, column-break-after, column-break-before, column-break-inside, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-span, column-width, dashboard-region, font-smoothing, highlight, hyphenate-character, hyphenate-limit-after, hyphenate-limit-before, hyphens, line-box-contain, line-break, line-clamp, locale, margin-before-collapse, margin-after-collapse, marquee-direction, marquee-increment, marquee-repetition, marquee-style, mask-attachment, mask-box-image, mask-box-image-outset, mask-box-image-repeat, mask-box-image-slice, mask-box-image-source, mask-box-image-width, mask-clip, mask-composite, mask-image, mask-origin, mask-position, mask-repeat, mask-size, nbsp-mode, perspective, perspective-origin, rtl-ordering, text-combine, text-decorations-in-effect, text-emphasis-color, text-emphasis-position, text-emphasis-style, text-fill-color, text-orientation, text-security, text-stroke-color, text-stroke-width, transform, transition, transform-origin, transform-style, transition-delay, transition-duration, transition-property, transition-timing-function, user-drag, user-modify, user-select, writing-mode, svg-shadow, box-sizing, border-radius", </ins> "description": "%emmetPreferencesCssWebkitProperties%" }, "css.mozProperties": { "type": "string", <del> "default": "", </del> <ins> "default": "animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-inline-policy, binding, border-bottom-colors, border-image, border-left-colors, border-right-colors, border-top-colors, box-align, box-direction, box-flex, box-ordinal-group, box-orient, box-pack, box-shadow, box-sizing, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-width, float-edge, font-feature-settings, font-language-override, force-broken-image-icon, hyphens, image-region, orient, outline-radius-bottomleft, outline-radius-bottomright, outline-radius-topleft, outline-radius-topright, perspective, perspective-origin, stack-sizing, tab-size, text-blink, text-decoration-color, text-decoration-line, text-decoration-style, text-size-adjust, transform, transform-origin, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-focus, user-input, user-modify, user-select, window-shadow, background-clip, border-radius", </ins> "description": "%emmetPreferencesCssMozProperties%" }, "css.oProperties": { "type": "string", <del> "default": "", </del> <ins> "default": "dashboard-region, animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, border-image, link, link-source, object-fit, object-position, tab-size, table-baseline, transform, transform-origin, transition, transition-delay, transition-duration, transition-property, transition-timing-function, accesskey, input-format, input-required, marquee-dir, marquee-loop, marquee-speed, marquee-style", </ins> "description": "%emmetPreferencesCssOProperties%" }, "css.msProperties": { "type": "string", <del> "default": "", </del> <ins> "default": "accelerator, backface-visibility, background-position-x, background-position-y, behavior, block-progression, box-align, box-direction, box-flex, box-line-progression, box-lines, box-ordinal-group, box-orient, box-pack, content-zoom-boundary, content-zoom-boundary-max, content-zoom-boundary-min, content-zoom-chaining, content-zoom-snap, content-zoom-snap-points, content-zoom-snap-type, content-zooming, filter, flow-from, flow-into, font-feature-settings, grid-column, grid-column-align, grid-column-span, grid-columns, grid-layer, grid-row, grid-row-align, grid-row-span, grid-rows, high-contrast-adjust, hyphenate-limit-chars, hyphenate-limit-lines, hyphenate-limit-zone, hyphens, ime-mode, interpolation-mode, layout-flow, layout-grid, layout-grid-char, layout-grid-line, layout-grid-mode, layout-grid-type, line-break, overflow-style, perspective, perspective-origin, perspective-origin-x, perspective-origin-y, scroll-boundary, scroll-boundary-bottom, scroll-boundary-left, scroll-boundary-right, scroll-boundary-top, scroll-chaining, scroll-rails, scroll-snap-points-x, scroll-snap-points-y, scroll-snap-type, scroll-snap-x, scroll-snap-y, scrollbar-arrow-color, scrollbar-base-color, scrollbar-darkshadow-color, scrollbar-face-color, scrollbar-highlight-color, scrollbar-shadow-color, scrollbar-track-color, text-align-last, text-autospace, text-justify, text-kashida-space, text-overflow, text-size-adjust, text-underline-position, touch-action, transform, transform-origin, transform-origin-x, transform-origin-y, transform-origin-z, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-select, word-break, wrap-flow, wrap-margin, wrap-through, writing-mode", </ins> "description": "%emmetPreferencesCssMsProperties%" } }


: nls.localize('links.command', "Ctrl + click to execute command") ); <del> const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText(nls.localize('links.navigate.al', "Alt + click to follow link")); const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText(nls.localize('links.command.al', "Alt + click to execute command")); </del> <ins> const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText( platform.isMacintosh ? nls.localize('links.navigate.al.mac', "Option + click to follow link") : nls.localize('links.navigate.al', "Alt + click to follow link") ); const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText( platform.isMacintosh ? nls.localize('links.command.al.mac', "Option + click to execute command") : nls.localize('links.command.al', "Alt + click to execute command") ); </ins> const decoration = { meta: ModelDecorationOptions.register({


const position = this.validatePosition(_position); const lineContent = this.getLineContent(position.lineNumber); const lineTokens = this._getLineTokens(position.lineNumber); <del> const offset = position.column - 1; const tokenIndex = lineTokens.findTokenIndexAtOffset(offset); </del> <ins> const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1); // (1). First try checking right biased word const [rbStartOffset, rbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex); const rightBiasedWord = getWordAtText( position.column, LanguageConfigurationRegistry.getWordDefinition(lineTokens.getLanguageId(tokenIndex)), lineContent.substring(rbStartOffset, rbEndOffset), rbStartOffset ); if (rightBiasedWord) { return rightBiasedWord; } // (2). Else, if we were at a language boundary, check the left biased word if (tokenIndex > 0 && rbStartOffset === position.column - 1) { // edge case, where `position` sits between two tokens belonging to two different languages const [lbStartOffset, lbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex - 1); const leftBiasedWord = getWordAtText( position.column, LanguageConfigurationRegistry.getWordDefinition(lineTokens.getLanguageId(tokenIndex - 1)), lineContent.substring(lbStartOffset, lbEndOffset), lbStartOffset ); if (leftBiasedWord) { return leftBiasedWord; } } return null; } private static _findLanguageBoundaries(lineTokens: LineTokens, tokenIndex: number): [number, number] { </ins> const languageId = lineTokens.getLanguageId(tokenIndex); // go left until a different language is hit


endOffset = lineTokens.getEndOffset(i); } <del> return getWordAtText( position.column, LanguageConfigurationRegistry.getWordDefinition(languageId), lineContent.substring(startOffset, endOffset), startOffset ); </del> <ins> return [startOffset, endOffset]; </ins> } public getWordUntilPosition(position: IPosition): model.IWordAtPosition {


} const pos = editor.getPosition(); model.tokenizeIfCheap(pos.lineNumber); const word = model.getWordAtPosition(pos); if (!word) { return false;


import * as assert from 'assert'; import { Event } from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; <del> import { IDisposable, dispose } from 'vs/base/common/lifecycle'; </del> <ins> import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; </ins> import { TextModel } from 'vs/editor/common/model/textModel'; import { Handler } from 'vs/editor/common/editorCommon'; <del> import { ISuggestSupport, ISuggestResult, SuggestRegistry, SuggestTriggerKind } from 'vs/editor/common/modes'; </del> <ins> import { ISuggestSupport, ISuggestResult, SuggestRegistry, SuggestTriggerKind, LanguageIdentifier, TokenizationRegistry, IState, MetadataConsts } from 'vs/editor/common/modes'; </ins> import { SuggestModel, LineContext } from 'vs/editor/contrib/suggest/suggestModel'; import { TestCodeEditor, MockScopeLocation } from 'vs/editor/test/browser/testCodeEditor'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';


import { IStorageService, NullStorageService } from 'vs/platform/storage/common/storage'; import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; import { ISelectedSuggestion } from 'vs/editor/contrib/suggest/suggestWidget'; <ins> import { MockMode } from 'vs/editor/test/common/mocks/mockMode'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { NULL_STATE } from 'vs/editor/common/modes/nullMode'; </ins> function createMockEditor(model: TextModel): TestCodeEditor { const contextKeyService = new MockContextKeyService();


} suite('SuggestModel - Context', function () { <ins> const OUTER_LANGUAGE_ID = new LanguageIdentifier('outerMode', 3); const INNER_LANGUAGE_ID = new LanguageIdentifier('innerMode', 4); class OuterMode extends MockMode { constructor() { super(OUTER_LANGUAGE_ID); this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {})); this._register(TokenizationRegistry.register(this.getLanguageIdentifier().language, { getInitialState: (): IState => NULL_STATE, tokenize: undefined, tokenize2: (line: string, state: IState): TokenizationResult2 => { const tokensArr: number[] = []; let prevLanguageId: LanguageIdentifier = undefined; for (let i = 0; i < line.length; i++) { const languageId = (line.charAt(i) === 'x' ? INNER_LANGUAGE_ID : OUTER_LANGUAGE_ID); if (prevLanguageId !== languageId) { tokensArr.push(i); tokensArr.push((languageId.id << MetadataConsts.LANGUAGEID_OFFSET)); } prevLanguageId = languageId; } const tokens = new Uint32Array(tokensArr.length); for (let i = 0; i < tokens.length; i++) { tokens[i] = tokensArr[i]; } return new TokenizationResult2(tokens, state); } })); } } </ins> <del> let model: TextModel; </del> <ins> class InnerMode extends MockMode { constructor() { super(INNER_LANGUAGE_ID); this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {})); } } </ins> <del> setup(function () { model = TextModel.createFromString('Das Pferd frisst keinen Gurkensalat - Philipp Reis 1861.nWer hat's erfunden?'); </del> <ins> const assertAutoTrigger = (model: TextModel, offset: number, expected: boolean, message?: string): void => { const pos = model.getPositionAt(offset); const editor = createMockEditor(model); editor.setPosition(pos); assert.equal(LineContext.shouldAutoTrigger(editor), expected, message); editor.dispose(); }; let disposables: Disposable[] = []; setup(() => { disposables = []; </ins> }); teardown(function () { <del> model.dispose(); </del> <ins> dispose(disposables); disposables = []; </ins> }); test('Context - shouldAutoTrigger', function () { <ins> const model = TextModel.createFromString('Das Pferd frisst keinen Gurkensalat - Philipp Reis 1861.nWer hat's erfunden?'); disposables.push(model); </ins> <del> function assertAutoTrigger(offset: number, expected: boolean): void { const pos = model.getPositionAt(offset); const editor = createMockEditor(model); editor.setPosition(pos); assert.equal(LineContext.shouldAutoTrigger(editor), expected); editor.dispose(); } assertAutoTrigger(3, true); // end of word, Das| assertAutoTrigger(4, false); // no word Das | assertAutoTrigger(1, false); // middle of word D|as assertAutoTrigger(55, false); // number, 1861| </del> <ins> assertAutoTrigger(model, 3, true, 'end of word, Das|'); assertAutoTrigger(model, 4, false, 'no word Das |'); assertAutoTrigger(model, 1, false, 'middle of word D|as'); assertAutoTrigger(model, 55, false, 'number, 1861|'); </ins> }); <ins> test('shouldAutoTrigger at embedded language boundaries', () => { const outerMode = new OuterMode(); const innerMode = new InnerMode(); disposables.push(outerMode, innerMode); const model = TextModel.createFromString('a<xx>a<x>', undefined, outerMode.getLanguageIdentifier()); disposables.push(model); assertAutoTrigger(model, 1, true, 'a|<x — should trigger at end of word'); assertAutoTrigger(model, 2, false, 'a<|x — should NOT trigger at start of word'); assertAutoTrigger(model, 3, false, 'a<x|x —  should NOT trigger in middle of word'); assertAutoTrigger(model, 4, true, 'a<xx|> — should trigger at boundary between languages'); assertAutoTrigger(model, 5, false, 'a<xx>|a — should NOT trigger at start of word'); assertAutoTrigger(model, 6, true, 'a<xx>a|< — should trigger at end of word'); assertAutoTrigger(model, 8, true, 'a<xx>a<x|> — should trigger at end of word at boundary'); }); </ins> }); suite('SuggestModel - TriggerAndCancelOracle', function () {


ModelRawLinesDeleted, ModelRawLinesInserted } from 'vs/editor/common/model/textModelEvents'; import { TextModel } from 'vs/editor/common/model/textModel'; <ins> import { LanguageIdentifier, TokenizationRegistry, IState, MetadataConsts } from 'vs/editor/common/modes'; import { MockMode } from 'vs/editor/test/common/mocks/mockMode'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; import { NULL_STATE } from 'vs/editor/common/modes/nullMode'; import { dispose, Disposable } from 'vs/base/common/lifecycle'; </ins> // --------- utils


suite('Editor Model - Words', () => { <del> var thisModel: TextModel; </del> <ins> const OUTER_LANGUAGE_ID = new LanguageIdentifier('outerMode', 3); const INNER_LANGUAGE_ID = new LanguageIdentifier('innerMode', 4); class OuterMode extends MockMode { constructor() { super(OUTER_LANGUAGE_ID); this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {})); this._register(TokenizationRegistry.register(this.getLanguageIdentifier().language, { getInitialState: (): IState => NULL_STATE, tokenize: undefined, tokenize2: (line: string, state: IState): TokenizationResult2 => { const tokensArr: number[] = []; let prevLanguageId: LanguageIdentifier = undefined; for (let i = 0; i < line.length; i++) { const languageId = (line.charAt(i) === 'x' ? INNER_LANGUAGE_ID : OUTER_LANGUAGE_ID); if (prevLanguageId !== languageId) { tokensArr.push(i); tokensArr.push((languageId.id << MetadataConsts.LANGUAGEID_OFFSET)); } prevLanguageId = languageId; } const tokens = new Uint32Array(tokensArr.length); for (let i = 0; i < tokens.length; i++) { tokens[i] = tokensArr[i]; } return new TokenizationResult2(tokens, state); } })); } } class InnerMode extends MockMode { constructor() { super(INNER_LANGUAGE_ID); this._register(LanguageConfigurationRegistry.register(this.getLanguageIdentifier(), {})); } } let disposables: Disposable[] = []; </ins> setup(() => { <del> var text = ['This text has some  words. ']; thisModel = TextModel.createFromString(text.join('n')); </del> <ins> disposables = []; </ins> }); teardown(() => { <del> thisModel.dispose(); </del> <ins> dispose(disposables); disposables = []; </ins> }); test('Get word at position', () => { <ins> const text = ['This text has some  words. ']; const thisModel = TextModel.createFromString(text.join('n')); disposables.push(thisModel); </ins> assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 1)), { word: 'This', startColumn: 1, endColumn: 5 }); assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 2)), { word: 'This', startColumn: 1, endColumn: 5 }); assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 4)), { word: 'This', startColumn: 1, endColumn: 5 });


assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 27)), null); assert.deepEqual(thisModel.getWordAtPosition(new Position(1, 28)), null); }); <ins> test('getWordAtPosition at embedded language boundaries', () => { const outerMode = new OuterMode(); const innerMode = new InnerMode(); disposables.push(outerMode, innerMode); const model = TextModel.createFromString('ab<xx>ab<x>', undefined, outerMode.getLanguageIdentifier()); disposables.push(model); assert.deepEqual(model.getWordAtPosition(new Position(1, 1)), { word: 'ab', startColumn: 1, endColumn: 3 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 2)), { word: 'ab', startColumn: 1, endColumn: 3 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 3)), { word: 'ab', startColumn: 1, endColumn: 3 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 4)), { word: 'xx', startColumn: 4, endColumn: 6 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 5)), { word: 'xx', startColumn: 4, endColumn: 6 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 6)), { word: 'xx', startColumn: 4, endColumn: 6 }); assert.deepEqual(model.getWordAtPosition(new Position(1, 7)), { word: 'ab', startColumn: 7, endColumn: 9 }); }); </ins> });


constructor(line: number, character: number); /** <del> * Check if `other` is before this position. </del> <ins> * Check if this position is before `other`. </ins> * * @param other A position. * @return `true` if position is on a smaller line


isBefore(other: Position): boolean; /** <del> * Check if `other` is before or equal to this position. </del> <ins> * Check if this position is before or equal to `other`. </ins> * * @param other A position. * @return `true` if position is on a smaller line


isBeforeOrEqual(other: Position): boolean; /** <del> * Check if `other` is after this position. </del> <ins> * Check if this position is after `other`. </ins> * * @param other A position. * @return `true` if position is on a greater line


isAfter(other: Position): boolean; /** <del> * Check if `other` is after or equal to this position. </del> <ins> * Check if this position is after or equal to `other`. </ins> * * @param other A position. * @return `true` if position is on a greater line


isAfterOrEqual(other: Position): boolean; /** <del> * Check if `other` equals this position. </del> <ins> * Check if this position is equal to `other`. </ins> * * @param other A position. * @return `true` if the line and character of the given position are equal to


import { toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; import { StableEditorScrollState } from 'vs/editor/browser/core/editorState'; import { ICodeEditor, MouseTargetType, IViewZoneChangeAccessor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; <del> import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; </del> <ins> import { registerEditorContribution, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; </ins> import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model'; import { CodeLensProviderRegistry, CodeLens } from 'vs/editor/common/modes';


import { EditorOption } from 'vs/editor/common/config/editorOptions'; import * as dom from 'vs/base/browser/dom'; import { hash } from 'vs/base/common/hash'; <ins> import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput'; </ins> export class CodeLensContribution implements IEditorContribution {