something

This commit is contained in:
partouf
2025-07-15 21:27:55 +02:00
parent 8e08cfe6ce
commit f5ebcce6d2
6 changed files with 535 additions and 202 deletions

222
package-lock.json generated
View File

@@ -15,7 +15,17 @@
"@aws-sdk/client-sqs": "^3.828.0",
"@aws-sdk/client-ssm": "^3.828.0",
"@aws-sdk/credential-providers": "^3.828.0",
"@codemirror/autocomplete": "^6.18.6",
"@codemirror/commands": "^6.8.1",
"@codemirror/lang-cpp": "^6.0.3",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-java": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.4",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.2",
"@codemirror/language": "^6.11.2",
"@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.38.0",
"@flatten-js/interval-tree": "^1.1.3",
@@ -1542,6 +1552,28 @@
"node": ">=14.21.3"
}
},
"node_modules/@codemirror/autocomplete": {
"version": "6.18.6",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0"
}
},
"node_modules/@codemirror/commands": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.27.0",
"@lezer/common": "^1.1.0"
}
},
"node_modules/@codemirror/lang-cpp": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.3.tgz",
@@ -1551,6 +1583,62 @@
"@lezer/cpp": "^1.0.0"
}
},
"node_modules/@codemirror/lang-go": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz",
"integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/go": "^1.0.0"
}
},
"node_modules/@codemirror/lang-java": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.2.tgz",
"integrity": "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/java": "^1.0.0"
}
},
"node_modules/@codemirror/lang-javascript": {
"version": "6.2.4",
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/javascript": "^1.0.0"
}
},
"node_modules/@codemirror/lang-python": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz",
"integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==",
"dependencies": {
"@codemirror/autocomplete": "^6.3.2",
"@codemirror/language": "^6.8.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.1",
"@lezer/python": "^1.1.4"
}
},
"node_modules/@codemirror/lang-rust": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.2.tgz",
"integrity": "sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/rust": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.2.tgz",
@@ -1564,10 +1652,25 @@
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/language/node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
"node_modules/@codemirror/lint": {
"version": "6.8.5",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/search": {
"version": "6.5.11",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/state": {
"version": "6.5.2",
@@ -2321,6 +2424,11 @@
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="
},
"node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
},
"node_modules/@lezer/cpp": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.3.tgz",
@@ -2331,10 +2439,15 @@
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/cpp/node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
"node_modules/@lezer/go": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz",
"integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/highlight": {
"version": "1.2.1",
@@ -2344,10 +2457,25 @@
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/highlight/node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
"node_modules/@lezer/java": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz",
"integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/javascript": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
"integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.1.3",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/lr": {
"version": "1.4.2",
@@ -2357,10 +2485,25 @@
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/lr/node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
"node_modules/@lezer/python": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz",
"integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/rust": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz",
"integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.2",
@@ -6378,53 +6521,6 @@
"@codemirror/view": "^6.0.0"
}
},
"node_modules/codemirror/node_modules/@codemirror/autocomplete": {
"version": "6.18.6",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0"
}
},
"node_modules/codemirror/node_modules/@codemirror/commands": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.27.0",
"@lezer/common": "^1.1.0"
}
},
"node_modules/codemirror/node_modules/@codemirror/lint": {
"version": "6.8.5",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"crelt": "^1.0.5"
}
},
"node_modules/codemirror/node_modules/@codemirror/search": {
"version": "6.5.11",
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"crelt": "^1.0.5"
}
},
"node_modules/codemirror/node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="
},
"node_modules/color": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",

View File

@@ -24,7 +24,17 @@
"@aws-sdk/client-sqs": "^3.828.0",
"@aws-sdk/client-ssm": "^3.828.0",
"@aws-sdk/credential-providers": "^3.828.0",
"@codemirror/autocomplete": "^6.18.6",
"@codemirror/commands": "^6.8.1",
"@codemirror/lang-cpp": "^6.0.3",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-java": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.4",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.2",
"@codemirror/language": "^6.11.2",
"@codemirror/lint": "^6.8.5",
"@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.38.0",
"@flatten-js/interval-tree": "^1.1.3",

View File

@@ -0,0 +1,261 @@
// CodeMirror 6 implementation for mobile devices in Compiler Explorer
import {EditorView, basicSetup} from 'codemirror';
import {EditorState, Compartment} from '@codemirror/state';
import {cpp} from '@codemirror/lang-cpp';
import {javascript} from '@codemirror/lang-javascript';
import {python} from '@codemirror/lang-python';
import {rust} from '@codemirror/lang-rust';
import {go} from '@codemirror/lang-go';
import {java} from '@codemirror/lang-java';
import {Diagnostic, linter, lintGutter} from '@codemirror/lint';
import {ICompilerExplorerEditor, CompilerError, EditorOptions} from './editor-abstraction';
interface LanguageExtension {
name: string;
extension: () => any;
}
// Language mappings for CodeMirror 6
const LANGUAGE_EXTENSIONS: Record<string, LanguageExtension> = {
'cpp': {name: 'C++', extension: cpp},
'c': {name: 'C', extension: cpp}, // Use C++ for C (close enough)
'cxx': {name: 'C++', extension: cpp},
'cc': {name: 'C++', extension: cpp},
'javascript': {name: 'JavaScript', extension: javascript},
'js': {name: 'JavaScript', extension: javascript},
'typescript': {name: 'TypeScript', extension: javascript}, // Use JS for TS
'ts': {name: 'TypeScript', extension: javascript},
'python': {name: 'Python', extension: python},
'py': {name: 'Python', extension: python},
'rust': {name: 'Rust', extension: rust},
'rs': {name: 'Rust', extension: rust},
'go': {name: 'Go', extension: go},
'java': {name: 'Java', extension: java},
};
export class CodeMirrorMobileEditor implements ICompilerExplorerEditor {
private view: EditorView;
private container: HTMLElement;
private languageCompartment: Compartment;
private lintCompartment: Compartment;
private currentLanguage: string;
private changeCallbacks: (() => void)[] = [];
private disposed = false;
private currentErrors: CompilerError[] = [];
constructor(container: HTMLElement, options: EditorOptions = {}) {
this.container = container;
this.currentLanguage = options.language || 'cpp';
// Create compartments for dynamic reconfiguration
this.languageCompartment = new Compartment();
this.lintCompartment = new Compartment();
// Create initial state
const initialState = EditorState.create({
doc: '',
extensions: [
basicSetup,
this.languageCompartment.of(this.getLanguageExtension(this.currentLanguage)),
this.lintCompartment.of([]),
EditorView.updateListener.of(this.createUpdateListener()),
EditorView.theme({
'&': {
fontSize: options.fontSize ? `${options.fontSize}px` : '14px',
height: '100%',
},
'.cm-content': {
padding: '10px',
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", monospace',
minHeight: '200px',
},
'.cm-focused': {
outline: 'none',
},
'.cm-editor': {
height: '100%',
},
'.cm-scroller': {
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", monospace',
},
// Error styling
'.cm-diagnostic-error': {
borderLeft: '3px solid #ff5555',
backgroundColor: 'rgba(255, 85, 85, 0.1)',
},
'.cm-diagnostic-warning': {
borderLeft: '3px solid #ffaa00',
backgroundColor: 'rgba(255, 170, 0, 0.1)',
},
'.cm-diagnostic-info': {
borderLeft: '3px solid #5555ff',
backgroundColor: 'rgba(85, 85, 255, 0.1)',
},
}),
// Enable readonly if specified
...(options.readOnly ? [EditorState.readOnly.of(true)] : []),
],
});
// Create the editor view
this.view = new EditorView({
state: initialState,
parent: container,
});
console.log('CodeMirrorMobileEditor created with language:', this.currentLanguage);
}
private getLanguageExtension(languageId: string): any {
const langConfig = LANGUAGE_EXTENSIONS[languageId.toLowerCase()];
if (langConfig) {
return langConfig.extension();
}
// Default to C++ if language not found
return cpp();
}
private createUpdateListener() {
return (update: any) => {
if (update.docChanged) {
// Notify change callbacks
this.notifyChange();
}
};
}
private notifyChange(): void {
if (this.disposed) return;
this.changeCallbacks.forEach(callback => {
try {
callback();
} catch (error) {
console.error('Error in change callback:', error);
}
});
}
// ICompilerExplorerEditor implementation
getValue(): string {
if (this.disposed) throw new Error('Editor disposed');
return this.view.state.doc.toString();
}
setValue(value: string): void {
if (this.disposed) throw new Error('Editor disposed');
const transaction = this.view.state.update({
changes: {
from: 0,
to: this.view.state.doc.length,
insert: value,
},
});
this.view.dispatch(transaction);
}
setLanguage(language: string): void {
if (this.disposed) throw new Error('Editor disposed');
const normalizedLanguage = language.toLowerCase();
if (this.currentLanguage === normalizedLanguage) return;
this.currentLanguage = normalizedLanguage;
// Update language extension
const languageExtension = this.getLanguageExtension(normalizedLanguage);
this.view.dispatch({
effects: this.languageCompartment.reconfigure(languageExtension),
});
console.log('CodeMirror language changed to:', normalizedLanguage);
}
setErrors(errors: CompilerError[]): void {
if (this.disposed) throw new Error('Editor disposed');
this.currentErrors = [...errors];
// Convert CompilerError[] to CodeMirror Diagnostic[]
const diagnostics: Diagnostic[] = errors.map(error => {
// Convert 1-based line numbers to 0-based positions
const line = Math.max(0, error.line - 1);
const doc = this.view.state.doc;
const lineInfo = doc.line(Math.min(line + 1, doc.lines));
const from = lineInfo.from + Math.max(0, error.column - 1);
const to = Math.min(from + 1, lineInfo.to); // At least one character
return {
from,
to,
severity: error.severity,
message: error.message,
};
});
// Create linter that returns our diagnostics
const errorLinter = linter(() => diagnostics);
// Update lint compartment
this.view.dispatch({
effects: this.lintCompartment.reconfigure([
errorLinter,
lintGutter(),
]),
});
}
onChange(callback: () => void): void {
if (this.disposed) throw new Error('Editor disposed');
this.changeCallbacks.push(callback);
}
dispose(): void {
if (this.disposed) return;
this.disposed = true;
this.changeCallbacks = [];
this.currentErrors = [];
// Destroy CodeMirror view
this.view.destroy();
// Clear container
this.container.innerHTML = '';
console.log('CodeMirrorMobileEditor disposed');
}
// Additional methods for enhanced functionality
focus(): void {
if (!this.disposed) {
this.view.focus();
}
}
layout(): void {
// CodeMirror 6 handles layout automatically, but we can force a refresh
if (!this.disposed) {
this.view.requestMeasure();
}
}
getLanguage(): string {
return this.currentLanguage;
}
getErrors(): CompilerError[] {
return [...this.currentErrors];
}
isDisposed(): boolean {
return this.disposed;
}
// Get the underlying CodeMirror view for advanced usage
getCodeMirrorView(): EditorView | null {
return this.disposed ? null : this.view;
}
}

View File

@@ -1,18 +1,13 @@
// CodeMirror 6 test page entry point
import {EditorView} from '@codemirror/view';
import {EditorState} from '@codemirror/state';
import {syntaxHighlighting, HighlightStyle} from '@codemirror/language';
import {tags} from '@lezer/highlight';
import {EditorView, basicSetup} from 'codemirror';
import {cpp} from '@codemirror/lang-cpp';
// import {createEditor, createEditorSync} from './editor-abstraction';
import {CodeMirrorMobileEditor} from './codemirror-mobile-editor';
console.log('CodeMirror test script loaded, imports successful');
console.log('EditorView:', EditorView);
console.log('EditorState:', EditorState);
console.log('C++ language support:', cpp);
console.log('C++ language function result:', cpp());
console.log('Syntax highlighting:', syntaxHighlighting);
console.log('Highlight tags:', tags);
console.log('C++ language support:', cpp);
console.log('basicSetup:', basicSetup);
console.log('cpp:', cpp);
function initializeCodeMirrorTest() {
console.log('CodeMirror 6 test page loaded - DOM ready');
@@ -35,141 +30,89 @@ int main() {
const cmContainer = document.getElementById('codemirror-editor');
if (cmContainer) {
try {
console.log('Creating CodeMirror editor...');
const cppExtension = cpp();
console.log('C++ extension created:', cppExtension);
console.log('C++ extension type:', typeof cppExtension);
console.log('C++ extension constructor:', cppExtension.constructor?.name);
// Create a custom highlight style to avoid version conflicts
const customHighlightStyle = HighlightStyle.define([
{ tag: tags.comment, color: '#008000' },
{ tag: tags.keyword, color: '#0000FF' },
{ tag: tags.string, color: '#800080' },
{ tag: tags.number, color: '#FF0000' },
{ tag: tags.variableName, color: '#000000' },
{ tag: tags.typeName, color: '#008080' },
{ tag: tags.operator, color: '#000000' },
{ tag: tags.bracket, color: '#000000' }
]);
console.log('Custom highlight style created:', customHighlightStyle);
const highlightExtension = syntaxHighlighting(customHighlightStyle);
console.log('Highlight extension created:', highlightExtension);
const extensions = [
cppExtension, // Add C++ language support first
highlightExtension, // Add syntax highlighting
EditorView.lineWrapping,
EditorView.theme({
'&': { height: '250px', border: '1px solid #ddd' },
'.cm-content': { padding: '10px', fontFamily: 'monospace', fontSize: '14px' },
'.cm-focused': { outline: 'none' }
}),
EditorView.updateListener.of(update => {
if (update.docChanged) {
console.log('CodeMirror content changed');
const outputEl = document.getElementById('cm-output');
if (outputEl) {
outputEl.textContent =
'Content: ' + view.state.doc.toString().substring(0, 50) + '...';
}
}
})
];
console.log('Extensions array:', extensions);
console.log('Extensions length:', extensions.length);
extensions.forEach((ext, i) => {
console.log(`Extension ${i}:`, ext, typeof ext);
});
const state = EditorState.create({
doc: `// CodeMirror 6 Editor (real transaction-based)
#include <iostream>
// Exact official example
new EditorView({
parent: cmContainer,
doc: `#include <iostream>
int main() {
std::cout << "Hello from CodeMirror 6!" << std::endl;
std::cout << "Hello World!" << std::endl;
return 0;
}`,
extensions: extensions
extensions: [basicSetup, cpp()]
});
console.log('EditorState created:', state);
console.log('State language data:', state.languageDataAt('language', 0));
const view = new EditorView({
state: state,
parent: cmContainer
});
console.log('EditorView created:', view);
// Check if syntax highlighting is working
setTimeout(() => {
console.log('=== Checking syntax highlighting after render ===');
const cmContent = cmContainer.querySelector('.cm-content');
if (cmContent) {
console.log('CM content element found:', cmContent);
const highlightedElements = cmContent.querySelectorAll('[class*="cm-"]');
console.log('Highlighted elements found:', highlightedElements.length);
Array.from(highlightedElements).forEach((el, i) => {
if (i < 5) { // Log first 5 elements
console.log(`Highlighted element ${i}:`, el.className, el.textContent);
}
});
// Check for specific C++ tokens
const includeElements = cmContent.querySelectorAll('[class*="keyword"], [class*="include"]');
console.log('Include/keyword elements:', includeElements.length);
const commentElements = cmContent.querySelectorAll('[class*="comment"]');
console.log('Comment elements:', commentElements.length);
} else {
console.log('CM content element not found');
}
}, 100);
// Test the abstraction API
const setValueBtn = document.getElementById('test-setValue');
if (setValueBtn) {
setValueBtn.onclick = () => {
view.dispatch({
changes: {
from: 0,
to: view.state.doc.length,
insert: 'int main() { return 42; }'
}
});
};
}
const getValueBtn = document.getElementById('test-getValue');
if (getValueBtn) {
getValueBtn.onclick = () => {
const content = view.state.doc.toString();
const outputEl = document.getElementById('cm-output');
if (outputEl) {
outputEl.textContent = 'Content: ' + content;
}
};
}
console.log('CodeMirror 6 editor created successfully');
const statusEl = document.getElementById('cm-status');
if (statusEl) {
statusEl.textContent = 'CodeMirror 6 loaded successfully with C++ syntax highlighting!';
statusEl.style.color = 'green';
}
} catch (error) {
console.error('Failed to create CodeMirror editor:', error);
const statusEl = document.getElementById('cm-status');
if (statusEl) {
statusEl.textContent = 'CodeMirror 6 failed to load: ' + (error as Error).message;
statusEl.style.color = 'red';
}
}
}
// Test 3: CodeMirror Mobile Editor Class
const mobileContainer = document.getElementById('mobile-editor');
if (mobileContainer) {
try {
console.log('Creating CodeMirrorMobileEditor...');
const mobileEditor = new CodeMirrorMobileEditor(mobileContainer, {
language: 'cpp',
fontSize: 14,
});
mobileEditor.setValue(`// CodeMirror Mobile Editor Test
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (const auto& num : numbers) {
std::cout << "Number: " << num << std::endl;
}
return 0;
}`);
// Test language switching
setTimeout(() => {
console.log('Testing language switch to JavaScript...');
mobileEditor.setLanguage('javascript');
mobileEditor.setValue(`// JavaScript test
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log('Fibonacci(10):', fibonacci(10));`);
}, 2000);
// Test error display
setTimeout(() => {
console.log('Testing error display...');
mobileEditor.setErrors([
{
line: 3,
column: 10,
message: 'Example compilation error',
severity: 'error'
},
{
line: 8,
column: 5,
message: 'Example warning',
severity: 'warning'
}
]);
}, 4000);
// Test change callback
mobileEditor.onChange(() => {
console.log('Mobile editor content changed, new length:', mobileEditor.getValue().length);
});
console.log('CodeMirrorMobileEditor created successfully');
} catch (error) {
console.error('Failed to create CodeMirrorMobileEditor:', error);
}
}
}

View File

@@ -94,8 +94,25 @@ export class MockEditor implements ICompilerExplorerEditor {
}
// Factory function for creating editors
export function createEditor(container: HTMLElement, options: EditorOptions): ICompilerExplorerEditor {
// For now, just return mock editor for testing
// Later this will detect mobile and return appropriate implementation
export async function createEditor(container: HTMLElement, options: EditorOptions): Promise<ICompilerExplorerEditor> {
// Detect mobile/touch devices
const isMobile = window.compilerExplorerOptions?.mobileViewer ||
'ontouchstart' in window ||
navigator.maxTouchPoints > 0;
if (isMobile) {
// Dynamic import for CodeMirror to avoid loading on desktop
const module = await import('./codemirror-mobile-editor');
return new module.CodeMirrorMobileEditor(container, options);
} else {
// Return mock editor for desktop (later this will be Monaco wrapper)
return new MockEditor();
}
}
// Synchronous factory for immediate creation (uses mock for now)
export function createEditorSync(container: HTMLElement, options: EditorOptions): ICompilerExplorerEditor {
// For now, return mock editor for testing
// This will be replaced with proper sync creation once we integrate
return new MockEditor();
}

View File

@@ -20,6 +20,12 @@ block content
h3 CodeMirror 6 Editor (Transaction-based)
#codemirror-editor
.row.mt-4
.col-12
h3 CodeMirror Mobile Editor Class (with Language Support)
#mobile-editor
p.small This tests the full CodeMirrorMobileEditor class with language switching, error display, and change detection.
.row.mt-4
.col-12
h3 CodeMirror 6 Status