@@ -156,7 +156,6 @@ static R_INIT: once_cell::sync::OnceCell<()> = once_cell::sync::OnceCell::new();
156156static mut R_MAIN : Option < RMain > = None ;
157157
158158pub struct RMain {
159- initializing : bool ,
160159 kernel_init_tx : Bus < KernelInfo > ,
161160
162161 /// Whether we are running in Console, Notebook, or Background mode.
@@ -406,17 +405,15 @@ impl RMain {
406405
407406 // Set up the global error handler (after support function initialization)
408407 errors:: initialize ( ) ;
409- }
410408
411- // Now that R has started (emitting any startup messages), and now that we have set
412- // up all hooks and handlers, officially finish the R initialization process to
413- // unblock the kernel-info request and also allow the LSP to start.
414- RMain :: with_mut ( |main| {
415- log:: info!(
416- "R has started and ark handlers have been registered, completing initialization."
417- ) ;
418- main. complete_initialization ( ) ;
419- } ) ;
409+ // Now that R has started (emitting any startup messages), and now that we have set
410+ // up all hooks and handlers, officially finish the R initialization process to
411+ // unblock the kernel-info request and also allow the LSP to start.
412+ RMain :: with_mut ( |main| {
413+ log:: info!( "R has started and ark handlers have been registered, completing initialization." ) ;
414+ main. complete_initialization ( ) ;
415+ } ) ;
416+ }
420417
421418 // Now that R has started and libr and ark have fully initialized, run site and user
422419 // level R profiles, in that order
@@ -431,6 +428,34 @@ impl RMain {
431428 crate :: sys:: interface:: run_r ( ) ;
432429 }
433430
431+ /// Completes the kernel's initialization.
432+ /// Unlike `RMain::start()`, this has access to `R_MAIN`'s state, such as
433+ /// the kernel-info banner.
434+ /// SAFETY: Can only be called from the R thread, and only once.
435+ pub unsafe fn complete_initialization ( & mut self ) {
436+ let version = unsafe {
437+ let version = Rf_findVarInFrame ( R_BaseNamespace , r_symbol ! ( "R.version.string" ) ) ;
438+ RObject :: new ( version) . to :: < String > ( ) . unwrap ( )
439+ } ;
440+
441+ // Initial input and continuation prompts
442+ let input_prompt: String = harp:: get_option ( "prompt" ) . try_into ( ) . unwrap ( ) ;
443+ let continuation_prompt: String = harp:: get_option ( "continue" ) . try_into ( ) . unwrap ( ) ;
444+
445+ let kernel_info = KernelInfo {
446+ version : version. clone ( ) ,
447+ banner : self . banner_output . clone ( ) ,
448+ input_prompt : Some ( input_prompt) ,
449+ continuation_prompt : Some ( continuation_prompt) ,
450+ } ;
451+
452+ log:: info!( "Sending kernel info: {version}" ) ;
453+ self . kernel_init_tx . broadcast ( kernel_info) ;
454+
455+ // Thread-safe initialisation flag for R
456+ R_INIT . set ( ( ) ) . expect ( "`R_INIT` can only be set once" ) ;
457+ }
458+
434459 pub fn new (
435460 kernel : Arc < Mutex < Kernel > > ,
436461 tasks_interrupt_rx : Receiver < RTask > ,
@@ -445,7 +470,6 @@ impl RMain {
445470 session_mode : SessionMode ,
446471 ) -> Self {
447472 Self {
448- initializing : true ,
449473 r_request_rx,
450474 comm_manager_tx,
451475 stdin_request_tx,
@@ -474,14 +498,23 @@ impl RMain {
474498
475499 /// Wait for complete R initialization
476500 ///
477- /// Wait for R being ready to take input (i.e. `ReadConsole` was called).
478- /// Resolves as the same time as the `Bus<KernelInfo>` init channel does.
501+ /// Wait for R being ready to evaluate R code. Resolves as the same time as
502+ /// the `Bus<KernelInfo>` init channel does.
479503 ///
480504 /// Thread-safe.
481505 pub fn wait_r_initialized ( ) {
482506 R_INIT . wait ( ) ;
483507 }
484508
509+ /// Has R completed initialization
510+ ///
511+ /// I.e. is it ready to evaluate R code.
512+ ///
513+ /// Thread-safe.
514+ pub fn is_r_initialized ( ) -> bool {
515+ R_INIT . get ( ) . is_some ( )
516+ }
517+
485518 /// Has the `RMain` singleton completed initialization.
486519 ///
487520 /// This can return true when R might still not have finished starting up.
@@ -545,38 +578,6 @@ impl RMain {
545578 thread. id ( ) == unsafe { R_MAIN_THREAD_ID . unwrap ( ) }
546579 }
547580
548- /// Completes the kernel's initialization
549- pub fn complete_initialization ( & mut self ) {
550- if self . initializing {
551- let version = unsafe {
552- let version = Rf_findVarInFrame ( R_BaseNamespace , r_symbol ! ( "R.version.string" ) ) ;
553- RObject :: new ( version) . to :: < String > ( ) . unwrap ( )
554- } ;
555-
556- // Initial input and continuation prompts
557- let input_prompt: String = harp:: get_option ( "prompt" ) . try_into ( ) . unwrap ( ) ;
558- let continuation_prompt: String = harp:: get_option ( "continue" ) . try_into ( ) . unwrap ( ) ;
559-
560- let kernel_info = KernelInfo {
561- version : version. clone ( ) ,
562- banner : self . banner_output . clone ( ) ,
563- input_prompt : Some ( input_prompt) ,
564- continuation_prompt : Some ( continuation_prompt) ,
565- } ;
566-
567- log:: info!( "Sending kernel info: {version}" ) ;
568- self . kernel_init_tx . broadcast ( kernel_info) ;
569-
570- // Internal initialisation flag, should only be used on the R thread
571- self . initializing = false ;
572-
573- // Used as thread-safe initialisation flag
574- R_INIT . set ( ( ) ) . unwrap ( ) ;
575- } else {
576- log:: warn!( "Initialization already complete!" ) ;
577- }
578- }
579-
580581 /// Provides read-only access to `iopub_tx`
581582 pub fn get_iopub_tx ( & self ) -> & Sender < IOPubMessage > {
582583 & self . iopub_tx
@@ -1323,7 +1324,7 @@ This is a Positron limitation we plan to fix. In the meantime, you can:
13231324 Stream :: Stderr
13241325 } ;
13251326
1326- if self . initializing {
1327+ if ! RMain :: is_r_initialized ( ) {
13271328 // During init, consider all output to be part of the startup banner
13281329 self . banner_output . push_str ( & content) ;
13291330 return ;
0 commit comments