From f58e61b901d1362aa1a48c2cf508300b5f6586eb Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 11 Dec 2025 21:21:31 +0800 Subject: [PATCH 01/17] Add format_options as part of BackendState --- crates/amalthea/src/comm/data_explorer_comm.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/amalthea/src/comm/data_explorer_comm.rs b/crates/amalthea/src/comm/data_explorer_comm.rs index 56dd29927..d9d628184 100644 --- a/crates/amalthea/src/comm/data_explorer_comm.rs +++ b/crates/amalthea/src/comm/data_explorer_comm.rs @@ -92,9 +92,12 @@ pub struct BackendState { /// requests. This parameter may change. pub connected: Option, - /// Optional experimental parameter to provide an explanation when - /// connected=false. This parameter may change. - pub error_message: Option + /// Optional experimental parameter to provide an explanation when + /// connected=false. This parameter may change. + pub error_message: Option, + + /// Optional formatting options for frontend display + pub format_options: Option, } /// Schema for a column in a table From 9c14a03e3e517e9b3534a2a9a6fcc428a7b707ab Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 11 Dec 2025 21:51:27 +0800 Subject: [PATCH 02/17] fetch scipen option --- crates/ark/src/data_explorer/r_data_explorer.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index d0f1db1b5..3e4c3ac78 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -72,6 +72,7 @@ use crossbeam::channel::Sender; use crossbeam::select; use harp::exec::RFunction; use harp::exec::RFunctionExt; +use harp::get_option; use harp::object::RObject; use harp::r_symbol; use harp::table_kind; @@ -1159,6 +1160,7 @@ impl RDataExplorer { }]), }, }, + format_options: Some(Self::current_format_options()), }; Ok(DataExplorerBackendReply::GetStateReply(state)) } @@ -1299,6 +1301,18 @@ impl RDataExplorer { // Call the conversion function with resolved sort keys convert_to_code::convert_to_code(params, object_name, &resolved_sort_keys) } + + fn current_format_options() -> FormatOptions { + let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); + let max_integral_digits = (7 + scipen).clamp(1, 20); + FormatOptions { + large_num_digits: 2, + small_num_digits: 4, + max_integral_digits, + max_value_length: 1000, + thousands_sep: None, + } + } } /// Open an R object in the data viewer. From c10d632d21a00783892ede5988fe3f0c5122089a Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 09:46:39 +0800 Subject: [PATCH 03/17] Also use digits --- crates/ark/src/data_explorer/r_data_explorer.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 3e4c3ac78..35ac8d1ce 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1304,10 +1304,16 @@ impl RDataExplorer { fn current_format_options() -> FormatOptions { let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); - let max_integral_digits = (7 + scipen).clamp(1, 20); + let digits: i64 = get_option("digits").try_into().unwrap_or(7); + + // Calculate thresholds for scientific notation + let max_integral_digits = (digits + scipen).clamp(1, 20); + let large_num_digits = (digits / 2).clamp(1, 10); + let small_num_digits = (digits / 2).clamp(1, 10); + FormatOptions { - large_num_digits: 2, - small_num_digits: 4, + large_num_digits, + small_num_digits, max_integral_digits, max_value_length: 1000, thousands_sep: None, From a8cae77c1b2b535968df111742378e2f562693a7 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 10:04:07 +0800 Subject: [PATCH 04/17] Remove clamping for maximum values --- crates/ark/src/data_explorer/r_data_explorer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 35ac8d1ce..1b33d4fa1 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1307,9 +1307,9 @@ impl RDataExplorer { let digits: i64 = get_option("digits").try_into().unwrap_or(7); // Calculate thresholds for scientific notation - let max_integral_digits = (digits + scipen).clamp(1, 20); - let large_num_digits = (digits / 2).clamp(1, 10); - let small_num_digits = (digits / 2).clamp(1, 10); + let max_integral_digits = (digits + scipen).max(1); + let large_num_digits = (digits / 2).max(1); + let small_num_digits = (digits / 2).max(1); FormatOptions { large_num_digits, From 03924fb35a05b702ddb8e63ecc31ce7b0ef17d80 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 10:27:40 +0800 Subject: [PATCH 05/17] Add comments for scipen and digits defaults --- crates/ark/src/data_explorer/r_data_explorer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 1b33d4fa1..1586450d9 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1303,8 +1303,8 @@ impl RDataExplorer { } fn current_format_options() -> FormatOptions { - let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); - let digits: i64 = get_option("digits").try_into().unwrap_or(7); + let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); // R default + let digits: i64 = get_option("digits").try_into().unwrap_or(7); // R default // Calculate thresholds for scientific notation let max_integral_digits = (digits + scipen).max(1); From 7e3086ffdcafa6fb34b0d3156b223a6ee4a87e49 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 10:30:01 +0800 Subject: [PATCH 06/17] 2 d.p. by default --- crates/ark/src/data_explorer/r_data_explorer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 1586450d9..4c28ed8d3 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1308,7 +1308,7 @@ impl RDataExplorer { // Calculate thresholds for scientific notation let max_integral_digits = (digits + scipen).max(1); - let large_num_digits = (digits / 2).max(1); + let large_num_digits = (digits - 5).max(0); // default to 2 d.p. let small_num_digits = (digits / 2).max(1); FormatOptions { From 74afed2ec60288499dc0e3ef5edf56132f27c14d Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 10:37:54 +0800 Subject: [PATCH 07/17] max integral digits and small num digits only depend on scipen, not digits --- crates/ark/src/data_explorer/r_data_explorer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 4c28ed8d3..d09a5ce7d 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1307,9 +1307,9 @@ impl RDataExplorer { let digits: i64 = get_option("digits").try_into().unwrap_or(7); // R default // Calculate thresholds for scientific notation - let max_integral_digits = (digits + scipen).max(1); + let max_integral_digits = (scipen + 5).max(1); // only depends on scipen let large_num_digits = (digits - 5).max(0); // default to 2 d.p. - let small_num_digits = (digits / 2).max(1); + let small_num_digits = (scipen + 6).max(1); // only depends on scipen FormatOptions { large_num_digits, From 35f1c6a836eda6d07b58fbffba4ecb4a3b8b4488 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Tue, 16 Dec 2025 10:38:16 +0800 Subject: [PATCH 08/17] Add function comment --- crates/ark/src/data_explorer/r_data_explorer.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index d09a5ce7d..5dab28c53 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1302,6 +1302,12 @@ impl RDataExplorer { convert_to_code::convert_to_code(params, object_name, &resolved_sort_keys) } + /// Returns the current format options as a `FormatOptions` object. + /// + /// These options are derived from the R options "scipen" and "digits". The + /// thresholds for scientific notation are calculated based on these + /// options. The `max_value_length` is set to 1000, and `thousands_sep` + /// is set to `None`. fn current_format_options() -> FormatOptions { let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); // R default let digits: i64 = get_option("digits").try_into().unwrap_or(7); // R default From 95697792ff3353369826697d260242eadfa80708 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:33:31 +0800 Subject: [PATCH 09/17] Add test for BackendState format_options reflecting R option changes (#1) * Initial plan * Add test for format_options state change after R option modification Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> * Improve error handling in test_format_options_state_change Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> * Remove unnecessary move keyword in closure Co-authored-by: kv9898 <105025148+kv9898@users.noreply.github.com> --- crates/ark/tests/data_explorer.rs | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/crates/ark/tests/data_explorer.rs b/crates/ark/tests/data_explorer.rs index 2a49ed2d9..d8b76b0d3 100644 --- a/crates/ark/tests/data_explorer.rs +++ b/crates/ark/tests/data_explorer.rs @@ -3108,3 +3108,63 @@ fn test_single_row_data_frame_column_profiles() { }); } } + +#[test] +fn test_format_options_state_change() { + let _lock = r_test_lock(); + + // Save the current R options so we can restore them later + let (original_scipen, original_digits) = r_task(|| { + let scipen_obj = harp::parse_eval_global("getOption('scipen')").expect("Failed to get scipen option"); + let digits_obj = harp::parse_eval_global("getOption('digits')").expect("Failed to get digits option"); + let scipen: i64 = scipen_obj.try_into().unwrap_or(0); + let digits: i64 = digits_obj.try_into().unwrap_or(7); + (scipen, digits) + }); + + // Set known R options for testing + r_task(|| { + harp::parse_eval_global("options(scipen = 0, digits = 7)").unwrap(); + }); + + // Open a data explorer with mtcars + let setup = TestSetup::new("mtcars"); + let socket = setup.socket(); + + // Get the initial state and verify format_options + TestAssertions::assert_state(&socket, |state| { + let format_options = state.format_options.as_ref().expect("format_options should be present"); + + // With scipen=0, digits=7: + // max_integral_digits = (0 + 5).max(1) = 5 + // large_num_digits = (7 - 5).max(0) = 2 + // small_num_digits = (0 + 6).max(1) = 6 + assert_eq!(format_options.max_integral_digits, 5); + assert_eq!(format_options.large_num_digits, 2); + assert_eq!(format_options.small_num_digits, 6); + }); + + // Change R options to different values + r_task(|| { + harp::parse_eval_global("options(scipen = 10, digits = 10)").unwrap(); + }); + + // Get the state again and verify format_options changed + TestAssertions::assert_state(&socket, |state| { + let format_options = state.format_options.as_ref().expect("format_options should be present"); + + // With scipen=10, digits=10: + // max_integral_digits = (10 + 5).max(1) = 15 + // large_num_digits = (10 - 5).max(0) = 5 + // small_num_digits = (10 + 6).max(1) = 16 + assert_eq!(format_options.max_integral_digits, 15); + assert_eq!(format_options.large_num_digits, 5); + assert_eq!(format_options.small_num_digits, 16); + }); + + // Restore original R options + r_task(|| { + let restore_cmd = format!("options(scipen = {}, digits = {})", original_scipen, original_digits); + harp::parse_eval_global(&restore_cmd).expect("Failed to restore original R options"); + }); +} From 910bb6d1fca29c00303016237d2c150813e25da3 Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Wed, 17 Dec 2025 16:42:06 +0800 Subject: [PATCH 10/17] use as.integer() this time (#3) --- crates/ark/src/data_explorer/r_data_explorer.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index 5dab28c53..a50a5ca91 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1309,7 +1309,14 @@ impl RDataExplorer { /// options. The `max_value_length` is set to 1000, and `thousands_sep` /// is set to `None`. fn current_format_options() -> FormatOptions { - let scipen: i64 = get_option("scipen").try_into().unwrap_or(0); // R default + // In R 4.2, Rf_GetOption1 (used by get_option) doesn't work correctly for scipen + // due to special handling added in later versions. We need to use the R interpreter's + // getOption() function instead. See: https://github.com/wch/r-source/commit/7f20c19 + // Note: 'digits' works fine with Rf_GetOption1, so we don't need to change it. + let scipen: i64 = harp::parse_eval_global("as.integer(getOption('scipen', 0))") + .ok() + .and_then(|obj| obj.try_into().ok()) + .unwrap_or(0); // R default let digits: i64 = get_option("digits").try_into().unwrap_or(7); // R default // Calculate thresholds for scientific notation From aa29e723d2e013f1a560109e0e349e80d2e56c77 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 09:51:16 -0700 Subject: [PATCH 11/17] Copilot does not need to sign the CLA --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index fc45a6916..1f4d28eae 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, Copilot # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From bc4f44befb46ba331c03f7d92601f051d24c2adc Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 09:52:14 -0700 Subject: [PATCH 12/17] Maybe Copilot's name is `copilot` --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 1f4d28eae..1a5748804 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, Copilot + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From b0508b6d6d4beb2ccd19e3b99ee95a55a9734545 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 09:56:32 -0700 Subject: [PATCH 13/17] Actually, it's name is `copilot[bot]` --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 1a5748804..44dd39612 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot[bot] # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From bdfe49ee9a4427766f111054f32b357ef18d6ade Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 10:01:19 -0700 Subject: [PATCH 14/17] Revert "Actually, it's name is `copilot[bot]`" This reverts commit b0508b6d6d4beb2ccd19e3b99ee95a55a9734545. --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 44dd39612..1a5748804 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot[bot] + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From 0ba2914220936a8f8b3c948653dc526808333d19 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 10:01:27 -0700 Subject: [PATCH 15/17] Revert "Maybe Copilot's name is `copilot`" This reverts commit bc4f44befb46ba331c03f7d92601f051d24c2adc. --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 1a5748804..1f4d28eae 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, copilot + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, Copilot # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From 98b3fd2bcde5bd53e8e4964a3c09e86de0e38d55 Mon Sep 17 00:00:00 2001 From: Julia Silge Date: Wed, 17 Dec 2025 10:01:33 -0700 Subject: [PATCH 16/17] Revert "Copilot does not need to sign the CLA" This reverts commit aa29e723d2e013f1a560109e0e349e80d2e56c77. --- .github/workflows/cla.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 1f4d28eae..fc45a6916 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -49,7 +49,7 @@ jobs: before we accept your contribution. You can sign the CLA by posting a comment on this PR saying: - allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm, Copilot + allowlist: DavisVaughan, dependabot[bot], dfalbel, isabelizimm, jonvanausdeln, lionel-, nstrayer, petetronic, positron-bot[bot], seeM, sharon-wang, softwarenerd, timtmok, wesm # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) From afa46f6d9aff50cdc74d6340cf8257855ae7b95e Mon Sep 17 00:00:00 2001 From: Dianyi Yang Date: Thu, 18 Dec 2025 03:25:41 +0800 Subject: [PATCH 17/17] Streamline code Co-authored-by: Daniel Falbel --- crates/ark/src/data_explorer/r_data_explorer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/ark/src/data_explorer/r_data_explorer.rs b/crates/ark/src/data_explorer/r_data_explorer.rs index a50a5ca91..b3da7b809 100644 --- a/crates/ark/src/data_explorer/r_data_explorer.rs +++ b/crates/ark/src/data_explorer/r_data_explorer.rs @@ -1314,8 +1314,7 @@ impl RDataExplorer { // getOption() function instead. See: https://github.com/wch/r-source/commit/7f20c19 // Note: 'digits' works fine with Rf_GetOption1, so we don't need to change it. let scipen: i64 = harp::parse_eval_global("as.integer(getOption('scipen', 0))") - .ok() - .and_then(|obj| obj.try_into().ok()) + .and_then(|obj| obj.try_into()) .unwrap_or(0); // R default let digits: i64 = get_option("digits").try_into().unwrap_or(7); // R default