mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-18 19:11:36 -04:00
* Initial 1.19 xcopy * Fix yarn build * Fix numerous build breaks * Next batch of build break fixes * More build break fixes * Runtime breaks * Additional post merge fixes * Fix windows setup file * Fix test failures. * Update license header blocks to refer to source eula
194 lines
7.9 KiB
TypeScript
194 lines
7.9 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { SpectronApplication } from '../../spectron/application';
|
|
import { QuickOutline } from './quickoutline';
|
|
import { References } from './peek';
|
|
|
|
const RENAME_BOX = '.monaco-editor .monaco-editor.rename-box';
|
|
const RENAME_INPUT = `${RENAME_BOX} .rename-input`;
|
|
|
|
export class Editor {
|
|
|
|
private static readonly VIEW_LINES = '.monaco-editor .view-lines';
|
|
private static readonly LINE_NUMBERS = '.monaco-editor .margin .margin-view-overlays .line-numbers';
|
|
private static readonly FOLDING_EXPANDED = '.monaco-editor .margin .margin-view-overlays>:nth-child(${INDEX}) .folding';
|
|
private static readonly FOLDING_COLLAPSED = `${Editor.FOLDING_EXPANDED}.collapsed`;
|
|
|
|
constructor(private spectron: SpectronApplication) {
|
|
}
|
|
|
|
async openOutline(): Promise<QuickOutline> {
|
|
const outline = new QuickOutline(this.spectron);
|
|
await outline.open();
|
|
return outline;
|
|
}
|
|
|
|
async findReferences(term: string, line: number): Promise<References> {
|
|
await this.clickOnTerm(term, line);
|
|
await this.spectron.workbench.quickopen.runCommand('Find All References');
|
|
const references = new References(this.spectron);
|
|
await references.waitUntilOpen();
|
|
return references;
|
|
}
|
|
|
|
async rename(filename: string, line: number, from: string, to: string): Promise<void> {
|
|
await this.clickOnTerm(from, line);
|
|
await this.spectron.workbench.quickopen.runCommand('Rename Symbol');
|
|
|
|
await this.spectron.client.waitForActiveElement(RENAME_INPUT);
|
|
await this.spectron.client.setValue(RENAME_INPUT, to);
|
|
|
|
await this.spectron.client.keys(['Enter', 'NULL']);
|
|
}
|
|
|
|
async gotoDefinition(term: string, line: number): Promise<void> {
|
|
await this.clickOnTerm(term, line);
|
|
await this.spectron.workbench.quickopen.runCommand('Go to Definition');
|
|
}
|
|
|
|
async peekDefinition(term: string, line: number): Promise<References> {
|
|
await this.clickOnTerm(term, line);
|
|
await this.spectron.workbench.quickopen.runCommand('Peek Definition');
|
|
const peek = new References(this.spectron);
|
|
await peek.waitUntilOpen();
|
|
return peek;
|
|
}
|
|
|
|
async waitForHighlightingLine(line: number): Promise<void> {
|
|
const currentLineIndex = await this.getViewLineIndex(line);
|
|
if (currentLineIndex) {
|
|
await this.spectron.client.waitForElement(`.monaco-editor .view-overlays>:nth-child(${currentLineIndex}) .current-line`);
|
|
return;
|
|
}
|
|
throw new Error('Cannot find line ' + line);
|
|
}
|
|
|
|
async getSelector(term: string, line: number): Promise<string> {
|
|
const lineIndex = await this.getViewLineIndex(line);
|
|
const classNames = await this.spectron.client.waitFor(() => this.getClassSelectors(term, lineIndex), classNames => classNames && !!classNames.length, 'Getting class names for editor lines');
|
|
return `${Editor.VIEW_LINES}>:nth-child(${lineIndex}) span span.${classNames[0]}`;
|
|
}
|
|
|
|
async foldAtLine(line: number): Promise<any> {
|
|
const lineIndex = await this.getViewLineIndex(line);
|
|
await this.spectron.client.waitAndClick(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex));
|
|
await this.spectron.client.waitForElement(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex));
|
|
}
|
|
|
|
async unfoldAtLine(line: number): Promise<any> {
|
|
const lineIndex = await this.getViewLineIndex(line);
|
|
await this.spectron.client.waitAndClick(Editor.FOLDING_COLLAPSED.replace('${INDEX}', '' + lineIndex));
|
|
await this.spectron.client.waitForElement(Editor.FOLDING_EXPANDED.replace('${INDEX}', '' + lineIndex));
|
|
}
|
|
|
|
async waitUntilHidden(line: number): Promise<void> {
|
|
await this.spectron.client.waitFor<number>(() => this.getViewLineIndexWithoutWait(line), lineNumber => lineNumber === undefined, 'Waiting until line number is hidden');
|
|
}
|
|
|
|
async waitUntilShown(line: number): Promise<void> {
|
|
await this.getViewLineIndex(line);
|
|
}
|
|
|
|
async clickOnTerm(term: string, line: number): Promise<void> {
|
|
const selector = await this.getSelector(term, line);
|
|
await this.spectron.client.waitAndClick(selector);
|
|
}
|
|
|
|
async waitForTypeInEditor(filename: string, text: string, selectorPrefix = ''): Promise<any> {
|
|
const editor = [
|
|
selectorPrefix || '',
|
|
`.monaco-editor[data-uri$="${filename}"]`
|
|
].join(' ');
|
|
|
|
await this.spectron.client.element(editor);
|
|
|
|
const textarea = `${editor} textarea`;
|
|
await this.spectron.client.waitForActiveElement(textarea);
|
|
|
|
// https://github.com/Microsoft/vscode/issues/34203#issuecomment-334441786
|
|
await this.spectron.client.spectron.client.selectorExecute(textarea, (elements, text) => {
|
|
const textarea = (Array.isArray(elements) ? elements : [elements])[0] 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);
|
|
}, text);
|
|
|
|
await this.waitForEditorContents(filename, c => c.indexOf(text) > -1, selectorPrefix);
|
|
}
|
|
|
|
async waitForEditorContents(filename: string, accept: (contents: string) => boolean, selectorPrefix = ''): Promise<any> {
|
|
const selector = [
|
|
selectorPrefix || '',
|
|
`.monaco-editor[data-uri$="${filename}"] .view-lines`
|
|
].join(' ');
|
|
|
|
return this.spectron.client.waitForTextContent(selector, undefined, c => accept(c.replace(/\u00a0/g, ' ')));
|
|
}
|
|
|
|
async waitForActiveEditor(filename: string): Promise<any> {
|
|
const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`;
|
|
return this.spectron.client.waitForActiveElement(selector);
|
|
}
|
|
|
|
// async waitForActiveEditorFirstLineText(filename: string): Promise<string> {
|
|
// const selector = `.editor-container .monaco-editor[data-uri$="${filename}"] textarea`;
|
|
// const result = await this.spectron.client.waitFor(
|
|
// () => this.spectron.client.spectron.client.execute(s => {
|
|
// if (!document.activeElement.matches(s)) {
|
|
// return undefined;
|
|
// }
|
|
|
|
// let element: Element | null = document.activeElement;
|
|
// while (element && !/monaco-editor/.test(element.className) && element !== document.body) {
|
|
// element = element.parentElement;
|
|
// }
|
|
|
|
// if (element && /monaco-editor/.test(element.className)) {
|
|
// const firstLine = element.querySelector('.view-lines span span:nth-child(1)');
|
|
|
|
// if (firstLine) {
|
|
// return (firstLine.textContent || '').replace(/\u00a0/g, ' '); // DAMN
|
|
// }
|
|
// }
|
|
|
|
// return undefined;
|
|
// }, selector),
|
|
// r => typeof r.value === 'string',
|
|
// `wait for active editor first line: ${selector}`
|
|
// );
|
|
|
|
// return result.value;
|
|
// }
|
|
|
|
private async getClassSelectors(term: string, viewline: number): Promise<string[]> {
|
|
const result: { text: string, className: string }[] = await this.spectron.webclient.selectorExecute(`${Editor.VIEW_LINES}>:nth-child(${viewline}) span span`,
|
|
elements => (Array.isArray(elements) ? elements : [elements])
|
|
.map(element => ({ text: element.textContent, className: element.className })));
|
|
return result.filter(r => r.text === term).map(({ className }) => className);
|
|
}
|
|
|
|
private async getViewLineIndex(line: number): Promise<number> {
|
|
return await this.spectron.client.waitFor<number>(() => this.getViewLineIndexWithoutWait(line), void 0, 'Getting line index');
|
|
}
|
|
|
|
private async getViewLineIndexWithoutWait(line: number): Promise<number | undefined> {
|
|
const lineNumbers = await this.spectron.webclient.selectorExecute(Editor.LINE_NUMBERS,
|
|
elements => (Array.isArray(elements) ? elements : [elements]).map(element => element.textContent));
|
|
for (let index = 0; index < lineNumbers.length; index++) {
|
|
if (lineNumbers[index] === `${line}`) {
|
|
return index + 1;
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
} |