2021-01-28 18:33:20 +01:00
|
|
|
/*
|
|
|
|
|
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';
|
2022-11-01 23:04:30 +01:00
|
|
|
import CodeMirror from 'codemirror';
|
|
|
|
|
import 'codemirror/mode/javascript/javascript';
|
|
|
|
|
import 'codemirror/mode/python/python';
|
|
|
|
|
import 'codemirror/mode/clike/clike';
|
|
|
|
|
import 'codemirror/lib/codemirror.css';
|
2021-01-28 18:33:20 +01:00
|
|
|
|
2021-02-13 03:53:46 +01:00
|
|
|
export type SourceHighlight = {
|
|
|
|
|
line: number;
|
2021-02-14 07:13:51 +01:00
|
|
|
type: 'running' | 'paused' | 'error';
|
2021-02-13 03:53:46 +01:00
|
|
|
};
|
|
|
|
|
|
2021-01-28 18:33:20 +01:00
|
|
|
export interface SourceProps {
|
2021-02-13 03:53:46 +01:00
|
|
|
text: string;
|
|
|
|
|
language: string;
|
|
|
|
|
// 1-based
|
|
|
|
|
highlight?: SourceHighlight[];
|
|
|
|
|
revealLine?: number;
|
2021-01-28 18:33:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const Source: React.FC<SourceProps> = ({
|
2021-02-01 01:37:13 +01:00
|
|
|
text,
|
|
|
|
|
language,
|
2021-02-13 03:53:46 +01:00
|
|
|
highlight = [],
|
|
|
|
|
revealLine
|
2021-01-28 18:33:20 +01:00
|
|
|
}) => {
|
2022-11-01 23:04:30 +01:00
|
|
|
const codemirrorElement = React.createRef<HTMLDivElement>();
|
|
|
|
|
const [codemirror, setCodemirror] = React.useState<CodeMirror.Editor>();
|
2021-01-28 23:25:10 +01:00
|
|
|
|
2022-11-01 23:04:30 +01:00
|
|
|
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';
|
2021-01-28 23:25:10 +01:00
|
|
|
|
2022-11-01 23:04:30 +01:00
|
|
|
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>;
|
2021-01-28 18:33:20 +01:00
|
|
|
};
|
2022-11-01 23:04:30 +01:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|