@@ -278,6 +278,9 @@ const judgePromise = loadJudge(problem.page).catch(() => null);
278278const candidateCaseStorageKey = `codetrial.candidateCases.${ problem . page } ` ;
279279/// Filled by `applyLanguages`, which `init` calls before anything reads it.
280280let languages = [ ] ;
281+ // A delayed judge may make the requested C tab available after the first
282+ // paint. Do not switch to it after the candidate has chosen a tab or edited.
283+ let languageChoiceCommitted = false ;
281284/// What the lobby asked for, until `/api/token` says what it got. The range
282285/// here mirrors the server's own and is the fallback for a URL that arrives
283286/// without passing through the lobby; the answer below is what the interview
@@ -295,6 +298,7 @@ const interviewLoop = codingLoop(params.get("loop"));
295298/// the answer would leave the editor bound and the starter code published in
296299/// an interview that has neither.
297300const whiteboard = modeIsWhiteboard ( params . get ( "mode" ) ) ;
301+ const requestedLanguage = whiteboard ? null : params . get ( "language" ) ;
298302/// The same answer as the wire spelling, which the token request and the
299303/// checklist both need. Derived from the boolean rather than from the URL a
300304/// second time, so an unrecognized value cannot reach the server as itself.
@@ -616,7 +620,11 @@ async function init() {
616620 applyEditorTheme ( readStored ( EDITOR_THEME_KEY ) ) ;
617621 renderProblem ( ) ;
618622 applyLanguages ( null ) ;
619- setLanguage ( "python" ) ;
623+ setLanguage (
624+ requestedLanguage && languages . includes ( requestedLanguage )
625+ ? requestedLanguage
626+ : "python" ,
627+ ) ;
620628 bindEvents ( ) ;
621629 if ( whiteboard ) initWhiteboard ( ) ;
622630 placeJimStageBelowToolbar (
@@ -651,6 +659,13 @@ async function init() {
651659 // microtask.
652660 void judgePromise . then ( ( spec ) => {
653661 applyLanguages ( spec ) ;
662+ if (
663+ ! languageChoiceCommitted &&
664+ requestedLanguage &&
665+ state . language !== requestedLanguage &&
666+ languages . includes ( requestedLanguage )
667+ )
668+ setLanguage ( requestedLanguage ) ;
654669 } ) ;
655670 // No enumeration here. Before the preflight grant the browser reports only a
656671 // blank placeholder, so the list is discarded and repainted a few lines down;
@@ -850,9 +865,10 @@ function bindEvents() {
850865 nodes . resultsChevron . textContent = nodes . resultsBody . hidden ? "^" : "v" ;
851866 } ) ;
852867 for ( const button of document . querySelectorAll ( "[data-language]" ) ) {
853- button . addEventListener ( "click" , ( ) =>
854- setLanguage ( button . dataset . language ) ,
855- ) ;
868+ button . addEventListener ( "click" , ( ) => {
869+ languageChoiceCommitted = true ;
870+ setLanguage ( button . dataset . language ) ;
871+ } ) ;
856872 }
857873 for ( const [ button , step ] of [
858874 [ nodes . editorFontSmaller , - 1 ] ,
@@ -988,6 +1004,7 @@ function bindEvents() {
9881004 }
9891005 } ) ;
9901006 nodes . editor . addEventListener ( "input" , ( ) => {
1007+ languageChoiceCommitted = true ;
9911008 // Before the buffer below is taken, because this sends the tab as it
9921009 // arrived. Typing inside the switch's own debounce window cancels it
9931010 // otherwise, and the single packet that survives carries the switch and the
0 commit comments