Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable of EditContext on Insiders #235370

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/typings/editContext.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ interface EditContextEventHandlersEventMap {

type EventHandler<TEvent extends Event = Event> = (event: TEvent) => void;

interface TextUpdateEvent extends Event {
new(type: DOMString, options?: TextUpdateEventInit): TextUpdateEvent;
declare class TextUpdateEvent extends Event {
constructor(type: DOMString, options?: TextUpdateEventInit);

readonly updateRangeStart: number;
readonly updateRangeEnd: number;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/editor/common/config/editorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { USUAL_WORD_SEPARATORS } from '../core/wordHelper.js';
import * as nls from '../../../nls.js';
import { AccessibilitySupport } from '../../../platform/accessibility/common/accessibility.js';
import { IConfigurationPropertySchema } from '../../../platform/configuration/common/configurationRegistry.js';
import product from '../../../platform/product/common/product.js';

//#region typed options

Expand Down Expand Up @@ -5795,7 +5796,7 @@ export const EditorOptions = {
emptySelectionClipboard: register(new EditorEmptySelectionClipboard()),
dropIntoEditor: register(new EditorDropIntoEditor()),
experimentalEditContextEnabled: register(new EditorBooleanOption(
EditorOption.experimentalEditContextEnabled, 'experimentalEditContextEnabled', false,
EditorOption.experimentalEditContextEnabled, 'experimentalEditContextEnabled', product.quality !== 'stable',
{
description: nls.localize('experimentalEditContextEnabled', "Sets whether the new experimental edit context should be used instead of the text area."),
included: platform.isChrome || platform.isEdge || platform.isNative
Expand Down
44 changes: 31 additions & 13 deletions src/vs/workbench/services/driver/browser/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { getClientArea, getTopLeftOffset } from '../../../../base/browser/dom.js';
import { getClientArea, getTopLeftOffset, isHTMLDivElement, isHTMLTextAreaElement } from '../../../../base/browser/dom.js';
import { mainWindow } from '../../../../base/browser/window.js';
import { coalesce } from '../../../../base/common/arrays.js';
import { language, locale } from '../../../../base/common/platform.js';
Expand Down Expand Up @@ -133,18 +133,36 @@ export class BrowserWindowDriver implements IWindowDriver {
if (!element) {
throw new Error(`Editor not found: ${selector}`);
}

const textarea = element as HTMLTextAreaElement;
const start = textarea.selectionStart;
const newStart = start + text.length;
const value = textarea.value;
const newValue = value.substr(0, start) + text + value.substr(start);

textarea.value = newValue;
textarea.setSelectionRange(newStart, newStart);

const event = new Event('input', { 'bubbles': true, 'cancelable': true });
textarea.dispatchEvent(event);
if (isHTMLDivElement(element)) {
// Edit context is enabled
const editContext = element.editContext;
if (!editContext) {
throw new Error(`Edit context not found: ${selector}`);
}
const selectionStart = editContext.selectionStart;
const selectionEnd = editContext.selectionEnd;
const event = new TextUpdateEvent('textupdate', {
updateRangeStart: selectionStart,
updateRangeEnd: selectionEnd,
text,
selectionStart: selectionStart + text.length,
selectionEnd: selectionStart + text.length,
compositionStart: 0,
compositionEnd: 0
});
editContext.dispatchEvent(event);
} else if (isHTMLTextAreaElement(element)) {
const start = element.selectionStart;
const newStart = start + text.length;
const value = element.value;
const newValue = value.substr(0, start) + text + value.substr(start);

element.value = newValue;
element.setSelectionRange(newStart, newStart);

const event = new Event('input', { 'bubbles': true, 'cancelable': true });
element.dispatchEvent(event);
}
}

async getTerminalBuffer(selector: string): Promise<string[]> {
Expand Down
9 changes: 6 additions & 3 deletions test/automation/src/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { launch as launchPlaywrightBrowser } from './playwrightBrowser';
import { PlaywrightDriver } from './playwrightDriver';
import { launch as launchPlaywrightElectron } from './playwrightElectron';
import { teardown } from './processes';
import { Quality } from './application';

export interface LaunchOptions {
codePath?: string;
Expand All @@ -28,6 +29,7 @@ export interface LaunchOptions {
readonly tracing?: boolean;
readonly headless?: boolean;
readonly browser?: 'chromium' | 'webkit' | 'firefox';
readonly quality: Quality;
}

interface ICodeInstance {
Expand Down Expand Up @@ -77,15 +79,15 @@ export async function launch(options: LaunchOptions): Promise<Code> {
const { serverProcess, driver } = await measureAndLog(() => launchPlaywrightBrowser(options), 'launch playwright (browser)', options.logger);
registerInstance(serverProcess, options.logger, 'server');

return new Code(driver, options.logger, serverProcess);
return new Code(driver, options.logger, serverProcess, options.quality);
}

// Electron smoke tests (playwright)
else {
const { electronProcess, driver } = await measureAndLog(() => launchPlaywrightElectron(options), 'launch playwright (electron)', options.logger);
registerInstance(electronProcess, options.logger, 'electron');

return new Code(driver, options.logger, electronProcess);
return new Code(driver, options.logger, electronProcess, options.quality);
}
}

Expand All @@ -96,7 +98,8 @@ export class Code {
constructor(
driver: PlaywrightDriver,
readonly logger: Logger,
private readonly mainProcess: cp.ChildProcess
private readonly mainProcess: cp.ChildProcess,
readonly quality: Quality
) {
this.driver = new Proxy(driver, {
get(target, prop) {
Expand Down
9 changes: 6 additions & 3 deletions test/automation/src/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Code, findElement } from './code';
import { Editors } from './editors';
import { Editor } from './editor';
import { IElement } from './driver';
import { Quality } from './application';

const VIEWLET = 'div[id="workbench.view.debug"]';
const DEBUG_VIEW = `${VIEWLET}`;
Expand All @@ -31,7 +32,8 @@ const CONSOLE_OUTPUT = `.repl .output.expression .value`;
const CONSOLE_EVALUATION_RESULT = `.repl .evaluation-result.expression .value`;
const CONSOLE_LINK = `.repl .value a.link`;

const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea';
const REPL_FOCUSED_NATIVE_EDIT_CONTEXT = '.repl-input-wrapper .monaco-editor .native-edit-context';
const REPL_FOCUSED_TEXTAREA = '.repl-input-wrapper .monaco-editor textarea';

export interface IStackFrame {
name: string;
Expand Down Expand Up @@ -127,8 +129,9 @@ export class Debug extends Viewlet {

async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise<void> {
await this.commands.runCommand('Debug: Focus on Debug Console View');
await this.code.waitForActiveElement(REPL_FOCUSED);
await this.code.waitForSetValue(REPL_FOCUSED, text);
const selector = this.code.quality === Quality.Stable ? REPL_FOCUSED_TEXTAREA : REPL_FOCUSED_NATIVE_EDIT_CONTEXT;
await this.code.waitForActiveElement(selector);
await this.code.waitForSetValue(selector, text);

// Wait for the keys to be picked up by the editor model such that repl evaluates what just got typed
await this.editor.waitForEditorContents('debug:replinput', s => s.indexOf(text) >= 0);
Expand Down
15 changes: 10 additions & 5 deletions test/automation/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { References } from './peek';
import { Commands } from './workbench';
import { Code } from './code';
import { Quality } from './application';

const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box';
const RENAME_INPUT = `${RENAME_BOX} .rename-input`;
Expand Down Expand Up @@ -78,10 +79,10 @@ export class Editor {
async waitForEditorFocus(filename: string, lineNumber: number, selectorPrefix = ''): Promise<void> {
const editor = [selectorPrefix || '', EDITOR(filename)].join(' ');
const line = `${editor} .view-lines > .view-line:nth-child(${lineNumber})`;
const textarea = `${editor} textarea`;
const editContext = `${editor} ${this._editContextSelector()}`;

await this.code.waitAndClick(line, 1, 1);
await this.code.waitForActiveElement(textarea);
await this.code.waitForActiveElement(editContext);
}

async waitForTypeInEditor(filename: string, text: string, selectorPrefix = ''): Promise<any> {
Expand All @@ -92,14 +93,18 @@ export class Editor {

await this.code.waitForElement(editor);

const textarea = `${editor} textarea`;
await this.code.waitForActiveElement(textarea);
const editContext = `${editor} ${this._editContextSelector()}`;
await this.code.waitForActiveElement(editContext);

await this.code.waitForTypeInEditor(textarea, text);
await this.code.waitForTypeInEditor(editContext, text);

await this.waitForEditorContents(filename, c => c.indexOf(text) > -1, selectorPrefix);
}

private _editContextSelector() {
return this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context';
}

async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise<any> {
const selector = [selectorPrefix || '', `${EDITOR(filename)} .view-lines`].join(' ');
return this.code.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));
Expand Down
3 changes: 2 additions & 1 deletion test/automation/src/editors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Quality } from './application';
import { Code } from './code';

export class Editors {
Expand Down Expand Up @@ -53,7 +54,7 @@ export class Editors {
}

async waitForActiveEditor(fileName: string, retryCount?: number): Promise<any> {
const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] textarea`;
const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`;
return this.code.waitForActiveElement(selector, retryCount);
}

Expand Down
3 changes: 2 additions & 1 deletion test/automation/src/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Code } from './code';
import { ncp } from 'ncp';
import { promisify } from 'util';
import { Commands } from './workbench';
import { Quality } from './application';
import path = require('path');
import fs = require('fs');

Expand All @@ -20,7 +21,7 @@ export class Extensions extends Viewlet {

async searchForExtension(id: string): Promise<any> {
await this.commands.runCommand('Extensions: Focus on Extensions View', { exactLabelMatch: true });
await this.code.waitForTypeInEditor('div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor textarea', `@id:${id}`);
await this.code.waitForTypeInEditor(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-editor ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`, `@id:${id}`);
await this.code.waitForTextContent(`div.part.sidebar div.composite.title h2`, 'Extensions: Marketplace');

let retrials = 1;
Expand Down
7 changes: 4 additions & 3 deletions test/automation/src/notebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Quality } from './application';
import { Code } from './code';
import { QuickAccess } from './quickaccess';
import { QuickInput } from './quickinput';
Expand Down Expand Up @@ -46,10 +47,10 @@ export class Notebook {

await this.code.waitForElement(editor);

const textarea = `${editor} textarea`;
await this.code.waitForActiveElement(textarea);
const editContext = `${editor} ${this.code.quality === Quality.Stable ? 'textarea' : '.native-edit-context'}`;
await this.code.waitForActiveElement(editContext);

await this.code.waitForTypeInEditor(textarea, text);
await this.code.waitForTypeInEditor(editContext, text);

await this._waitForActiveCellEditorContents(c => c.indexOf(text) > -1);
}
Expand Down
16 changes: 11 additions & 5 deletions test/automation/src/scm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import { Viewlet } from './viewlet';
import { IElement } from './driver';
import { findElement, findElements, Code } from './code';
import { Quality } from './application';

const VIEWLET = 'div[id="workbench.view.scm"]';
const SCM_INPUT = `${VIEWLET} .scm-editor textarea`;
const SCM_INPUT_NATIVE_EDIT_CONTEXT = `${VIEWLET} .scm-editor .native-edit-context`;
const SCM_INPUT_TEXTAREA = `${VIEWLET} .scm-editor textarea`;
const SCM_RESOURCE = `${VIEWLET} .monaco-list-row .resource`;
const REFRESH_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[aria-label="Refresh"]`;
const COMMIT_COMMAND = `div[id="workbench.parts.sidebar"] .actions-container a.action-label[aria-label="Commit"]`;
Expand Down Expand Up @@ -44,7 +46,7 @@ export class SCM extends Viewlet {

async openSCMViewlet(): Promise<any> {
await this.code.dispatchKeybinding('ctrl+shift+g');
await this.code.waitForElement(SCM_INPUT);
await this.code.waitForElement(this._editContextSelector());
}

async waitForChange(name: string, type?: string): Promise<void> {
Expand All @@ -71,9 +73,13 @@ export class SCM extends Viewlet {
}

async commit(message: string): Promise<void> {
await this.code.waitAndClick(SCM_INPUT);
await this.code.waitForActiveElement(SCM_INPUT);
await this.code.waitForSetValue(SCM_INPUT, message);
await this.code.waitAndClick(this._editContextSelector());
await this.code.waitForActiveElement(this._editContextSelector());
await this.code.waitForSetValue(this._editContextSelector(), message);
await this.code.waitAndClick(COMMIT_COMMAND);
}

private _editContextSelector(): string {
return this.code.quality === Quality.Stable ? SCM_INPUT_TEXTAREA : SCM_INPUT_NATIVE_EDIT_CONTEXT;
}
}
14 changes: 10 additions & 4 deletions test/automation/src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { Editor } from './editor';
import { Editors } from './editors';
import { Code } from './code';
import { QuickAccess } from './quickaccess';
import { Quality } from './application';

const SEARCH_BOX = '.settings-editor .suggest-input-container .monaco-editor textarea';
const SEARCH_BOX_NATIVE_EDIT_CONTEXT = '.settings-editor .suggest-input-container .monaco-editor .native-edit-context';
const SEARCH_BOX_TEXTAREA = '.settings-editor .suggest-input-container .monaco-editor textarea';

export class SettingsEditor {
constructor(private code: Code, private editors: Editors, private editor: Editor, private quickaccess: QuickAccess) { }
Expand Down Expand Up @@ -57,21 +59,25 @@ export class SettingsEditor {

async openUserSettingsUI(): Promise<void> {
await this.quickaccess.runCommand('workbench.action.openSettings2');
await this.code.waitForActiveElement(SEARCH_BOX);
await this.code.waitForActiveElement(this._editContextSelector());
}

async searchSettingsUI(query: string): Promise<void> {
await this.openUserSettingsUI();

await this.code.waitAndClick(SEARCH_BOX);
await this.code.waitAndClick(this._editContextSelector());
if (process.platform === 'darwin') {
await this.code.dispatchKeybinding('cmd+a');
} else {
await this.code.dispatchKeybinding('ctrl+a');
}
await this.code.dispatchKeybinding('Delete');
await this.code.waitForElements('.settings-editor .settings-count-widget', false, results => !results || (results?.length === 1 && !results[0].textContent));
await this.code.waitForTypeInEditor('.settings-editor .suggest-input-container .monaco-editor textarea', query);
await this.code.waitForTypeInEditor(this._editContextSelector(), query);
await this.code.waitForElements('.settings-editor .settings-count-widget', false, results => results?.length === 1 && results[0].textContent.includes('Found'));
}

private _editContextSelector() {
return this.code.quality === Quality.Stable ? SEARCH_BOX_TEXTAREA : SEARCH_BOX_NATIVE_EDIT_CONTEXT;
}
}
Loading