chore(recorder): explore using codemirror (#18529)
This commit is contained in:
parent
45aa82242d
commit
17c8554255
|
|
@ -49,3 +49,13 @@
|
||||||
.recorder .selector-input {
|
.recorder .selector-input {
|
||||||
flex: auto;
|
flex: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recorder .toolbar .cm-wrapper {
|
||||||
|
margin-left: 8px;
|
||||||
|
display: flex;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recorder .toolbar .CodeMirror {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { CallLog, Mode, Source } from './recorderTypes';
|
import type { CallLog, Mode, Source } from './recorderTypes';
|
||||||
|
import { CodeMirrorWrapper } from '@web/components/codeMirrorWrapper';
|
||||||
import { Source as SourceView } from '@web/components/source';
|
import { Source as SourceView } from '@web/components/source';
|
||||||
import { SplitView } from '@web/components/splitView';
|
import { SplitView } from '@web/components/splitView';
|
||||||
import { Toolbar } from '@web/components/toolbar';
|
import { Toolbar } from '@web/components/toolbar';
|
||||||
|
|
@ -45,14 +46,6 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
log,
|
log,
|
||||||
mode,
|
mode,
|
||||||
}) => {
|
}) => {
|
||||||
const [locator, setLocator] = React.useState('');
|
|
||||||
const [focusSelectorInput, setFocusSelectorInput] = React.useState(false);
|
|
||||||
window.playwrightSetSelector = (selector: string, focus?: boolean) => {
|
|
||||||
const language = sources[0]?.language || 'javascript';
|
|
||||||
setLocator(asLocator(language, selector));
|
|
||||||
setFocusSelectorInput(!!focus);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [fileId, setFileId] = React.useState<string | undefined>();
|
const [fileId, setFileId] = React.useState<string | undefined>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
@ -68,6 +61,13 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
label: '',
|
label: '',
|
||||||
highlight: []
|
highlight: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [locator, setLocator] = React.useState('');
|
||||||
|
window.playwrightSetSelector = (selector: string, focus?: boolean) => {
|
||||||
|
const language = source.language;
|
||||||
|
setLocator(asLocator(language, selector));
|
||||||
|
};
|
||||||
|
|
||||||
window.playwrightSetFileIfNeeded = (value: string) => {
|
window.playwrightSetFileIfNeeded = (value: string) => {
|
||||||
const newSource = sources.find(s => s.id === value);
|
const newSource = sources.find(s => s.id === value);
|
||||||
// Do not forcefully switch between two recorded sources, because
|
// Do not forcefully switch between two recorded sources, because
|
||||||
|
|
@ -81,14 +81,6 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
messagesEndRef.current?.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||||
}, [messagesEndRef]);
|
}, [messagesEndRef]);
|
||||||
|
|
||||||
const selectorInputRef = React.createRef<HTMLInputElement>();
|
|
||||||
React.useLayoutEffect(() => {
|
|
||||||
if (focusSelectorInput && selectorInputRef.current) {
|
|
||||||
selectorInputRef.current.select();
|
|
||||||
selectorInputRef.current.focus();
|
|
||||||
setFocusSelectorInput(false);
|
|
||||||
}
|
|
||||||
}, [focusSelectorInput, selectorInputRef]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
|
@ -145,12 +137,12 @@ export const Recorder: React.FC<RecorderProps> = ({
|
||||||
<ToolbarButton icon='microscope' title='Explore' toggled={mode === 'inspecting'} onClick={() => {
|
<ToolbarButton icon='microscope' title='Explore' toggled={mode === 'inspecting'} onClick={() => {
|
||||||
window.dispatch({ event: 'setMode', params: { mode: mode === 'inspecting' ? 'none' : 'inspecting' } }).catch(() => { });
|
window.dispatch({ event: 'setMode', params: { mode: mode === 'inspecting' ? 'none' : 'inspecting' } }).catch(() => { });
|
||||||
}}>Explore</ToolbarButton>
|
}}>Explore</ToolbarButton>
|
||||||
<input ref={selectorInputRef} className='selector-input' placeholder='Playwright Selector' spellCheck='false' value={locator} disabled={mode !== 'none'} onChange={event => {
|
<CodeMirrorWrapper text={locator} language={source.language} readOnly={false} focusOnChange={true} wrapLines={true} onChange={text => {
|
||||||
setLocator(event.target.value);
|
setLocator(text);
|
||||||
window.dispatch({ event: 'selectorUpdated', params: { selector: event.target.value } });
|
window.dispatch({ event: 'selectorUpdated', params: { selector: text } });
|
||||||
}} />
|
}}></CodeMirrorWrapper>
|
||||||
<ToolbarButton icon='files' title='Copy' onClick={() => {
|
<ToolbarButton icon='files' title='Copy' onClick={() => {
|
||||||
copy(selectorInputRef.current?.value || '');
|
copy(locator);
|
||||||
}}></ToolbarButton>
|
}}></ToolbarButton>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<CallLogView language={source.language} log={Array.from(log.values())}/>
|
<CallLogView language={source.language} log={Array.from(log.values())}/>
|
||||||
|
|
|
||||||
127
packages/web/src/components/codeMirrorWrapper.css
Normal file
127
packages/web/src/components/codeMirrorWrapper.css
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import '../third_party/vscode/colors.css';
|
||||||
|
|
||||||
|
.cm-wrapper, .cm-wrapper > div {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-meta {
|
||||||
|
color: var(--vscode-editor-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-number {
|
||||||
|
color: var(--vscode-debugTokenExpression-number);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-keyword {
|
||||||
|
color: var(--vscode-debugTokenExpression-name);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-operator {
|
||||||
|
color: var(--vscode-editor-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-string {
|
||||||
|
color: var(--vscode-debugTokenExpression-string);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-string-2 {
|
||||||
|
color: var(--vscode-debugTokenExpression-string);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-error {
|
||||||
|
color: var(--vscode-errorForeground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-def, .CodeMirror span.cm-tag {
|
||||||
|
color: #0070c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-comment, .CodeMirror span.cm-link {
|
||||||
|
color: #008000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-variable, .CodeMirror span.cm-variable-2, .CodeMirror span.cm-atom {
|
||||||
|
color: #0070c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-property, .CodeMirror span.cm-qualifier, .CodeMirror span.cm-attribute {
|
||||||
|
color: #001080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-variable-3,
|
||||||
|
.CodeMirror span.cm-type {
|
||||||
|
color: #267f99;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(prefers-color-scheme: dark) {
|
||||||
|
|
||||||
|
.CodeMirror span.cm-def, .CodeMirror span.cm-tag {
|
||||||
|
color: var(--vscode-debugView-valueChangedHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-comment, .CodeMirror span.cm-link {
|
||||||
|
color: #6a9955;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-variable, .CodeMirror span.cm-variable-2, .CodeMirror span.cm-atom {
|
||||||
|
color: #4fc1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-property, .CodeMirror span.cm-qualifier, .CodeMirror span.cm-attribute {
|
||||||
|
color: #9cdcfe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-variable-3,
|
||||||
|
.CodeMirror span.cm-type {
|
||||||
|
color: #4ec9b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror span.cm-bracket {
|
||||||
|
color: var(--vscode-editorBracketHighlight-foreground3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-cursor {
|
||||||
|
border-left: 1px solid #bebebe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror div.CodeMirror-selected {
|
||||||
|
background: var(--vscode-terminal-inactiveSelectionBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-gutters {
|
||||||
|
background: var(--vscode-editor-background);
|
||||||
|
border-right: 1px solid var(--vscode-editorGroup-border);
|
||||||
|
color: var(--vscode-editorLineNumber-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror .CodeMirror-matchingbracket {
|
||||||
|
background-color: var(--vscode-editorBracketPairGuide-background1);
|
||||||
|
color: var(--vscode-editorBracketHighlight-foreground1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror {
|
||||||
|
font-family: var(--vscode-editor-font-family) !important;
|
||||||
|
color: var(--vscode-editor-foreground) !important;
|
||||||
|
background-color: var(--vscode-editor-background) !important;
|
||||||
|
font-weight: var(--vscode-editor-font-weight) !important;
|
||||||
|
font-size: var(--vscode-editor-font-size) !important;
|
||||||
|
}
|
||||||
109
packages/web/src/components/codeMirrorWrapper.tsx
Normal file
109
packages/web/src/components/codeMirrorWrapper.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) Microsoft Corporation.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './source.css';
|
||||||
|
import * as React from 'react';
|
||||||
|
import CodeMirror from 'codemirror';
|
||||||
|
import 'codemirror/mode/javascript/javascript';
|
||||||
|
import 'codemirror/mode/python/python';
|
||||||
|
import 'codemirror/mode/clike/clike';
|
||||||
|
import 'codemirror/lib/codemirror.css';
|
||||||
|
|
||||||
|
export type SourceHighlight = {
|
||||||
|
line: number;
|
||||||
|
type: 'running' | 'paused' | 'error';
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface SourceProps {
|
||||||
|
text: string;
|
||||||
|
language: string;
|
||||||
|
readOnly: boolean;
|
||||||
|
// 1-based
|
||||||
|
highlight?: SourceHighlight[];
|
||||||
|
revealLine?: number;
|
||||||
|
lineNumbers?: boolean;
|
||||||
|
focusOnChange?: boolean;
|
||||||
|
wrapLines?: boolean;
|
||||||
|
onChange?: (text: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeMirrorWrapper: React.FC<SourceProps> = ({
|
||||||
|
text,
|
||||||
|
language,
|
||||||
|
readOnly,
|
||||||
|
highlight = [],
|
||||||
|
revealLine,
|
||||||
|
lineNumbers,
|
||||||
|
focusOnChange,
|
||||||
|
wrapLines,
|
||||||
|
onChange,
|
||||||
|
}) => {
|
||||||
|
const codemirrorElement = React.createRef<HTMLDivElement>();
|
||||||
|
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
let mode;
|
||||||
|
if (language === 'javascript')
|
||||||
|
mode = 'javascript';
|
||||||
|
if (language === 'python')
|
||||||
|
mode = 'python';
|
||||||
|
if (language === 'java')
|
||||||
|
mode = 'text/x-java';
|
||||||
|
if (language === 'csharp')
|
||||||
|
mode = 'text/x-csharp';
|
||||||
|
|
||||||
|
if (codemirror && codemirror.getOption('mode') === mode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!codemirrorElement.current)
|
||||||
|
return;
|
||||||
|
if (codemirror)
|
||||||
|
codemirror.getWrapperElement().remove();
|
||||||
|
|
||||||
|
const cm = CodeMirror(codemirrorElement.current, {
|
||||||
|
value: '',
|
||||||
|
mode,
|
||||||
|
readOnly,
|
||||||
|
lineNumbers,
|
||||||
|
lineWrapping: wrapLines,
|
||||||
|
});
|
||||||
|
if (onChange)
|
||||||
|
cm.on('change', () => onChange(cm.getValue()));
|
||||||
|
setCodemirror(cm);
|
||||||
|
updateEditor(cm, text, highlight, revealLine, focusOnChange);
|
||||||
|
}, [codemirror, codemirrorElement, text, language, highlight, revealLine, focusOnChange, lineNumbers, wrapLines, readOnly, onChange]);
|
||||||
|
|
||||||
|
if (codemirror)
|
||||||
|
updateEditor(codemirror, text, highlight, revealLine, focusOnChange);
|
||||||
|
|
||||||
|
return <div className='cm-wrapper' ref={codemirrorElement}></div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateEditor(cm: CodeMirror.Editor, text: string, highlight: SourceHighlight[], revealLine?: number, focusOnChange?: boolean) {
|
||||||
|
if (cm.getValue() !== text) {
|
||||||
|
cm.setValue(text);
|
||||||
|
if (focusOnChange) {
|
||||||
|
cm.execCommand('selectAll');
|
||||||
|
cm.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < cm.lineCount(); ++i)
|
||||||
|
cm.removeLineClass(i, 'wrap');
|
||||||
|
for (const h of highlight)
|
||||||
|
cm.addLineClass(h.line - 1, 'wrap', `source-line-${h.type}`);
|
||||||
|
if (revealLine)
|
||||||
|
cm.scrollIntoView({ line: revealLine - 1, ch: 0 }, 50);
|
||||||
|
}
|
||||||
|
|
@ -46,118 +46,3 @@
|
||||||
outline: 1px solid #ff5656;
|
outline: 1px solid #ff5656;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-wrapper, .cm-wrapper > div {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-meta {
|
|
||||||
color: var(--vscode-editor-foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-number {
|
|
||||||
color: var(--vscode-debugTokenExpression-number);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-keyword {
|
|
||||||
color: var(--vscode-debugTokenExpression-name);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-operator {
|
|
||||||
color: var(--vscode-editor-foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-string {
|
|
||||||
color: var(--vscode-debugTokenExpression-string);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-string-2 {
|
|
||||||
color: var(--vscode-debugTokenExpression-string);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-error {
|
|
||||||
color: var(--vscode-errorForeground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-def, .CodeMirror span.cm-tag {
|
|
||||||
color: #0070c1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-comment, .CodeMirror span.cm-link {
|
|
||||||
color: #008000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-variable, .CodeMirror span.cm-variable-2, .CodeMirror span.cm-atom {
|
|
||||||
color: #0070c1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-property, .CodeMirror span.cm-qualifier, .CodeMirror span.cm-attribute {
|
|
||||||
color: #001080;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-variable-3,
|
|
||||||
.CodeMirror span.cm-type {
|
|
||||||
color: #267f99;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media(prefers-color-scheme: dark) {
|
|
||||||
|
|
||||||
.CodeMirror span.cm-def, .CodeMirror span.cm-tag {
|
|
||||||
color: var(--vscode-debugView-valueChangedHighlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-comment, .CodeMirror span.cm-link {
|
|
||||||
color: #6a9955;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-variable, .CodeMirror span.cm-variable-2, .CodeMirror span.cm-atom {
|
|
||||||
color: #4fc1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-property, .CodeMirror span.cm-qualifier, .CodeMirror span.cm-attribute {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-variable-3,
|
|
||||||
.CodeMirror span.cm-type {
|
|
||||||
color: #4ec9b0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror span.cm-bracket {
|
|
||||||
color: var(--vscode-editorBracketHighlight-foreground3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-cursor {
|
|
||||||
border-left: 1px solid #bebebe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror div.CodeMirror-selected {
|
|
||||||
background: var(--vscode-terminal-inactiveSelectionBackground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror .CodeMirror-gutters {
|
|
||||||
background: var(--vscode-editor-background);
|
|
||||||
border-right: 1px solid var(--vscode-editorGroup-border);
|
|
||||||
color: var(--vscode-editorLineNumber-foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror .CodeMirror-matchingbracket {
|
|
||||||
background-color: var(--vscode-editorBracketPairGuide-background1);
|
|
||||||
color: var(--vscode-editorBracketHighlight-foreground1) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .CodeMirror-line,
|
|
||||||
.CodeMirror-line-like {
|
|
||||||
color: var(--vscode-editor-foreground) !important;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.CodeMirror {
|
|
||||||
font-family: var(--vscode-editor-font-family) !important;
|
|
||||||
color: var(--vscode-editor-foreground) !important;
|
|
||||||
background-color: var(--vscode-editor-background) !important;
|
|
||||||
font-weight: var(--vscode-editor-font-weight) !important;
|
|
||||||
font-size: var(--vscode-editor-font-size) !important;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,9 @@
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './source.css';
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import CodeMirror from 'codemirror';
|
import './codeMirrorWrapper.css';
|
||||||
import 'codemirror/mode/javascript/javascript';
|
import { CodeMirrorWrapper } from './codeMirrorWrapper';
|
||||||
import 'codemirror/mode/python/python';
|
|
||||||
import 'codemirror/mode/clike/clike';
|
|
||||||
import 'codemirror/lib/codemirror.css';
|
|
||||||
|
|
||||||
export type SourceHighlight = {
|
export type SourceHighlight = {
|
||||||
line: number;
|
line: number;
|
||||||
|
|
@ -41,51 +37,5 @@ export const Source: React.FC<SourceProps> = ({
|
||||||
highlight = [],
|
highlight = [],
|
||||||
revealLine
|
revealLine
|
||||||
}) => {
|
}) => {
|
||||||
const codemirrorElement = React.createRef<HTMLDivElement>();
|
return <CodeMirrorWrapper text={text} language={language} readOnly={true} highlight={highlight} revealLine={revealLine} lineNumbers={true}></CodeMirrorWrapper>;
|
||||||
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
let mode;
|
|
||||||
if (language === 'javascript')
|
|
||||||
mode = 'javascript';
|
|
||||||
if (language === 'python')
|
|
||||||
mode = 'python';
|
|
||||||
if (language === 'java')
|
|
||||||
mode = 'text/x-java';
|
|
||||||
if (language === 'csharp')
|
|
||||||
mode = 'text/x-csharp';
|
|
||||||
|
|
||||||
if (codemirror && codemirror.getOption('mode') === mode)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!codemirrorElement.current)
|
|
||||||
return;
|
|
||||||
if (codemirror)
|
|
||||||
codemirror.getWrapperElement().remove();
|
|
||||||
|
|
||||||
const cm = CodeMirror(codemirrorElement.current, {
|
|
||||||
value: '',
|
|
||||||
mode,
|
|
||||||
readOnly: true,
|
|
||||||
lineNumbers: true,
|
|
||||||
});
|
|
||||||
setCodemirror(cm);
|
|
||||||
updateEditor(cm, text, highlight, revealLine);
|
|
||||||
}, [codemirror, codemirrorElement, text, language, highlight, revealLine]);
|
|
||||||
|
|
||||||
if (codemirror)
|
|
||||||
updateEditor(codemirror, text, highlight, revealLine);
|
|
||||||
|
|
||||||
return <div className='cm-wrapper' ref={codemirrorElement}></div>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateEditor(cm: CodeMirror.Editor, text: string, highlight: SourceHighlight[], revealLine: number | undefined) {
|
|
||||||
if (cm.getValue() !== text)
|
|
||||||
cm.setValue(text);
|
|
||||||
for (let i = 0; i < cm.lineCount(); ++i)
|
|
||||||
cm.removeLineClass(i, 'wrap');
|
|
||||||
for (const h of highlight)
|
|
||||||
cm.addLineClass(h.line - 1, 'wrap', `source-line-${h.type}`);
|
|
||||||
if (revealLine)
|
|
||||||
cm.scrollIntoView({ line: revealLine - 1, ch: 0 }, 50);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
box-shadow: var(--box-shadow);
|
box-shadow: var(--box-shadow);
|
||||||
background-color: var(--vscode-sideBar-background);
|
background-color: var(--vscode-sideBar-background);
|
||||||
color: var(--vscode-sideBarTitle-foreground);
|
color: var(--vscode-sideBarTitle-foreground);
|
||||||
height: 40px;
|
min-height: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
flex: none;
|
flex: none;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.toolbar-button {
|
.toolbar-button {
|
||||||
|
flex: none;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
color: var(--vscode-sideBarTitle-foreground);
|
color: var(--vscode-sideBarTitle-foreground);
|
||||||
|
|
|
||||||
|
|
@ -359,10 +359,12 @@ it.describe('pause', () => {
|
||||||
await page.pause();
|
await page.pause();
|
||||||
})();
|
})();
|
||||||
const recorderPage = await recorderPageGetter();
|
const recorderPage = await recorderPageGetter();
|
||||||
const [box1] = await Promise.all([
|
|
||||||
waitForTestLog<Box>(page, 'Highlight box for test: '),
|
const box1Promise = waitForTestLog<Box>(page, 'Highlight box for test: ');
|
||||||
recorderPage.fill('input[placeholder="Playwright Selector"]', 'text=Submit'),
|
await recorderPage.click('.toolbar .CodeMirror');
|
||||||
]);
|
await recorderPage.keyboard.type('getByText(\'Submit\')');
|
||||||
|
const box1 = await box1Promise;
|
||||||
|
|
||||||
const button = await page.$('text=Submit');
|
const button = await page.$('text=Submit');
|
||||||
const box2 = await button.boundingBox();
|
const box2 = await button.boundingBox();
|
||||||
expect(roundBox(box1)).toEqual(roundBox(box2));
|
expect(roundBox(box1)).toEqual(roundBox(box2));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue