44 < meta charset ="UTF-8 ">
55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
66 < title > Null-Safe Clang Playground</ title >
7+
8+ <!-- Monaco Editor from CDN (cached by browser) -->
9+ < link rel ="stylesheet " data-name ="vs/editor/editor.main " href ="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/editor/editor.main.min.css ">
10+
711 < style >
812 * {
913 margin : 0 ;
323327 border-radius : 2px ;
324328 }
325329
330+ # editor-wrapper {
331+ flex : 1 ;
332+ position : relative;
333+ overflow : hidden;
334+ }
335+
326336 # editor {
327337 position : absolute;
328338 top : 0 ;
329339 left : 0 ;
330340 right : 0 ;
331341 bottom : 0 ;
332- padding : 20px ;
333- font-family : 'Menlo' , 'Monaco' , 'Consolas' , 'Courier New' , monospace;
334- font-size : 14px ;
335- line-height : 1.5 ;
336- background : var (--bg-primary );
337- color : var (--text-primary );
338- border : none;
339- outline : none;
340- resize : none;
341- tab-size : 4 ;
342- overflow-y : auto;
343- caret-color : white;
344- z-index : 2 ;
345- }
346-
347- # editor-wrapper {
348- flex : 1 ;
349- position : relative;
350- overflow : hidden;
351342 }
352343
353344 # output {
@@ -555,7 +546,7 @@ <h1>Null-Safe Clang Playground</h1>
555546 </ div >
556547 </ div >
557548 < div id ="editor-wrapper ">
558- < textarea id ="editor " spellcheck =" false " placeholder =" Write your C code here... " > </ textarea >
549+ < div id ="editor "> </ div >
559550 </ div >
560551 </ div >
561552
@@ -581,8 +572,15 @@ <h1>Null-Safe Clang Playground</h1>
581572
582573 < div class ="toast " id ="toast "> </ div >
583574
575+ <!-- Load Monaco Editor from CDN -->
576+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.min.js "> </ script >
584577 < script >
585- const editor = document . getElementById ( 'editor' ) ;
578+ // Configure Monaco loader
579+ require . config ( { paths : { vs : 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs' } } ) ;
580+ </ script >
581+
582+ < script >
583+ const editorElement = document . getElementById ( 'editor' ) ;
586584 const outputNullsafe = document . getElementById ( 'output-nullsafe' ) ;
587585 const outputMainline = document . getElementById ( 'output-mainline' ) ;
588586 const compileBtn = document . getElementById ( 'compileBtn' ) ;
@@ -594,6 +592,8 @@ <h1>Null-Safe Clang Playground</h1>
594592 const divider = document . getElementById ( 'divider' ) ;
595593 const outputDivider = document . getElementById ( 'outputDivider' ) ;
596594
595+ let editor = null ; // Monaco editor instance
596+
597597 const examples = {
598598 'null-check' : `void process(int* data) {
599599 if (data) {
@@ -631,13 +631,55 @@ <h1>Null-Safe Clang Playground</h1>
631631 } ;
632632
633633 const defaultCode = examples [ 'null-check' ] ;
634- editor . value = defaultCode ;
634+
635+ // Monaco editor will be initialized async
636+ function initMonaco ( ) {
637+ return new Promise ( ( resolve ) => {
638+ require ( [ 'vs/editor/editor.main' ] , function ( ) {
639+ editor = monaco . editor . create ( editorElement , {
640+ value : defaultCode ,
641+ language : 'c' ,
642+ theme : 'vs-dark' ,
643+ automaticLayout : true ,
644+ minimap : { enabled : false } ,
645+ fontSize : 14 ,
646+ lineNumbers : 'on' ,
647+ scrollBeyondLastLine : false ,
648+ wordWrap : 'off' ,
649+ tabSize : 4
650+ } ) ;
651+
652+ // Add Ctrl+Enter shortcut
653+ editor . addAction ( {
654+ id : 'compile-code' ,
655+ label : 'Compile Code' ,
656+ keybindings : [ monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter ] ,
657+ run : function ( ) {
658+ compile ( ) ;
659+ }
660+ } ) ;
661+
662+ resolve ( ) ;
663+ } ) ;
664+ } ) ;
665+ }
666+
667+ // Helper to get/set editor content
668+ function getEditorValue ( ) {
669+ return editor ? editor . getValue ( ) : '' ;
670+ }
671+
672+ function setEditorValue ( value ) {
673+ if ( editor ) {
674+ editor . setValue ( value ) ;
675+ }
676+ }
635677
636678 let clangVersion = '' ;
637679 let isCompiling = false ;
638680 let isDragging = false ;
639- let scriptUrl = null ; // URL for worker to load clang.js
640- let wasmBinary = null ; // Pre-loaded WASM binary to share with workers
681+ let scriptUrl = null ;
682+ let wasmBinary = null ;
641683
642684 // Toast notification
643685 function showToast ( message , duration = 2000 ) {
@@ -686,16 +728,15 @@ <h1>Null-Safe Clang Playground</h1>
686728 examplesSelect . addEventListener ( 'change' , ( e ) => {
687729 const example = e . target . value ;
688730 if ( example && examples [ example ] ) {
689- editor . value = examples [ example ] ;
731+ setEditorValue ( examples [ example ] ) ;
690732 showToast ( 'Example loaded!' ) ;
691- // Don't reset - keep the selection showing
692733 }
693734 } ) ;
694735
695736 // Share button - encode code in URL
696737 shareBtn . addEventListener ( 'click' , async ( ) => {
697738 try {
698- const code = editor . value ;
739+ const code = getEditorValue ( ) ;
699740 const encoded = btoa ( unescape ( encodeURIComponent ( code ) ) ) ;
700741 const url = new URL ( window . location . href . split ( '?' ) [ 0 ] ) ;
701742 url . searchParams . set ( 'code' , encoded ) ;
@@ -715,7 +756,7 @@ <h1>Null-Safe Clang Playground</h1>
715756 if ( encodedCode ) {
716757 try {
717758 const code = decodeURIComponent ( escape ( atob ( encodedCode ) ) ) ;
718- editor . value = code ;
759+ setEditorValue ( code ) ;
719760 showToast ( 'Code loaded from URL!' ) ;
720761 } catch ( err ) {
721762 console . error ( 'Failed to decode URL code:' , err ) ;
@@ -792,7 +833,7 @@ <h1>Null-Safe Clang Playground</h1>
792833 const startTime = performance . now ( ) ;
793834
794835 try {
795- const code = editor . value ;
836+ const code = getEditorValue ( ) ;
796837
797838 // Compile both versions in parallel
798839 const [ nullsafeResult , mainlineResult ] = await Promise . all ( [
@@ -911,30 +952,11 @@ <h1>Null-Safe Clang Playground</h1>
911952 compileBtn . addEventListener ( 'click' , compile ) ;
912953
913954 // Auto-compile on load
914- window . addEventListener ( 'load' , ( ) => {
915- loadCodeFromURL ( ) ; // Load code from URL if present
955+ window . addEventListener ( 'load' , async ( ) => {
956+ await initMonaco ( ) ; // Initialize Monaco editor first
957+ loadCodeFromURL ( ) ; // Load code from URL if present
916958 initCompiler ( ) ;
917959 } ) ;
918-
919- // Keyboard shortcut: Cmd/Ctrl + Enter to compile
920- editor . addEventListener ( 'keydown' , ( e ) => {
921- if ( ( e . metaKey || e . ctrlKey ) && e . key === 'Enter' ) {
922- e . preventDefault ( ) ;
923- compile ( ) ;
924- }
925- } ) ;
926-
927- // Tab key handling
928- editor . addEventListener ( 'keydown' , ( e ) => {
929- if ( e . key === 'Tab' ) {
930- e . preventDefault ( ) ;
931- const start = editor . selectionStart ;
932- const end = editor . selectionEnd ;
933- const value = editor . value ;
934- editor . value = value . substring ( 0 , start ) + ' ' + value . substring ( end ) ;
935- editor . selectionStart = editor . selectionEnd = start + 4 ;
936- }
937- } ) ;
938960 </ script >
939961</ body >
940962</ html >
0 commit comments