From c3ce62100a04ad9fa629b284dcc1a44d599ae478 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 3 May 2017 18:48:54 +0200 Subject: [PATCH] Debt: Simplify TextAreaHandler --- .../browser/controller/keyboardHandler.ts | 72 +++++- .../browser/controller/textAreaHandler.ts | 237 ++++++++---------- .../browser/controller/textAreaState.ts | 13 +- src/vs/editor/common/viewModel/viewModel.ts | 2 - .../editor/common/viewModel/viewModelImpl.ts | 10 +- .../test/browser/controller/imeTester.ts | 32 +-- .../browser/controller/textAreaState.test.ts | 23 -- 7 files changed, 173 insertions(+), 216 deletions(-) diff --git a/src/vs/editor/browser/controller/keyboardHandler.ts b/src/vs/editor/browser/controller/keyboardHandler.ts index c1b61ce4af0..d40903f2940 100644 --- a/src/vs/editor/browser/controller/keyboardHandler.ts +++ b/src/vs/editor/browser/controller/keyboardHandler.ts @@ -7,8 +7,8 @@ import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { GlobalScreenReaderNVDA } from 'vs/editor/common/config/commonEditorConfig'; -import { TextAreaHandler } from 'vs/editor/browser/controller/textAreaHandler'; -import { TextAreaStrategy } from 'vs/editor/browser/controller/textAreaState'; +import { TextAreaHandler, ITextAreaHandlerHost } from 'vs/editor/browser/controller/textAreaHandler'; +import { TextAreaStrategy, ISimpleModel } from 'vs/editor/browser/controller/textAreaState'; import { Range } from 'vs/editor/common/core/range'; import { ViewEventHandler } from 'vs/editor/common/viewModel/viewEventHandler'; import { Configuration } from 'vs/editor/browser/config/configuration'; @@ -18,6 +18,7 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { FastDomNode } from 'vs/base/browser/fastDomNode'; import { VerticalRevealType } from 'vs/editor/common/controller/cursorEvents'; import { ViewController } from 'vs/editor/browser/view/viewController'; +import { EndOfLinePreference } from "vs/editor/common/editorCommon"; export interface IKeyboardHandlerHelper { viewDomNode: FastDomNode; @@ -41,16 +42,20 @@ export class KeyboardHandler extends ViewEventHandler { private _context: ViewContext; private viewController: ViewController; - private viewHelper: IKeyboardHandlerHelper; private textArea: FastDomNode; - private textAreaHandler: TextAreaHandler; + private viewHelper: IKeyboardHandlerHelper; + private visiblePosition: TextAreaVisiblePosition; private contentLeft: number; private contentWidth: number; private scrollLeft: number; private scrollTop: number; - private visiblePosition: TextAreaVisiblePosition; + private _selections: Range[]; + private _lastCopiedValue: string; + private _lastCopiedValueIsFromEmptySelection: boolean; + + private textAreaHandler: TextAreaHandler; constructor(context: ViewContext, viewController: ViewController, viewHelper: IKeyboardHandlerHelper) { super(); @@ -67,11 +72,55 @@ export class KeyboardHandler extends ViewEventHandler { this.scrollLeft = 0; this.scrollTop = 0; - this.textAreaHandler = new TextAreaHandler(this._getStrategy(), this.textArea, this._context.model); + this._selections = [new Range(1, 1, 1, 1)]; + this._lastCopiedValue = null; + this._lastCopiedValueIsFromEmptySelection = false; + + const textAreaHandlerHost: ITextAreaHandlerHost = { + getPlainTextToCopy: (): string => { + const whatToCopy = this._context.model.getPlainTextToCopy(this._selections, browser.enableEmptySelectionClipboard); + + if (browser.enableEmptySelectionClipboard) { + if (browser.isFirefox) { + // When writing "LINE\r\n" to the clipboard and then pasting, + // Firefox pastes "LINE\n", so let's work around this quirk + this._lastCopiedValue = whatToCopy.replace(/\r\n/g, '\n'); + } else { + this._lastCopiedValue = whatToCopy; + } + + let selections = this._selections; + this._lastCopiedValueIsFromEmptySelection = (selections.length === 1 && selections[0].isEmpty()); + } + + return whatToCopy; + }, + getHTMLToCopy: (): string => { + return this._context.model.getHTMLToCopy(this._selections, browser.enableEmptySelectionClipboard); + } + }; + const simpleModel: ISimpleModel = { + getLineCount: (): number => { + return this._context.model.getLineCount(); + }, + getLineMaxColumn: (lineNumber: number): number => { + return this._context.model.getLineMaxColumn(lineNumber); + }, + getValueInRange: (range: Range, eol: EndOfLinePreference): string => { + return this._context.model.getValueInRange(range, eol); + } + }; + this.textAreaHandler = new TextAreaHandler(textAreaHandlerHost, this._getStrategy(), this.textArea, simpleModel); this._register(this.textAreaHandler.onKeyDown((e) => this.viewController.emitKeyDown(e))); this._register(this.textAreaHandler.onKeyUp((e) => this.viewController.emitKeyUp(e))); - this._register(this.textAreaHandler.onPaste((e) => this.viewController.paste('keyboard', e.text, e.pasteOnNewLine))); + this._register(this.textAreaHandler.onPaste((e) => { + let pasteOnNewLine = false; + if (browser.enableEmptySelectionClipboard) { + pasteOnNewLine = (e.text === this._lastCopiedValue && this._lastCopiedValueIsFromEmptySelection); + } + this.viewController.paste('keyboard', e.text, pasteOnNewLine); + })); this._register(this.textAreaHandler.onCut((e) => this.viewController.cut('keyboard'))); this._register(this.textAreaHandler.onType((e) => { if (e.replaceCharCnt) { @@ -80,9 +129,9 @@ export class KeyboardHandler extends ViewEventHandler { this.viewController.type('keyboard', e.text); } })); - this._register(this.textAreaHandler.onCompositionStart((e) => { - const lineNumber = e.showAtLineNumber; - const column = e.showAtColumn; + this._register(this.textAreaHandler.onCompositionStart(() => { + const lineNumber = this._selections[0].startLineNumber; + const column = this._selections[0].startColumn; this._context.privateViewEventBus.emit(new viewEvents.ViewRevealRangeRequestEvent( new Range(lineNumber, column, lineNumber, column), @@ -132,7 +181,7 @@ export class KeyboardHandler extends ViewEventHandler { } })); - this._register(this.textAreaHandler.onCompositionEnd((e) => { + this._register(this.textAreaHandler.onCompositionEnd(() => { this.textArea.unsetHeight(); this.textArea.unsetWidth(); this.textArea.setLeft(0); @@ -190,6 +239,7 @@ export class KeyboardHandler extends ViewEventHandler { private _lastCursorSelectionChanged: viewEvents.ViewCursorSelectionChangedEvent = null; public onCursorSelectionChanged(e: viewEvents.ViewCursorSelectionChangedEvent): boolean { + this._selections = [e.selection].concat(e.secondarySelections); this._lastCursorSelectionChanged = e; return false; } diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 8f0caefae58..78517360e70 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -32,12 +32,6 @@ const enum ReadFromTextArea { export interface IPasteData { text: string; - pasteOnNewLine: boolean; -} - -export interface ICompositionStartData { - showAtLineNumber: number; - showAtColumn: number; } // See https://github.com/Microsoft/monaco-editor/issues/320 @@ -47,6 +41,11 @@ const isChromev55_v56 = ( && navigator.userAgent.indexOf('Edge/') === -1 ); +export interface ITextAreaHandlerHost { + getPlainTextToCopy(): string; + getHTMLToCopy(): string; +} + export class TextAreaHandler extends Disposable { private _onKeyDown = this._register(new Emitter()); @@ -64,72 +63,81 @@ export class TextAreaHandler extends Disposable { private _onType = this._register(new Emitter()); public onType: Event = this._onType.event; - private _onCompositionStart = this._register(new Emitter()); - public onCompositionStart: Event = this._onCompositionStart.event; + private _onCompositionStart = this._register(new Emitter()); + public onCompositionStart: Event = this._onCompositionStart.event; private _onCompositionUpdate = this._register(new Emitter()); public onCompositionUpdate: Event = this._onCompositionUpdate.event; - private _onCompositionEnd = this._register(new Emitter()); - public onCompositionEnd: Event = this._onCompositionEnd.event; + private _onCompositionEnd = this._register(new Emitter()); + public onCompositionEnd: Event = this._onCompositionEnd.event; - private textArea: TextAreaWrapper; - private model: ISimpleModel; + // --- - private selection: Range; - private selections: Range[]; - private hasFocus: boolean; + private readonly _host: ITextAreaHandlerHost; + private readonly _textArea: TextAreaWrapper; + private readonly _model: ISimpleModel; - private asyncTriggerCut: RunOnceScheduler; + private _selection: Range; + private _hasFocus: boolean; - private textAreaState: TextAreaState; - private textareaIsShownAtCursor: boolean; + private readonly _asyncTriggerCut: RunOnceScheduler; - private lastCopiedValue: string; - private lastCopiedValueIsFromEmptySelection: boolean; + private _textAreaState: TextAreaState; + private _isDoingComposition: boolean; private _nextCommand: ReadFromTextArea; - constructor(strategy: TextAreaStrategy, textArea: FastDomNode, model: ISimpleModel) { + constructor(host: ITextAreaHandlerHost, strategy: TextAreaStrategy, textArea: FastDomNode, model: ISimpleModel) { super(); - this.textArea = this._register(new TextAreaWrapper(textArea)); - this.model = model; - this.selection = new Range(1, 1, 1, 1); - this.selections = [new Range(1, 1, 1, 1)]; + this._host = host; + this._textArea = this._register(new TextAreaWrapper(textArea)); + this._model = model; + + this._selection = new Range(1, 1, 1, 1); + this._hasFocus = false; + + this._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0)); + + this._textAreaState = createTextAreaState(strategy); + this._isDoingComposition = false; + this._nextCommand = ReadFromTextArea.Type; - this.asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0)); + this._register(dom.addStandardDisposableListener(textArea.domNode, 'keydown', (e: IKeyboardEvent) => { + if (this._isDoingComposition && e.equals(KeyCode.KEY_IN_COMPOSITION)) { + // Stop propagation for keyDown events if the IME is processing key input + e.stopPropagation(); + } - this.lastCopiedValue = null; - this.lastCopiedValueIsFromEmptySelection = false; - this.textAreaState = createTextAreaState(strategy); + if (e.equals(KeyCode.Escape)) { + // Prevent default always for `Esc`, otherwise it will generate a keypress + // See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx + e.preventDefault(); + } + this._onKeyDown.fire(e); + })); - this.hasFocus = false; + this._register(dom.addStandardDisposableListener(textArea.domNode, 'keyup', (e: IKeyboardEvent) => { + this._onKeyUp.fire(e); + })); - this._register(dom.addStandardDisposableListener(textArea.domNode, 'keydown', (e: IKeyboardEvent) => this._onKeyDownHandler(e))); - this._register(dom.addStandardDisposableListener(textArea.domNode, 'keyup', (e: IKeyboardEvent) => this._onKeyUp.fire(e))); - this._register(dom.addStandardDisposableListener(textArea.domNode, 'keypress', (e: IKeyboardEvent) => this._onKeyPressHandler(e))); - - this.textareaIsShownAtCursor = false; let compositionLocale = null; this._register(dom.addDisposableListener(textArea.domNode, 'compositionstart', (e: CompositionEvent) => { - if (this.textareaIsShownAtCursor) { + if (this._isDoingComposition) { return; } - this.textareaIsShownAtCursor = true; + this._isDoingComposition = true; // In IE we cannot set .value when handling 'compositionstart' because the entire composition will get canceled. if (!browser.isEdgeOrIE) { - this.setTextAreaState('compositionstart', this.textAreaState.toEmpty(), false); + this.setTextAreaState('compositionstart', this._textAreaState.toEmpty(), false); } - this._onCompositionStart.fire({ - showAtLineNumber: this.selection.startLineNumber, - showAtColumn: this.selection.startColumn - }); + this._onCompositionStart.fire(); })); this._register(dom.addDisposableListener(textArea.domNode, 'compositionupdate', (e: CompositionEvent) => { @@ -148,75 +156,55 @@ export class TextAreaHandler extends Disposable { // Multi-part Japanese compositions reset cursor in Edge/IE, Chinese and Korean IME don't have this issue. // The reason that we can't use this path for all CJK IME is IE and Edge behave differently when handling Korean IME, // which breaks this path of code. - this.textAreaState = this.textAreaState.fromTextArea(this.textArea); - let typeInput = this.textAreaState.deduceInput(); + this._textAreaState = this._textAreaState.fromTextArea(this._textArea); + let typeInput = this._textAreaState.deduceInput(); this._onType.fire(typeInput); this._onCompositionUpdate.fire(e); return; } - this.textAreaState = this.textAreaState.fromText(e.data); - let typeInput = this.textAreaState.updateComposition(); + this._textAreaState = this._textAreaState.fromText(e.data); + let typeInput = this._textAreaState.updateComposition(); this._onType.fire(typeInput); this._onCompositionUpdate.fire(e); })); - let readFromTextArea = () => { - let tempTextAreaState = this.textAreaState.fromTextArea(this.textArea); - let typeInput = tempTextAreaState.deduceInput(); - if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) { - // Ignore invalid input but keep it around for next time - return; - } - - this.textAreaState = tempTextAreaState; - // console.log('==> DEDUCED INPUT: ' + JSON.stringify(typeInput)); - if (this._nextCommand === ReadFromTextArea.Type) { - if (typeInput.text !== '') { - this._onType.fire(typeInput); - } - } else { - this.executePaste(typeInput.text); - this._nextCommand = ReadFromTextArea.Type; - } - }; - this._register(dom.addDisposableListener(textArea.domNode, 'compositionend', (e: CompositionEvent) => { // console.log('onCompositionEnd: ' + e.data); if (browser.isEdgeOrIE && e.locale === 'ja') { // https://github.com/Microsoft/monaco-editor/issues/339 - this.textAreaState = this.textAreaState.fromTextArea(this.textArea); - let typeInput = this.textAreaState.deduceInput(); + this._textAreaState = this._textAreaState.fromTextArea(this._textArea); + let typeInput = this._textAreaState.deduceInput(); this._onType.fire(typeInput); } else { - this.textAreaState = this.textAreaState.fromText(e.data); - let typeInput = this.textAreaState.updateComposition(); + this._textAreaState = this._textAreaState.fromText(e.data); + let typeInput = this._textAreaState.updateComposition(); this._onType.fire(typeInput); } // Due to isEdgeOrIE (where the textarea was not cleared initially) and isChrome (the textarea is not updated correctly when composition ends) // we cannot assume the text at the end consists only of the composited text if (browser.isEdgeOrIE || browser.isChrome) { - this.textAreaState = this.textAreaState.fromTextArea(this.textArea); + this._textAreaState = this._textAreaState.fromTextArea(this._textArea); } - if (!this.textareaIsShownAtCursor) { + if (!this._isDoingComposition) { return; } - this.textareaIsShownAtCursor = false; + this._isDoingComposition = false; this._onCompositionEnd.fire(); })); this._register(dom.addDisposableListener(textArea.domNode, 'input', () => { // console.log('onInput: ' + this.textArea.getValue()); - if (this.textareaIsShownAtCursor) { + if (this._isDoingComposition) { // See https://github.com/Microsoft/monaco-editor/issues/320 if (isChromev55_v56) { - let text = this.textArea.getValue(); - this.textAreaState = this.textAreaState.fromText(text); - let typeInput = this.textAreaState.updateComposition(); + let text = this._textArea.getValue(); + this._textAreaState = this._textAreaState.fromText(text); + let typeInput = this._textAreaState.updateComposition(); this._onType.fire(typeInput); let e = { locale: compositionLocale, @@ -228,14 +216,30 @@ export class TextAreaHandler extends Disposable { return; } - readFromTextArea(); + let tempTextAreaState = this._textAreaState.fromTextArea(this._textArea); + let typeInput = tempTextAreaState.deduceInput(); + if (typeInput.replaceCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) { + // Ignore invalid input but keep it around for next time + return; + } + + this._textAreaState = tempTextAreaState; + // console.log('==> DEDUCED INPUT: ' + JSON.stringify(typeInput)); + if (this._nextCommand === ReadFromTextArea.Type) { + if (typeInput.text !== '') { + this._onType.fire(typeInput); + } + } else { + this.executePaste(typeInput.text); + this._nextCommand = ReadFromTextArea.Type; + } })); // --- Clipboard operations this._register(dom.addDisposableListener(textArea.domNode, 'cut', (e: ClipboardEvent) => { this._ensureClipboardGetsEditorSelection(e); - this.asyncTriggerCut.schedule(); + this._asyncTriggerCut.schedule(); })); this._register(dom.addDisposableListener(textArea.domNode, 'copy', (e: ClipboardEvent) => { @@ -246,9 +250,9 @@ export class TextAreaHandler extends Disposable { if (ClipboardEventUtils.canUseTextData(e)) { this.executePaste(ClipboardEventUtils.getTextData(e)); } else { - if (this.textArea.getSelectionStart() !== this.textArea.getSelectionEnd()) { + if (this._textArea.getSelectionStart() !== this._textArea.getSelectionEnd()) { // Clean up the textarea, to get a clean paste - this.setTextAreaState('paste', this.textAreaState.toEmpty(), false); + this.setTextAreaState('paste', this._textAreaState.toEmpty(), false); } this._nextCommand = ReadFromTextArea.Paste; } @@ -264,56 +268,34 @@ export class TextAreaHandler extends Disposable { // --- begin event handlers public setStrategy(strategy: TextAreaStrategy): void { - this.textAreaState = this.textAreaState.toStrategy(strategy); + this._textAreaState = this._textAreaState.toStrategy(strategy); } public setHasFocus(isFocused: boolean): void { - if (this.hasFocus === isFocused) { + if (this._hasFocus === isFocused) { // no change return; } - this.hasFocus = isFocused; - if (this.hasFocus) { + this._hasFocus = isFocused; + if (this._hasFocus) { this._writePlaceholderAndSelectTextArea('focusgain', false); } } public setCursorSelections(primary: Range, secondary: Range[]): void { - this.selection = primary; - this.selections = [primary].concat(secondary); + this._selection = primary; this._writePlaceholderAndSelectTextArea('selection changed', false); } // --- end event handlers private setTextAreaState(reason: string, textAreaState: TextAreaState, forceFocus: boolean): void { - if (!this.hasFocus) { + if (!this._hasFocus) { textAreaState = textAreaState.resetSelection(); } - textAreaState.applyToTextArea(reason, this.textArea, this.hasFocus || forceFocus); - this.textAreaState = textAreaState; - } - - private _onKeyDownHandler(e: IKeyboardEvent): void { - if (this.textareaIsShownAtCursor && e.equals(KeyCode.KEY_IN_COMPOSITION)) { - // Stop propagation for keyDown events if the IME is processing key input - e.stopPropagation(); - } - - if (e.equals(KeyCode.Escape)) { - // Prevent default always for `Esc`, otherwise it will generate a keypress - // See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx - e.preventDefault(); - } - this._onKeyDown.fire(e); - } - - private _onKeyPressHandler(e: IKeyboardEvent): void { - if (!this.hasFocus) { - // Sometimes, when doing Alt-Tab, in FF, a 'keypress' is sent before a 'focus' - return; - } + textAreaState.applyToTextArea(reason, this._textArea, this._hasFocus || forceFocus); + this._textAreaState = textAreaState; } // ------------- Operations that are always executed asynchronously @@ -322,14 +304,8 @@ export class TextAreaHandler extends Disposable { if (txt === '') { return; } - - let pasteOnNewLine = false; - if (browser.enableEmptySelectionClipboard) { - pasteOnNewLine = (txt === this.lastCopiedValue && this.lastCopiedValueIsFromEmptySelection); - } this._onPaste.fire({ - text: txt, - pasteOnNewLine: pasteOnNewLine + text: txt }); } @@ -338,13 +314,13 @@ export class TextAreaHandler extends Disposable { } private _writePlaceholderAndSelectTextArea(reason: string, forceFocus: boolean): void { - if (!this.textareaIsShownAtCursor) { + if (!this._isDoingComposition) { // Do not write to the textarea if it is visible. if (browser.isIPad) { // Do not place anything in the textarea for the iPad - this.setTextAreaState(reason, this.textAreaState.toEmpty(), forceFocus); + this.setTextAreaState(reason, this._textAreaState.toEmpty(), forceFocus); } else { - this.setTextAreaState(reason, this.textAreaState.fromEditorSelection(this.model, this.selection), forceFocus); + this.setTextAreaState(reason, this._textAreaState.fromEditorSelection(this._model, this._selection), forceFocus); } } } @@ -352,28 +328,15 @@ export class TextAreaHandler extends Disposable { // ------------- Clipboard operations private _ensureClipboardGetsEditorSelection(e: ClipboardEvent): void { - let whatToCopy = this.model.getPlainTextToCopy(this.selections, browser.enableEmptySelectionClipboard); + let whatToCopy = this._host.getPlainTextToCopy(); if (ClipboardEventUtils.canUseTextData(e)) { let whatHTMLToCopy: string = null; if (!browser.isEdgeOrIE && (whatToCopy.length < 65536 || CopyOptions.forceCopyWithSyntaxHighlighting)) { - whatHTMLToCopy = this.model.getHTMLToCopy(this.selections, browser.enableEmptySelectionClipboard); + whatHTMLToCopy = this._host.getHTMLToCopy(); } ClipboardEventUtils.setTextData(e, whatToCopy, whatHTMLToCopy); } else { - this.setTextAreaState('copy or cut', this.textAreaState.fromText(whatToCopy), false); - } - - if (browser.enableEmptySelectionClipboard) { - if (browser.isFirefox) { - // When writing "LINE\r\n" to the clipboard and then pasting, - // Firefox pastes "LINE\n", so let's work around this quirk - this.lastCopiedValue = whatToCopy.replace(/\r\n/g, '\n'); - } else { - this.lastCopiedValue = whatToCopy; - } - - let selections = this.selections; - this.lastCopiedValueIsFromEmptySelection = (selections.length === 1 && selections[0].isEmpty()); + this.setTextAreaState('copy or cut', this._textAreaState.fromText(whatToCopy), false); } } } diff --git a/src/vs/editor/browser/controller/textAreaState.ts b/src/vs/editor/browser/controller/textAreaState.ts index 6b55e6e5db7..e5ebbe1e456 100644 --- a/src/vs/editor/browser/controller/textAreaState.ts +++ b/src/vs/editor/browser/controller/textAreaState.ts @@ -7,7 +7,6 @@ import { commonPrefixLength, commonSuffixLength } from 'vs/base/common/strings'; import { Range } from 'vs/editor/common/core/range'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; -import { Position } from 'vs/editor/common/core/position'; import { Constants } from 'vs/editor/common/core/uint'; export interface ITextAreaWrapper { @@ -21,17 +20,9 @@ export interface ITextAreaWrapper { } export interface ISimpleModel { - getLineMaxColumn(lineNumber: number): number; - getEOL(): string; - getValueInRange(range: Range, eol: EndOfLinePreference): string; - getModelLineContent(lineNumber: number): string; getLineCount(): number; - getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string; - getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string; - - coordinatesConverter: { - convertViewPositionToModelPosition(viewPosition: Position): Position; - }; + getLineMaxColumn(lineNumber: number): number; + getValueInRange(range: Range, eol: EndOfLinePreference): string; } export interface ITypeData { diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index b9ccbc9982e..19a4b265f78 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -112,10 +112,8 @@ export interface IViewModel { getLineMaxColumn(lineNumber: number): number; getLineRenderLineNumber(lineNumber: number): string; getAllOverviewRulerDecorations(): ViewModelDecoration[]; - getEOL(): string; getValueInRange(range: Range, eol: EndOfLinePreference): string; - getModelLineContent(modelLineNumber: number): string; getModelLineMaxColumn(modelLineNumber: number): number; validateModelPosition(modelPosition: IPosition): Position; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 9a2122971a9..3f75c1f17ce 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -539,19 +539,11 @@ export class ViewModel extends Disposable implements IViewModel { return this.decorations.getAllOverviewRulerDecorations(); } - public getEOL(): string { - return this.model.getEOL(); - } - public getValueInRange(range: Range, eol: editorCommon.EndOfLinePreference): string { var modelRange = this.coordinatesConverter.convertViewRangeToModelRange(range); return this.model.getValueInRange(modelRange, eol); } - public getModelLineContent(modelLineNumber: number): string { - return this.model.getLineContent(modelLineNumber); - } - public getModelLineMaxColumn(modelLineNumber: number): number { return this.model.getLineMaxColumn(modelLineNumber); } @@ -561,7 +553,7 @@ export class ViewModel extends Disposable implements IViewModel { } public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string { - let newLineCharacter = this.getEOL(); + let newLineCharacter = this.model.getEOL(); if (ranges.length === 1) { let range: Range = ranges[0]; diff --git a/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts index faaa003cc12..9ee87fcd50f 100644 --- a/src/vs/editor/test/browser/controller/imeTester.ts +++ b/src/vs/editor/test/browser/controller/imeTester.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { TextAreaHandler } from 'vs/editor/browser/controller/textAreaHandler'; +import { TextAreaHandler, ITextAreaHandlerHost } from 'vs/editor/browser/controller/textAreaHandler'; import { TextAreaStrategy, ISimpleModel } from 'vs/editor/browser/controller/textAreaState'; import { Range, IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { Position } from 'vs/editor/common/core/position'; import { createFastDomNode } from 'vs/base/browser/fastDomNode'; // To run this test, open imeTester.html @@ -18,18 +17,12 @@ class SingleLineTestModel implements ISimpleModel { private _line: string; private _eol: string; - public coordinatesConverter = { - convertViewPositionToModelPosition: (viewPosition: Position): Position => { - return viewPosition; - } - }; - constructor(line: string) { this._line = line; this._eol = '\n'; } - setText(text: string) { + _setText(text: string) { this._line = text; } @@ -37,10 +30,6 @@ class SingleLineTestModel implements ISimpleModel { return this._line.length + 1; } - getEOL(): string { - return this._eol; - } - getValueInRange(range: IRange, eol: editorCommon.EndOfLinePreference): string { return this._line.substring(range.startColumn - 1, range.endColumn - 1); } @@ -52,14 +41,6 @@ class SingleLineTestModel implements ISimpleModel { getLineCount(): number { return 1; } - - public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string { - return ''; - } - - public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string { - return ''; - } } class TestView { @@ -101,7 +82,12 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr: let model = new SingleLineTestModel('some text'); - let handler = new TextAreaHandler(strategy, createFastDomNode(input), model); + const textAreaHandlerHost: ITextAreaHandlerHost = { + getPlainTextToCopy: (): string => '', + getHTMLToCopy: (): string => '' + }; + + let handler = new TextAreaHandler(textAreaHandlerHost, strategy, createFastDomNode(input), model); input.onfocus = () => { handler.setHasFocus(true); @@ -135,7 +121,7 @@ function doCreateTest(strategy: TextAreaStrategy, description: string, inputStr: }; let updateModelAndPosition = (text: string, off: number, len: number) => { - model.setText(text); + model._setText(text); updatePosition(off, len); view.paint(output); diff --git a/src/vs/editor/test/browser/controller/textAreaState.test.ts b/src/vs/editor/test/browser/controller/textAreaState.test.ts index 3513a18c665..3ae07ec1733 100644 --- a/src/vs/editor/test/browser/controller/textAreaState.test.ts +++ b/src/vs/editor/test/browser/controller/textAreaState.test.ts @@ -6,7 +6,6 @@ import * as assert from 'assert'; import { IENarratorTextAreaState, ISimpleModel, TextAreaState, ITextAreaWrapper } from 'vs/editor/browser/controller/textAreaState'; -import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { EndOfLinePreference } from 'vs/editor/common/editorCommon'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -466,12 +465,6 @@ class SimpleModel implements ISimpleModel { private _lines: string[]; private _eol: string; - public coordinatesConverter = { - convertViewPositionToModelPosition: (viewPosition: Position): Position => { - return viewPosition; - } - }; - constructor(lines: string[], eol: string) { this._lines = lines; this._eol = eol; @@ -493,10 +486,6 @@ class SimpleModel implements ISimpleModel { throw new Error('Unknown EOL preference'); } - public getEOL(): string { - return this._eol; - } - public getValueInRange(range: Range, eol: EndOfLinePreference): string { if (Range.isEmpty(range)) { return ''; @@ -520,19 +509,7 @@ class SimpleModel implements ISimpleModel { return resultLines.join(lineEnding); } - public getModelLineContent(lineNumber: number): string { - return this._lines[lineNumber - 1]; - } - public getLineCount(): number { return this._lines.length; } - - public getPlainTextToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string { - return ''; - } - - public getHTMLToCopy(ranges: Range[], enableEmptySelectionClipboard: boolean): string { - return ''; - } }